Skip to content

Commit

Permalink
Fixed #1294: Inconsistent variance in generics
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite committed Aug 27, 2015
1 parent 70caaca commit 09989c5
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 2 deletions.
18 changes: 18 additions & 0 deletions spec/compiler/codegen/is_a_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -602,4 +602,22 @@ describe "Codegen: is_a?" do
Foo(Int32).is_a?(Foo.class)
)).to_b.should be_true
end

it "says false for GenericChild(Base).is_a?(GenericBase(Child)) (#1294)" do
run(%(
class Base
end
class Child < Base
end
class GenericBase(T)
end
class GenericChild(T) < GenericBase(T)
end
GenericChild(Base).new.is_a?(GenericBase(Child))
)).to_b.should be_false
end
end
22 changes: 22 additions & 0 deletions spec/compiler/type_inference/restrictions_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,26 @@ describe "Restrictions" do
(types["Foo"] as GenericClassType).instantiate([float64] of TypeVar),
) }
end

it "should not let GenericChild(Base) pass as a GenericBase(Child) (#1294)" do
assert_error %(
class Base
end
class Child < Base
end
class GenericBase(T)
end
class GenericChild(T) < GenericBase(T)
end
def foo(x : GenericBase(Child))
end
foo GenericChild(Base).new
),
"no overload matches"
end
end
5 changes: 3 additions & 2 deletions src/compiler/crystal/semantic/restrictions.cr
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,8 @@ module Crystal

mapping.each do |name, node|
typevar_type = TypeLookup.lookup(extending_class, node)
unless other.type_vars[name].type.is_restriction_of?(typevar_type, owner)
other_type = other.type_vars[name].type.devirtualize
unless typevar_type.implements?(other_type)
return nil
end
end
Expand All @@ -480,7 +481,7 @@ module Crystal
if m = @mapping[class_type_var]?
t = TypeLookup.lookup(extending_class, m)
restricted = t.restrict other_type_var, context
return nil unless restricted
return nil unless restricted && t == restricted

if other_type_var.is_a?(Path) && other_type_var.names.length == 1
context.set_free_var(other_type_var.names.first, restricted)
Expand Down

0 comments on commit 09989c5

Please sign in to comment.