Skip to content

Don't generalize capturing lambdas in argument position#9708

Merged
rtfeldman merged 2 commits into
mainfrom
fix-dispatch-capturing-arg-lambda-9699
Jun 19, 2026
Merged

Don't generalize capturing lambdas in argument position#9708
rtfeldman merged 2 commits into
mainfrom
fix-dispatch-capturing-arg-lambda-9699

Conversation

@rtfeldman

Copy link
Copy Markdown
Contributor

Closes #9699.

A static-dispatch method chain on a value whose type is not yet concrete — such as letters.to_utf8().contains(...) where letters is a string literal flowing through find_first — could report a spurious MISSING METHOD: ... on an unresolved type variable error. The cause was that a capturing lambda passed directly as a call argument was being generalized at its own rank, before the caller pinned its parameter types. That froze the lambda body's static-dispatch chain as a generalized scheme; when the predicate was then instantiated, only the instantiated copy's dispatches got resolved against the concrete element type, leaving the original CIR node's type variable an unresolved flex dispatcher that the end-of-check ambiguity sweep then flagged.

A bare (non-capturing) lambda in argument position already skips generalization via the !is_call_arg guard in shouldGeneralize; the closure (capture-wrapper) case slipped through because checkExpr clears the checking_call_arg flag before delegating to the inner lambda. The fix re-asserts that flag in the e_closure case, so a capturing argument lambda is treated the same as a bare one and is not generalized — letting its dispatch chain resolve in place once find_first pins the element type, with the side benefit of creating fewer type variables.

A static-dispatch method chain on a not-yet-concrete value, such as
letters.to_utf8().contains(...) where letters is a string literal flowing
through find_first, could report a spurious MISSING METHOD error. The cause
was that a capturing lambda passed directly as a call argument was generalized
at its own rank, before the caller pinned its parameter types, freezing the
lambda body's dispatch chain as a generalized scheme. When the predicate was
then instantiated, only the instantiated copy's dispatches resolved, leaving
the original CIR node's type variable an unresolved flex dispatcher that the
end-of-check ambiguity sweep flagged.

A bare (non-capturing) lambda in argument position already skips generalization
via the !is_call_arg guard in shouldGeneralize; the closure case slipped through
because checkExpr clears checking_call_arg before delegating to the inner lambda.
Re-assert the flag in the e_closure case so a capturing argument lambda is
treated the same as a bare one and its dispatch chain resolves in place once the
element type is pinned.
report.zig already emits "the annotation says it should be"; this snapshot
still had the older "annotation say" wording, so a full snapshot regen
(run-check-snapshots in CI) leaves it dirty. Regenerate it to match.
@rtfeldman rtfeldman marked this pull request as ready for review June 19, 2026 01:47
@rtfeldman rtfeldman merged commit c4e6e5f into main Jun 19, 2026
39 checks passed
@rtfeldman rtfeldman deleted the fix-dispatch-capturing-arg-lambda-9699 branch June 19, 2026 01:47
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.

Unable to dispatch method on an unresolved type variable

1 participant