@@ -255,29 +255,21 @@ def resolve_overloads(changes, genv, node, param_map, a_args, ret, &blk)
255255 # If any positional argument has no type information, we cannot
256256 # determine which overload to select. Return silently (untyped)
257257 # rather than attempting to match. This prevents oscillation in
258- # cyclic cases like @x = Foo.transform(@x), and avoids false
259- # "failed to resolve overloads" diagnostics for untyped arguments.
260- # We still set up dependency edges so the box re-runs when the
261- # empty arguments later receive types.
258+ # cyclic cases and avoids false "failed to resolve overloads"
259+ # diagnostics for untyped arguments.
262260 #
263- # For splat arguments, the positional vertex itself holds Array
264- # types (non-empty), but the array *element* vertex may be empty.
265- # The same oscillation occurs when match_arguments? extracts
266- # elements via get_rest_args and the universal typecheck on the
267- # flattened element list fails due to conflicting array sources.
268- # We detect this by checking element vertices of splatted arrays.
269- has_uninformative_args = a_args . positionals . any? { |vtx | vtx . types . empty? }
270- unless has_uninformative_args
271- a_args . positionals . each_with_index do |vtx , i |
272- next unless a_args . splat_flags [ i ]
273- vtx . each_type do |ty |
274- base = ty . base_type ( genv )
275- if base . is_a? ( Type ::Instance ) && base . mod == genv . mod_ary && base . args [ 0 ]
276- has_uninformative_args = true if base . args [ 0 ] . types . empty?
277- end
278- end
279- break if has_uninformative_args
280- end
261+ # Top-level empty vertices are always uninformative. For type
262+ # parameter vertices (e.g., Array[T], Hash[K,V], tuples), we
263+ # only recurse when overloads differ in their positional parameter
264+ # types -- otherwise empty type params (like those of `{}`) cannot
265+ # cause oscillation and should not trigger bail-out.
266+ overloads_differ_in_positionals = !@method_types . each_cons ( 2 ) . all? { |mt1 , mt2 |
267+ positionals_match? ( mt1 , mt2 )
268+ }
269+ has_uninformative_args = if overloads_differ_in_positionals
270+ a_args . positionals . any? { |vtx | vertex_uninformative? ( genv , vtx ) }
271+ else
272+ a_args . positionals . any? { |vtx | vtx . types . empty? }
281273 end
282274 if has_uninformative_args
283275 a_args . positionals . each do |vtx |
@@ -298,6 +290,61 @@ def resolve_overloads(changes, genv, node, param_map, a_args, ret, &blk)
298290 end
299291 end
300292
293+ def vertex_uninformative? ( genv , vtx , depth = 0 )
294+ return true if vtx . types . empty?
295+ return false if depth > 3
296+ vtx . each_type do |ty |
297+ base = ty . base_type ( genv )
298+ next unless base . is_a? ( Type ::Instance ) && !base . args . empty?
299+ base . args . each do |arg_vtx |
300+ return true if arg_vtx && vertex_uninformative? ( genv , arg_vtx , depth + 1 )
301+ end
302+ end
303+ false
304+ end
305+
306+ # Check if two method types have structurally identical positional
307+ # parameter types (req, opt, rest).
308+ def positionals_match? ( mt1 , mt2 )
309+ return false unless mt1 . req_positionals . size == mt2 . req_positionals . size
310+ return false unless mt1 . opt_positionals . size == mt2 . opt_positionals . size
311+ return false unless mt1 . rest_positionals . nil? == mt2 . rest_positionals . nil?
312+ mt1 . req_positionals . zip ( mt2 . req_positionals ) . all? { |a , b | sig_types_match? ( a , b ) } &&
313+ mt1 . opt_positionals . zip ( mt2 . opt_positionals ) . all? { |a , b | sig_types_match? ( a , b ) } &&
314+ ( mt1 . rest_positionals . nil? || sig_types_match? ( mt1 . rest_positionals , mt2 . rest_positionals ) )
315+ end
316+
317+ # Structural equality check for two SigTyNode objects.
318+ def sig_types_match? ( a , b )
319+ return false unless a . class == b . class
320+ case a
321+ when AST ::SigTyInstanceNode , AST ::SigTyInterfaceNode
322+ a . cpath == b . cpath &&
323+ a . args . size == b . args . size &&
324+ a . args . zip ( b . args ) . all? { |x , y | sig_types_match? ( x , y ) }
325+ when AST ::SigTySingletonNode
326+ a . cpath == b . cpath
327+ when AST ::SigTyTupleNode , AST ::SigTyUnionNode , AST ::SigTyIntersectionNode
328+ a . types . size == b . types . size &&
329+ a . types . zip ( b . types ) . all? { |x , y | sig_types_match? ( x , y ) }
330+ when AST ::SigTyRecordNode
331+ a . fields . size == b . fields . size &&
332+ a . fields . all? { |k , v | b . fields [ k ] && sig_types_match? ( v , b . fields [ k ] ) }
333+ when AST ::SigTyOptionalNode , AST ::SigTyProcNode
334+ sig_types_match? ( a . type , b . type )
335+ when AST ::SigTyVarNode
336+ a . var == b . var
337+ when AST ::SigTyLiteralNode
338+ a . lit == b . lit
339+ when AST ::SigTyAliasNode
340+ a . cpath == b . cpath && a . name == b . name &&
341+ a . args . size == b . args . size &&
342+ a . args . zip ( b . args ) . all? { |x , y | sig_types_match? ( x , y ) }
343+ else
344+ true # Leaf types (bool, nil, self, void, untyped, etc.)
345+ end
346+ end
347+
301348 def show
302349 @method_types . map do |method_type |
303350 args = [ ]
0 commit comments