Skip to content

fix(analyser): pick most-specific overload in scope 🎯#158

Merged
timfennis merged 1 commit into
masterfrom
bugfix/specificity-aware-overload-resolution
May 24, 2026
Merged

fix(analyser): pick most-specific overload in scope 🎯#158
timfennis merged 1 commit into
masterfrom
bugfix/specificity-aware-overload-resolution

Conversation

@timfennis
Copy link
Copy Markdown
Owner

Context

Reported via chat: locate(seq, predicate) was broken — calling it with a function argument errored with locate did not find anything, even when the predicate matched.

The stdlib registers two locate overloads with arity 2 (ndc_stdlib/src/sequence.rs):

  • locate(SeqValue, &mut VmCallable) — predicate form
  • locate(SeqValue, Value) — element-equality form, registered second

Scope::find_function used rposition to pick an overload, so the later-registered element-equality form won whenever both matched. When a function value was passed, the analyser bound the call to the wrong overload, which then compared each element to the function value (never equal) and finally errored.

Changes

  • Scope::find_function now collects every overload in the scope whose signature accepts the call, then picks the one not strictly dominated by another match's parameter signature in the subtype partial order. Ties resolve to the latest-registered overload, preserving shadow semantics.
  • Variadic overloads (parameters: None) are treated as the least specific shape, so any concrete overload that also matches dominates them.
  • Added is_strictly_more_specific helper that compares two parameter lists pointwise via StaticType::is_subtype.

Scope chain semantics are unchanged: any match in the current scope still stops the walk, so fn foo(Any) in an inner scope completely shadows the parent, while fn foo(Int) only shadows Int calls.

Tests

  • 5 unit tests in scope.rs covering same-scope specificity (locate-style and numeric), fn(Any) shadowing, fn(Int) falling through for other arg types, and concrete vs variadic.
  • Functional regression at tests/functional/programs/603_stdlib_seq/012_locate.ndc exercising both locate overloads.

🤖 Generated with Claude Code

Same-scope overload resolution used `rposition`, so a later-registered
less-specific overload would shadow an earlier more-specific one. The
`locate` stdlib function exposed this: passing a predicate dispatched to
the element-equality overload (registered second), which compared the
function value against each element and produced "locate did not find
anything".

`Scope::find_function` now collects every signature-compatible candidate
and returns the one not strictly dominated on its parameter signature in
the subtype partial order, tie-breaking by latest registration. Variadic
overloads are treated as least specific.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@timfennis timfennis force-pushed the bugfix/specificity-aware-overload-resolution branch from 24aa558 to c12ee66 Compare May 24, 2026 14:40
@timfennis timfennis merged commit 4bfa9f1 into master May 24, 2026
1 check passed
@timfennis timfennis deleted the bugfix/specificity-aware-overload-resolution branch May 24, 2026 16:01
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