Skip to content

Resolve multi-candidate methods on impls defined outside the type's module - #4778

Open
kasimte wants to merge 1 commit into
model-checking:mainfrom
kasimte:fix-impl-path-resolution
Open

Resolve multi-candidate methods on impls defined outside the type's module#4778
kasimte wants to merge 1 commit into
model-checking:mainfrom
kasimte:fix-impl-path-resolution

Conversation

@kasimte

@kasimte kasimte commented Sep 2, 2026

Copy link
Copy Markdown

Resolves #4777.

last_two_items_of_path_match compares the user's turbofish against def_path_str's rendering of each candidate. Impls living outside their type's home module render as <impl Type<Args>>, which no user-spellable path can equal — so multi-candidate methods in that position (e.g. the three Box<dyn Any(+Send)(+Sync), A>::downcast_unchecked impls in alloc's boxed/convert.rs) fail to resolve under every spelling, while single-candidate methods skip refinement and work.

This is the out-of-module half of #3773 (whose fix and multiple_inherent_impls.rs test cover the same-module rendering). It adds a fallback that unwraps the <impl SELF_TYPE> form, extracts SELF_TYPE's generic arguments, strips the disambiguation parentheses def_path_str adds around trait-object bounds (tuple-type parentheses are semantic and preserved), and retries the comparison.

Scope: this keeps the existing string-comparison approach and only unblocks the out-of-module rendering; the milder same-module symptom (concrete turbofish arguments not matching a structured self-type such as MaybeUninit<u32> vs the impl's MaybeUninit<T> — the generic-parameter spelling works there) is unchanged, and a semantic-resolution rewrite would subsume both. Happy to take direction if the deeper rewrite is preferred.

Tests: four unit tests in the existing simple_last_two_items_of_path_match module (dyn-args match + mismatch, tuple parens preserved, non-generic no-fallback) and a new end-to-end regression test tests/kani/FunctionContracts/cross_module_multiple_impls.rs (fails to resolve before the fix, verifies after). Also validated on the motivating case: all three Box<dyn Any…>::downcast_unchecked contracts in verify-rust-std resolve and verify as proof_for_contract targets under the patched resolver.

Applies cleanly on current main (last_two_items_of_path_match is unchanged there). One call-out: candidates whose rendered path contains -> (fn-pointer / Fn-sugar types) are not unwrapped by the fallback's bracket counting — they keep the existing failed-to-resolve behavior rather than matching a different candidate.

Motivating case: model-checking/verify-rust-std#669 — the three Box<dyn Any…>::downcast_unchecked contract targets there.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.

…odule

resolve_in_type_def refines multiple same-named inherent-impl candidates
by comparing the user's turbofish generic arguments against the last two
::-separated segments of def_path_str(candidate). When a candidate's impl
block lives in a different module than its self type, def_path_str renders
it as `path::to::module::<impl path::to::Type<Args>>::method` instead of
`Type::<Args>::method`, and no user-spellable turbofish can match that
<impl ...> wrapper.

Real instance: Box<dyn Any(+Send)(+Sync), A>::downcast_unchecked's three
impls live in alloc/src/boxed/convert.rs while Box is defined in boxed.rs.

Add a fallback in last_two_items_of_path_match: when the direct comparison
fails and the candidate's second-to-last path segment is in <impl SELF_TYPE>
form, extract SELF_TYPE's own generic arguments and retry the comparison
against those. The retry strips the redundant parens def_path_str adds
around a trait-object bound in a generic-argument list (e.g.
`(dyn Any + 'static)` -> `dyn Any + 'static`) before comparing; tuple-type
parens are semantic and preserved.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Z-CompilerBenchCI Tag a PR to run benchmark CI Z-EndToEndBenchCI Tag a PR to run benchmark CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

proof_for_contract cannot resolve methods on impls defined outside the type's own module when multiple same-named candidates exist

1 participant