Skip to content

Skip overload resolution when positional arguments have no type information#393

Merged
mame merged 1 commit intoruby:masterfrom
mame:fix-overload-oscillation
Feb 25, 2026
Merged

Skip overload resolution when positional arguments have no type information#393
mame merged 1 commit intoruby:masterfrom
mame:fix-overload-oscillation

Conversation

@mame
Copy link
Member

@mame mame commented Feb 25, 2026

When a multi-overload method is called with an empty (untyped) positional argument, we cannot determine which overload to select. Previously, empty vertices matched all overloads via the found_any mechanism in typecheck, which caused infinite oscillation in cyclic patterns like:

@x = Foo.transform(@x)  # transform has disjoint overloads

The cycle was: empty -> all match -> types flow in -> mismatch -> types removed -> empty -> repeat forever.

Fix: in resolve_overloads, if any positional argument vertex is empty, skip overload resolution entirely and return untyped. Dependency edges are still added so the box re-runs when arguments later receive types.

This is stateless (no flags on boxes or vertices), naturally convergent, and semantically correct: we cannot dispatch on what we do not know.

Trade-off: passing untyped to an overloaded method now returns untyped instead of the union of all return types. This affects 4 existing tests. Single-signature methods (force=true) are unaffected.

…mation

When a multi-overload method is called with an empty (untyped) positional
argument, we cannot determine which overload to select. Previously, empty
vertices matched all overloads via the found_any mechanism in typecheck,
which caused infinite oscillation in cyclic patterns like:

  @x = Foo.transform(@x)  # transform has disjoint overloads

The cycle was: empty -> all match -> types flow in -> mismatch -> types
removed -> empty -> repeat forever.

Fix: in resolve_overloads, if any positional argument vertex is empty,
skip overload resolution entirely and return untyped. Dependency edges
are still added so the box re-runs when arguments later receive types.

This is stateless (no flags on boxes or vertices), naturally convergent,
and semantically correct: we cannot dispatch on what we do not know.

Trade-off: passing untyped to an overloaded method now returns untyped
instead of the union of all return types. This affects 4 existing tests.
Single-signature methods (force=true) are unaffected.
@mame mame enabled auto-merge (rebase) February 25, 2026 08:30
@mame mame merged commit ae9dccc into ruby:master Feb 25, 2026
7 checks passed
@mame mame deleted the fix-overload-oscillation branch February 25, 2026 08:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant