@@ -117,7 +117,7 @@ def create_generic_type(constant, name)
117
117
# the generic class `Foo[Bar]` is still a `Foo`. That is:
118
118
# `Foo[Bar].new.is_a?(Foo)` should be true, which isn't the case
119
119
# if we just clone the class. But subclassing works just fine.
120
- create_safe_subclass ( constant )
120
+ create_safe_subclass ( constant , name )
121
121
else
122
122
# This can only be a module and it is fine to just clone modules
123
123
# since they can't have instances and will not have `is_a?` relationships.
@@ -151,31 +151,35 @@ def create_generic_type(constant, name)
151
151
generic_type
152
152
end
153
153
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 )
156
156
# Lookup the "inherited" class method
157
157
inherited_method = constant . method ( :inherited )
158
158
# and the module that defines it
159
159
owner = inherited_method . owner
160
160
161
- # If no one has overriden the inherited method yet, just subclass
161
+ # If no one has overridden the inherited method yet, just subclass
162
162
return Class . new ( constant ) if Class == owner
163
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.
164
+ # Otherwise, some inherited method could be preventing us
165
+ # from creating subclasses, so let's override it and rescue
166
+ owner . send ( :define_method , :inherited ) do |new_subclass |
167
+ # Reinstate the original inherited method back ASAP
177
168
owner . send ( :define_method , :inherited , inherited_method )
169
+
170
+ # Register this new subclass ASAP, to prevent re-entry into the `create_safe_subclass` code-path.
171
+ # This can happen if the sig of the original `.inherited` method references the generic type itself.
172
+ @generic_instances [ name ] ||= new_subclass
173
+
174
+ # Call the original `.inherited` method, but rescue any errors that might be raised,
175
+ # which would have otherwise prevented our subclass from being created.
176
+ inherited_method . call ( new_subclass )
177
+ rescue
178
+ # Ignoring errors
178
179
end
180
+
181
+ # return a subclass
182
+ Class . new ( constant )
179
183
end
180
184
181
185
sig { params ( constant : Module ) . returns ( T ::Array [ TypeVariableModule ] ) }
0 commit comments