@@ -117,7 +117,7 @@ def create_generic_type(constant, name)
117117 # the generic class `Foo[Bar]` is still a `Foo`. That is:
118118 # `Foo[Bar].new.is_a?(Foo)` should be true, which isn't the case
119119 # if we just clone the class. But subclassing works just fine.
120- create_safe_subclass ( constant )
120+ create_safe_subclass ( constant , name )
121121 else
122122 # This can only be a module and it is fine to just clone modules
123123 # since they can't have instances and will not have `is_a?` relationships.
@@ -151,31 +151,32 @@ def create_generic_type(constant, name)
151151 generic_type
152152 end
153153
154- sig { params ( constant : T ::Class [ T . anything ] ) . returns ( T ::Class [ T . anything ] ) }
155- def create_safe_subclass ( constant )
154+ sig { params ( constant : T ::Class [ T . anything ] , name : String ) . returns ( T ::Class [ T . anything ] ) }
155+ def create_safe_subclass ( constant , name )
156156 # Lookup the "inherited" class method
157157 inherited_method = constant . method ( :inherited )
158158 # and the module that defines it
159159 owner = inherited_method . owner
160160
161- # If no one has overriden the inherited method yet, just subclass
162- return Class . new ( constant ) if Class == owner
163-
164- begin
165- # Otherwise, some inherited method could be preventing us
166- # from creating subclasses, so let's override it and rescue
167- owner . send ( :define_method , :inherited ) do |s |
168- inherited_method . call ( s )
169- rescue
170- # Ignoring errors
171- end
172-
173- # return a subclass
174- Class . new ( constant )
175- ensure
176- # Reinstate the original inherited method back.
161+ # Otherwise, some inherited method could be preventing us
162+ # from creating subclasses, so let's override it and rescue
163+ owner . send ( :define_method , :inherited ) do |new_subclass |
164+ # Reinstate the original inherited method back ASAP
177165 owner . send ( :define_method , :inherited , inherited_method )
166+
167+ # Register this new subclass ASAP, to prevent re-entry into the `create_safe_subclass` code-path.
168+ # This can happen if the sig of the original `.inherited` method references the generic type itself.
169+ @generic_instances [ name ] ||= new_subclass
170+
171+ # Call the original `.inherited` method, but rescue any errors that might be raised,
172+ # which would have otherwise prevented our subclass from being created.
173+ inherited_method . call ( new_subclass )
174+ rescue
175+ # Ignoring errors
178176 end
177+
178+ # return a subclass
179+ Class . new ( constant )
179180 end
180181
181182 sig { params ( constant : Module ) . returns ( T ::Array [ TypeVariableModule ] ) }
0 commit comments