Implementation plan and status
The general RFD remains incomplete. The DbDropGuard::db vertical slice has a
deliberately conservative external trait-method path: current-module and
all-supported-edition standard-prelude trait enumeration (with only the
intersection treated as definitely in scope), name-based
associated-item discovery, a read-only fixed-trait proof, Self-only signature
instantiation, and explicit shared-reference receiver elaboration. A source
completeness audit and a local-ADT inherent-provider scan prevent this partial
tier from selecting when omitted work could take priority or compete. Missing
metadata, imports, macros, attributes, inherent providers, additional method
type parameters, and competing possible candidates remain unknown rather than
being discarded. The checklist below still describes the complete design.
The next planned integration slice, Parse::next, is tracked by the
Associated Type Normalization
RFD; that RFD owns its projection,
external impl, generic-default, and external inherent-method requirements.
That integration slice now implements prioritized selection for one rigid external-ADT tier. Complete name-keyed metadata supplies receiver-bearing function identities; the selected signature preserves owner versus method type generics and is instantiated in a synchronous child egraph version. Receiver and argument mismatch discards the child and its staged parameter environment. Missing metadata remains incomplete, and broader local/builtin discovery, receiver adjustment, result-driven inference, and conditional-candidate work remain governed by the unchecked items below.
Step 1: Method candidate and result types
-
Preserve local item
visibility_modifiersyntax in CST/symbol data and add checkedVisibilityplusis_visible_fromfor functions and traits, covering private,pub,pub(crate),pub(super), andpub(in path). -
Add
MethodOrigin,ResolvedMethod,MethodResolution, receiver-adjustment, and internal candidate types. -
Include
MethodResolution::Error(ErrorReported)as a propagation state, distinct from lookupNotFound. -
Depend on the Trait System's checked receiver representation; never infer
method-ness or receiver form from a
Ty::Inferfirst parameter. - Represent ambiguity and deferred lookup separately from not-found.
-
Represent candidate evaluation as definite
Yes, conditionalYes, unknown (Maybeor unsupported metadata), orNo; do not apply candidate responses during classification. -
Retain a
NeedsMoreInfolookup as a body-checker lookup obligation keyed by the original receiver/name/scope and relevant inference dependencies; do not publish a competing candidate's residuals before selection. - Add tests for deterministic candidate ordering and result-state transitions.
-
Exhaustively test the resolution table: all
No; a sole definite or conditional candidate; definite plus unknown/conditional; multiple conditionals; conditional plus unknown; multiple definite candidates; and non-exhaustive metadata.
Step 2: Local inherent method discovery
-
Filter
local_impls(db, LocalCrateSymbol)to inherent impls with a matching self-type head andSolverEligibility::Eligible. -
Retain a potentially matching
Unsupportedinherent impl as an incomplete candidate source. In particular, do not try to open lifetime/const-generic impls with type inference variables and do not concludeNotFoundfrom the remaining subset. -
Classify receiver heads as local provider, structurally no provider, or
deferred external/builtin provider. The local scan is exhaustive for the
first,
&T/&mut Twrappers are empty and may proceed to built-in deref, and the last is incomplete while item metadata is unavailable. - Load impl items and select functions by name.
-
For dot calls, retain only functions with a supported
CheckedReceiver; exclude associated functions and unsupported typed/explicit-lifetime receivers before applicability testing. -
Require
method_candidate_eligibility == Eligible. A same-name function with lifetime/const method generics, an incomplete own parameter environment, or a deferred projection/signature form is unknown/incomplete, notFoundfrom its represented subset. -
Filter inherent functions through
is_visible_fromusing the call's lookup module. Inaccessible same-name functions do not contribute viability/ambiguity, but may support a targeted not-visible diagnostic. - Test multiple impl blocks, nested modules, macro-produced impls, nonmatching heads, and duplicate applicable methods.
- Test a private method from the defining module and an inaccessible sibling module, including the diagnostic when it is the only name match.
-
Test
self,mut self,&self, and&mut selfcandidates, exclusion of a same-name associated function, and deferral of a typed receiver. - Test unsupported method generic kinds, own where-predicates, and projection-bearing signatures contribute unknown even when the owner impl itself is eligible.
-
Test that an external receiver head with unavailable inherent metadata is
unknown/unsupported at the priority tier, not
NotFoundor a local-traitFound. -
Test that direct lookup on
&Localis exhaustively empty at the reference wrapper and proceeds to the one built-in deref step instead of being blocked as an unknown external provider.
Step 3: Transactional inherent matching and instantiation
- Open each impl's single binder freshly in an inference probe.
-
Make every caller-egraph exploratory/final probe synchronous and
non-suspending. Await receiver/argument information before branching and
never retain a child version across
.awaitwhile its caller parent is frozen. - Match the full impl self type against the receiver and retain the same substitution for impl where-clauses and the method signature.
-
Before solver integration, defer candidates with nonempty impl
where-clauses or method
CheckedParameterEnvpredicates rather than treating either set as proven. - Retain a branch-independent recipe/response for the unique candidate and discard every exploratory probe; final commit occurs with call compatibility in Step 4.
- Test generic impls, repeated impl generics, unsupported where-clause deferral, and rollback after partial unification failure.
- Instrument a probe to assert it owns no suspension/wait registration and leaves the caller version writable immediately after extraction/discard.
Step 4: Receiver adjustments and body-checker integration
-
Generate the canonical and one built-in-dereferenced
LookupSelfTysequence. Match impl/trait applicability on that type, then derive the permitted value/shared/mutable autoref from the candidate's checked receiver in deterministic order. - Await a bare receiver inference variable and retry when its bound changes.
-
If receiver normalization produces
Ty::Error, propagate its existingErrorReportedinto recovery call IR without candidate discovery or a secondary method diagnostic. - Wire unique inherent methods into method-call argument and result checking.
- Re-open the selected inherent candidate in one transaction which covers its impl substitution, predicate-free signature instantiation, and argument/receiver/result compatibility. This pre-solver step accepts only the empty predicate sets gated in Step 3; Step 6 extends the same transaction with solver responses and staged obligations.
-
Test owned,
&self,&mut self, reference receiver, unknown receiver, not-found, and ambiguous calls. -
Test a receiver finalized to
Ty::Errorterminates lookup immediately and produces exactly the original diagnostic. - Test that a late argument or result mismatch rolls back impl/method variables and wakeups and does not fall through to a losing method candidate.
Step 5: Trait method-name discovery
- Enumerate explicit-bound traits and local traits visible in the lookup scope.
- Apply checked trait visibility from the lookup module independently of the still-deferred complete import/prelude candidate enumeration.
-
Load trait items and retain fixed
(TraitSymbol, FnSymbol)candidates matching the requested name. - Union and deduplicate those pairs across explicit-bound, repeated-bound, import, and visible-local discovery paths before opening trait arguments or counting ambiguity.
- Apply the same checked-receiver gate as inherent dot-call lookup; a same-name trait associated function is not a method candidate.
- Apply the function's method-candidate eligibility independently of its trait owner's eligibility; partial method signatures are unknown.
-
Open only
Eligiblelocal trait signatures. Track a relevantUnsupportedsignature as an unknown/incomplete candidate source rather than silently omitting it. - Keep an explicit external-trait bound as an unknown name source when its item metadata is unavailable; do not silently omit it because local trait discovery cannot load its functions.
-
Do not scan impls or construct an existential
?Traitsolver goal in this step. - Test bound-provided methods, out-of-scope traits, same-name methods on multiple traits, and traits without the method.
- Test that the same trait item discovered from an explicit bound and local visibility is evaluated once, while genuinely different trait/function pairs remain distinct.
Step 6: Fixed-trait solver integration
-
For each trait candidate, open type arguments in an isolated probe and submit the
fixed
LookupSelfTy: Trait<Args...>goal, whereLookupSelfTyis after the current built-in deref step but before method-specific autoref. - Keep solver substitutions and residuals isolated until the outcome table selects exactly one candidate.
-
Treat
Maybeas unknown/NeedsMoreInfoand never expect the solver to return an impl or trait identity. - Retain the unique response and residual for Step 7; do not mutate caller inference or the obligation store during candidate classification.
- Submit instantiated inherent-impl where-clauses through the same fixed-trait solver boundary before committing an inherent candidate.
- Extend the selected inherent-method transaction to instantiate and submit the method function's own parameter-environment predicates after method-generic substitution, staging all residuals until commit.
- Test environment-assumption proofs, local impl proofs, conditional proofs, multiple viable traits, solver ambiguity, and losing-candidate rollback.
-
s.foo()selectingfn foo(&self)proves/matches impls forS, then records/checks an&Sautoref; it never asks the solver for&S: Trait. - Test an inherent impl/method predicate response followed by a late call mismatch; solver effects, wakeups, and staged obligations all roll back.
-
In a default trait method body, the synthesized owner fact proves the
fixed
Self: ThisTraitgoal needed to call another method from that trait; no recursive impl search or selected-impl evidence is required.
Step 7: Trait method signature instantiation
- Import the selected function signature from the trait item.
-
Substitute
Selfand trait arguments from the retained proof response. - Instantiate method-level generics independently and check call arguments.
- Perform response application, signature instantiation, the method function's instantiated parameter-environment predicates, receiver/argument/result checking, and residual-obligation staging in one selected-method child transaction. Commit the egraph child before publishing its staged obligations; discard both on any failure.
- Test generic receivers, generic traits, explicit bounds, and final failure when a registered residual obligation cannot be discharged.
-
Test a method-level
where U: Boundpredicate after method-generic substitution; it is staged on success and absent after rollback. - Test rollback on a late argument/result mismatch and verify that no selected-candidate substitution, fresh method variable, wake, or residual obligation escapes.
Step 8: Qualified and associated calls
-
Resolve visible local inherent
Type::functioncalls for functions with no checked receiver. Reuse impl-head classification/ambiguity and prove the selected impl predicates. - Instantiate associated-function generics and its own parameter environment, check arguments/results, and stage obligations in one selected call transaction with full late-failure rollback.
-
Return unsupported/unknown rather than exhaustive
NotFoundfor an external type whose inherent associated-item metadata is unavailable. -
Add receiver-less fixed-trait
<Type as Trait>::functionlookup after qualified paths are lowered, including fixed-trait proof, signature instantiation, visibility, eligibility, and the same transaction. - Preserve ambiguity and visibility diagnostics instead of selecting by source order.
- Test impl/function predicates, generics, ambiguity, inaccessible items, external incompleteness, argument/result mismatch rollback, and exclusion of receiver-taking functions until full UFCS.
Deferred beyond the vertical slice
-
General external and builtin method providers beyond represented trait
items and structural
Sized. - Lifetime/const-generic method candidates.
- Complete trait visibility and prelude behavior.
-
Custom
Derefand associated type normalization. - Full UFCS and method turbofish behavior.
- Specialization-aware method priority.