diff --git a/spec/compiler/codegen/const_spec.cr b/spec/compiler/codegen/const_spec.cr index a674256fa354f6ce833faaf6f634389c452565b5..3ab20f1440f2fcaa12b5f1d00558106c317ecaff 100644 --- a/spec/compiler/codegen/const_spec.cr +++ b/spec/compiler/codegen/const_spec.cr @@ -91,7 +91,23 @@ describe "Codegen: const" do end it "uses correct types lookup" do - run("module A; class B; def foo; 1; end; end; C = B.new; end; def foo; A::C.foo; end; foo").to_i.should eq(1) + run(" + module A + class B + def foo + 1 + end + end + + C = B.new; + end + + def foo + A::C.foo + end + + foo + ").to_i.should eq(1) end it "codegens variable assignment in const" do diff --git a/spec/compiler/type_inference/module_spec.cr b/spec/compiler/type_inference/module_spec.cr index a62e669204b9f807d91da0a0a15ca578d6f3c7a5..9760626eea1f2d4643ab18fd60d7273cbd45612f 100755 --- a/spec/compiler/type_inference/module_spec.cr +++ b/spec/compiler/type_inference/module_spec.cr @@ -361,4 +361,26 @@ describe "Type inference: module" do end ", "cyclic include detected" end + + it "finds types close to included module" do + assert_type(" + module Foo + class T + end + + def foo + T + end + end + + class Bar + class T + end + + include Foo + end + + Bar.new.foo + ") { types["Foo"].types["T"].metaclass } + end end diff --git a/src/compiler/crystal/type_inference.cr b/src/compiler/crystal/type_inference.cr index d41b626981f34500a9e8498b8a8b7f20fec878cb..3b354b6fc644a74302d56eedcf24e207e9677f1c 100644 --- a/src/compiler/crystal/type_inference.cr +++ b/src/compiler/crystal/type_inference.cr @@ -21,6 +21,7 @@ module Crystal getter! untyped_def getter block getter vars + property type_lookup property in_fun_literal def initialize(@mod, @vars = {} of String => Var, @scope = nil, @parent = nil, @call = nil, @owner = nil, @untyped_def = nil, @typed_def = nil, @arg_types = nil, @free_vars = nil, @yield_vars = nil, @type_filter_stack = [nil] of Hash(String, TypeFilter)?) @@ -268,7 +269,7 @@ module Crystal target.bind_to value - current_type.types[target.names.first] = Const.new(@mod, current_type, target.names.first, value, @types.clone, @scope) + current_type.types[target.names.first] = Const.new(@mod, current_type, target.names.first, value, @types.dup, @scope) node.type = @mod.nil end @@ -383,6 +384,7 @@ module Crystal pushing_type_filters do block_visitor = TypeVisitor.new(mod, block_vars, (node.scope || @scope), @parent, @call, @owner, @untyped_def, @typed_def, @arg_types, @free_vars, @yield_vars, @type_filter_stack) block_visitor.block = node + block_visitor.type_lookup = type_lookup node.body.accept block_visitor end @@ -408,6 +410,7 @@ module Crystal block_visitor = TypeVisitor.new(mod, fun_vars, @scope, @parent, @call, @owner, node.def, node.def, @arg_types, @free_vars, @yield_vars, @type_filter_stack) block_visitor.in_fun_literal = true + block_visitor.type_lookup = type_lookup node.def.body.accept block_visitor false @@ -695,10 +698,10 @@ module Crystal case type when Const unless type.value.type? - old_types, old_scope, old_vars = @types, @scope, @vars - @types, @scope, @vars = type.scope_types, type.scope, ({} of String => Var) + old_types, old_scope, old_vars, old_type_lookup = @types, @scope, @vars, @type_lookup + @types, @scope, @vars, @type_lookup = type.scope_types, type.scope, ({} of String => Var), nil type.value.accept self - @types, @scope, @vars = old_types, old_scope, old_vars + @types, @scope, @vars, @type_lookup = old_types, old_scope, old_vars, old_type_lookup end node.target_const = type node.bind_to type.value diff --git a/src/compiler/crystal/type_inference/call.cr b/src/compiler/crystal/type_inference/call.cr index 80b82a463daa2438301aeafd023f6ff72e407f7d..83e51deb386deabdf2af7f45a3e2ea19e7346106 100644 --- a/src/compiler/crystal/type_inference/call.cr +++ b/src/compiler/crystal/type_inference/call.cr @@ -147,13 +147,12 @@ module Crystal match_owner = match.owner typed_def = match_owner.lookup_def_instance(match.def.object_id, lookup_arg_types, block_type) if use_cache unless typed_def - prepared_typed_def = prepare_typed_def_with_args(match.def, match_owner, lookup_self_type, match.arg_types, fun_literal) - typed_def = prepared_typed_def.typed_def - typed_def_args = prepared_typed_def.args + typed_def, typed_def_args = prepare_typed_def_with_args(match.def, match_owner, lookup_self_type, match.arg_types, fun_literal) match_owner.add_def_instance(match.def.object_id, lookup_arg_types, block_type, typed_def) if use_cache if typed_def.body bubbling_exception do visitor = TypeVisitor.new(mod, typed_def_args, lookup_self_type, parent_visitor, self, owner, match.def, typed_def, match.arg_types, match.free_vars, yield_vars) + visitor.type_lookup = match.type_lookup typed_def.body.accept visitor end end @@ -756,7 +755,7 @@ module Crystal args[var.name] = var end - PreparedTypedDef.new(typed_def, args) + {typed_def, args} end end end diff --git a/src/compiler/crystal/type_inference/type_lookup.cr b/src/compiler/crystal/type_inference/type_lookup.cr index 8497de76551a310900ef0fd7b4a329c50457afa3..73a5bf3e15cea273bba6f297fde751ad281e7c15 100644 --- a/src/compiler/crystal/type_inference/type_lookup.cr +++ b/src/compiler/crystal/type_inference/type_lookup.cr @@ -87,5 +87,14 @@ module Crystal @type = @root false end + + def visit(node : TypeOf) + visitor = TypeVisitor.new(@root.program, {"self" => Var.new("self", @root.instance_type)}) + node.expressions.each do |exp| + exp.accept visitor + end + @type = @root.program.type_merge(node.expressions.map &.type) + false + end end end diff --git a/src/compiler/crystal/type_inference/type_visitor_helper.cr b/src/compiler/crystal/type_inference/type_visitor_helper.cr index 82e3719a7be6a082f4ccea45afb988778d12e6ff..d9bd1626a20d45f174d90079fb5d272265515126 100644 --- a/src/compiler/crystal/type_inference/type_visitor_helper.cr +++ b/src/compiler/crystal/type_inference/type_visitor_helper.cr @@ -411,7 +411,7 @@ module Crystal target_type = type.not_nil!.lookup_type(node.names[1 .. -1]) end else - base_lookup = node.global ? mod : (@scope || @types.last) + base_lookup = node.global ? mod : (@type_lookup || @scope || @types.last) target_type = base_lookup.lookup_type node unless target_type