Skip to content

Commit

Permalink
Showing 5 changed files with 25 additions and 4 deletions.
15 changes: 15 additions & 0 deletions spec/compiler/semantic/generic_class_spec.cr
Original file line number Diff line number Diff line change
@@ -966,4 +966,19 @@ describe "Semantic: generic class" do
foo(Gen(String).new.as(Gen(String)))
)) { int32 }
end

it "subclasses twice with same generic class (#3423)" do
assert_type(%(
class Foo(T)
end
class Bar(T) < Foo(T)
end
class Bar(T) < Foo(T)
end
Bar(Int32).new
)) { generic_class "Bar", int32 }
end
end
2 changes: 1 addition & 1 deletion src/compiler/crystal/program.cr
Original file line number Diff line number Diff line change
@@ -163,7 +163,7 @@ module Crystal

types["StaticArray"] = static_array = @static_array = StaticArrayType.new self, self, "StaticArray", value, ["T", "N"]
static_array.struct = true
static_array.declare_instance_var("@buffer", TypeParameter.new(self, static_array, "T"))
static_array.declare_instance_var("@buffer", static_array.type_parameter("T"))
static_array.allowed_in_generics = false

types["String"] = string = @string = NonGenericClassType.new self, self, "String", reference
2 changes: 1 addition & 1 deletion src/compiler/crystal/semantic/top_level_visitor.cr
Original file line number Diff line number Diff line change
@@ -116,7 +116,7 @@ class Crystal::TopLevelVisitor < Crystal::SemanticVisitor
if type_vars = node.type_vars
free_vars = {} of String => TypeVar
type_vars.each do |type_var|
free_vars[type_var] = TypeParameter.new(program, type.as(GenericType), type_var)
free_vars[type_var] = type.as(GenericType).type_parameter(type_var)
end
else
free_vars = nil
4 changes: 2 additions & 2 deletions src/compiler/crystal/semantic/type_lookup.cr
Original file line number Diff line number Diff line change
@@ -68,7 +68,7 @@ class Crystal::Type
if root.is_a?(GenericType)
free_vars ||= {} of String => TypeVar
root.type_vars.each do |type_var|
free_vars[type_var] ||= TypeParameter.new(program, root, type_var)
free_vars[type_var] ||= root.type_parameter(type_var)
end
@free_vars = free_vars
end
@@ -324,7 +324,7 @@ class Crystal::Type
end

if (self_type = @self_type).is_a?(GenericType)
params = self_type.type_vars.map { |type_var| TypeParameter.new(self_type.program, self_type, type_var).as(TypeVar) }
params = self_type.type_vars.map { |type_var| self_type.type_parameter(type_var).as(TypeVar) }
self_type.instantiate(params)
else
@self_type.virtual_type
6 changes: 6 additions & 0 deletions src/compiler/crystal/types.cr
Original file line number Diff line number Diff line change
@@ -1153,6 +1153,12 @@ module Crystal
# by the type variables.
getter(generic_types) { {} of Array(TypeVar) => Type }

# Returns a TypeParameter relative to this type
def type_parameter(name) : TypeParameter
type_parameters = @type_parameters ||= {} of String => TypeParameter
type_parameters[name] ||= TypeParameter.new(program, self, name)
end

def instantiate(type_vars)
if (instance = generic_types[type_vars]?)
return instance

0 comments on commit 7025618

Please sign in to comment.