@@ -8,6 +8,7 @@ use std::ops::ControlFlow;
88use derive_where:: derive_where;
99use rustc_type_ir:: inherent:: * ;
1010use rustc_type_ir:: lang_items:: TraitSolverLangItem ;
11+ use rustc_type_ir:: search_graph:: CandidateUsages ;
1112use rustc_type_ir:: solve:: SizedTraitKind ;
1213use rustc_type_ir:: {
1314 self as ty, Interner , TypeFlags , TypeFoldable , TypeSuperVisitable , TypeVisitable ,
@@ -33,10 +34,11 @@ enum AliasBoundKind {
3334///
3435/// It consists of both the `source`, which describes how that goal would be proven,
3536/// and the `result` when using the given `source`.
36- #[ derive_where( Clone , Debug ; I : Interner ) ]
37+ #[ derive_where( Debug ; I : Interner ) ]
3738pub ( super ) struct Candidate < I : Interner > {
3839 pub ( super ) source : CandidateSource < I > ,
3940 pub ( super ) result : CanonicalResponse < I > ,
41+ pub ( super ) candidate_usages : CandidateUsages ,
4042}
4143
4244/// Methods used to assemble candidates for either trait or projection goals.
@@ -116,8 +118,11 @@ where
116118 ecx : & mut EvalCtxt < ' _ , D > ,
117119 goal : Goal < I , Self > ,
118120 assumption : I :: Clause ,
119- ) -> Result < Candidate < I > , NoSolution > {
120- Self :: fast_reject_assumption ( ecx, goal, assumption) ?;
121+ ) -> Result < Candidate < I > , CandidateUsages > {
122+ match Self :: fast_reject_assumption ( ecx, goal, assumption) {
123+ Ok ( ( ) ) => { }
124+ Err ( NoSolution ) => return Err ( CandidateUsages :: default ( ) ) ,
125+ }
121126
122127 // Dealing with `ParamEnv` candidates is a bit of a mess as we need to lazily
123128 // check whether the candidate is global while considering normalization.
@@ -126,18 +131,23 @@ where
126131 // in `probe` even if the candidate does not apply before we get there. We handle this
127132 // by using a `Cell` here. We only ever write into it inside of `match_assumption`.
128133 let source = Cell :: new ( CandidateSource :: ParamEnv ( ParamEnvSource :: Global ) ) ;
129- ecx. probe ( |result : & QueryResult < I > | inspect:: ProbeKind :: TraitCandidate {
130- source : source. get ( ) ,
131- result : * result,
132- } )
133- . enter ( |ecx| {
134- Self :: match_assumption ( ecx, goal, assumption, |ecx| {
135- ecx. try_evaluate_added_goals ( ) ?;
136- source. set ( ecx. characterize_param_env_assumption ( goal. param_env , assumption) ?) ;
137- ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
134+ let ( result, candidate_usages) = ecx
135+ . probe ( |result : & QueryResult < I > | inspect:: ProbeKind :: TraitCandidate {
136+ source : source. get ( ) ,
137+ result : * result,
138138 } )
139- } )
140- . map ( |result| Candidate { source : source. get ( ) , result } )
139+ . enter_unique_candidate ( |ecx| {
140+ Self :: match_assumption ( ecx, goal, assumption, |ecx| {
141+ ecx. try_evaluate_added_goals ( ) ?;
142+ source. set ( ecx. characterize_param_env_assumption ( goal. param_env , assumption) ?) ;
143+ ecx. evaluate_added_goals_and_make_canonical_response ( Certainty :: Yes )
144+ } )
145+ } ) ;
146+
147+ match result {
148+ Ok ( result) => Ok ( Candidate { source : source. get ( ) , result, candidate_usages } ) ,
149+ Err ( NoSolution ) => Err ( candidate_usages) ,
150+ }
141151 }
142152
143153 /// Try equating an assumption predicate against a goal's predicate. If it
@@ -355,6 +365,12 @@ pub(super) enum AssembleCandidatesFrom {
355365 EnvAndBounds ,
356366}
357367
368+ #[ derive_where( Debug , Default ; I : Interner ) ]
369+ pub ( super ) struct Candidates < I : Interner > {
370+ pub applicable : Vec < Candidate < I > > ,
371+ pub not_applicable_param_env : Vec < CandidateUsages > ,
372+ }
373+
358374impl < D , I > EvalCtxt < ' _ , D >
359375where
360376 D : SolverDelegate < Interner = I > ,
@@ -364,16 +380,18 @@ where
364380 & mut self ,
365381 goal : Goal < I , G > ,
366382 assemble_from : AssembleCandidatesFrom ,
367- ) -> Vec < Candidate < I > > {
383+ ) -> Candidates < I > {
384+ let mut candidates = Candidates :: default ( ) ;
368385 let Ok ( normalized_self_ty) =
369386 self . structurally_normalize_ty ( goal. param_env , goal. predicate . self_ty ( ) )
370387 else {
371- return vec ! [ ] ;
388+ return candidates ;
372389 } ;
373390
374391 if normalized_self_ty. is_ty_var ( ) {
375392 debug ! ( "self type has been normalized to infer" ) ;
376- return self . forced_ambiguity ( MaybeCause :: Ambiguity ) . into_iter ( ) . collect ( ) ;
393+ candidates. applicable . extend ( self . forced_ambiguity ( MaybeCause :: Ambiguity ) ) ;
394+ return candidates;
377395 }
378396
379397 let goal: Goal < I , G > = goal
@@ -382,12 +400,11 @@ where
382400 // normalizing the self type as well, since type variables are not uniquified.
383401 let goal = self . resolve_vars_if_possible ( goal) ;
384402
385- let mut candidates = vec ! [ ] ;
386-
387403 if let TypingMode :: Coherence = self . typing_mode ( )
388404 && let Ok ( candidate) = self . consider_coherence_unknowable_candidate ( goal)
389405 {
390- return vec ! [ candidate] ;
406+ candidates. applicable . push ( candidate) ;
407+ return candidates;
391408 }
392409
393410 self . assemble_alias_bound_candidates ( goal, & mut candidates) ;
@@ -408,7 +425,7 @@ where
408425 // to worry about causing major performance regressions when doing so.
409426 // See trait-system-refactor-initiative#226 for some ideas here.
410427 if TypingMode :: Coherence == self . typing_mode ( )
411- || !candidates. iter ( ) . any ( |c| {
428+ || !candidates. applicable . iter ( ) . any ( |c| {
412429 matches ! (
413430 c. source,
414431 CandidateSource :: ParamEnv ( ParamEnvSource :: NonGlobal )
@@ -445,7 +462,7 @@ where
445462 fn assemble_impl_candidates < G : GoalKind < D > > (
446463 & mut self ,
447464 goal : Goal < I , G > ,
448- candidates : & mut Vec < Candidate < I > > ,
465+ candidates : & mut Candidates < I > ,
449466 ) {
450467 let cx = self . cx ( ) ;
451468 cx. for_each_relevant_impl (
@@ -460,7 +477,7 @@ where
460477 }
461478
462479 match G :: consider_impl_candidate ( self , goal, impl_def_id) {
463- Ok ( candidate) => candidates. push ( candidate) ,
480+ Ok ( candidate) => candidates. applicable . push ( candidate) ,
464481 Err ( NoSolution ) => ( ) ,
465482 }
466483 } ,
@@ -471,7 +488,7 @@ where
471488 fn assemble_builtin_impl_candidates < G : GoalKind < D > > (
472489 & mut self ,
473490 goal : Goal < I , G > ,
474- candidates : & mut Vec < Candidate < I > > ,
491+ candidates : & mut Candidates < I > ,
475492 ) {
476493 let cx = self . cx ( ) ;
477494 let trait_def_id = goal. predicate . trait_def_id ( cx) ;
@@ -570,31 +587,36 @@ where
570587 }
571588 } ;
572589
573- candidates. extend ( result) ;
590+ candidates. applicable . extend ( result) ;
574591
575592 // There may be multiple unsize candidates for a trait with several supertraits:
576593 // `trait Foo: Bar<A> + Bar<B>` and `dyn Foo: Unsize<dyn Bar<_>>`
577594 if cx. is_lang_item ( trait_def_id, TraitSolverLangItem :: Unsize ) {
578- candidates. extend ( G :: consider_structural_builtin_unsize_candidates ( self , goal) ) ;
595+ candidates
596+ . applicable
597+ . extend ( G :: consider_structural_builtin_unsize_candidates ( self , goal) ) ;
579598 }
580599 }
581600
582601 #[ instrument( level = "trace" , skip_all) ]
583602 fn assemble_param_env_candidates < G : GoalKind < D > > (
584603 & mut self ,
585604 goal : Goal < I , G > ,
586- candidates : & mut Vec < Candidate < I > > ,
605+ candidates : & mut Candidates < I > ,
587606 ) {
588607 for assumption in goal. param_env . caller_bounds ( ) . iter ( ) {
589- candidates. extend ( G :: probe_and_consider_param_env_candidate ( self , goal, assumption) ) ;
608+ match G :: probe_and_consider_param_env_candidate ( self , goal, assumption) {
609+ Ok ( candidate) => candidates. applicable . push ( candidate) ,
610+ Err ( candidate_usages) => candidates. not_applicable_param_env . push ( candidate_usages) ,
611+ }
590612 }
591613 }
592614
593615 #[ instrument( level = "trace" , skip_all) ]
594616 fn assemble_alias_bound_candidates < G : GoalKind < D > > (
595617 & mut self ,
596618 goal : Goal < I , G > ,
597- candidates : & mut Vec < Candidate < I > > ,
619+ candidates : & mut Candidates < I > ,
598620 ) {
599621 let ( ) = self . probe ( |_| ProbeKind :: NormalizedSelfTyAssembly ) . enter ( |ecx| {
600622 ecx. assemble_alias_bound_candidates_recur (
@@ -619,7 +641,7 @@ where
619641 & mut self ,
620642 self_ty : I :: Ty ,
621643 goal : Goal < I , G > ,
622- candidates : & mut Vec < Candidate < I > > ,
644+ candidates : & mut Candidates < I > ,
623645 consider_self_bounds : AliasBoundKind ,
624646 ) {
625647 let ( kind, alias_ty) = match self_ty. kind ( ) {
@@ -661,7 +683,11 @@ where
661683 if let Ok ( result) =
662684 self . evaluate_added_goals_and_make_canonical_response ( Certainty :: AMBIGUOUS )
663685 {
664- candidates. push ( Candidate { source : CandidateSource :: AliasBound , result } ) ;
686+ candidates. applicable . push ( Candidate {
687+ source : CandidateSource :: AliasBound ,
688+ result,
689+ candidate_usages : CandidateUsages :: default ( ) ,
690+ } ) ;
665691 }
666692 return ;
667693 }
@@ -680,7 +706,7 @@ where
680706 . item_self_bounds ( alias_ty. def_id )
681707 . iter_instantiated ( self . cx ( ) , alias_ty. args )
682708 {
683- candidates. extend ( G :: probe_and_consider_implied_clause (
709+ candidates. applicable . extend ( G :: probe_and_consider_implied_clause (
684710 self ,
685711 CandidateSource :: AliasBound ,
686712 goal,
@@ -695,7 +721,7 @@ where
695721 . item_non_self_bounds ( alias_ty. def_id )
696722 . iter_instantiated ( self . cx ( ) , alias_ty. args )
697723 {
698- candidates. extend ( G :: probe_and_consider_implied_clause (
724+ candidates. applicable . extend ( G :: probe_and_consider_implied_clause (
699725 self ,
700726 CandidateSource :: AliasBound ,
701727 goal,
@@ -706,7 +732,9 @@ where
706732 }
707733 }
708734
709- candidates. extend ( G :: consider_additional_alias_assumptions ( self , goal, alias_ty) ) ;
735+ candidates
736+ . applicable
737+ . extend ( G :: consider_additional_alias_assumptions ( self , goal, alias_ty) ) ;
710738
711739 if kind != ty:: Projection {
712740 return ;
@@ -728,7 +756,7 @@ where
728756 fn assemble_object_bound_candidates < G : GoalKind < D > > (
729757 & mut self ,
730758 goal : Goal < I , G > ,
731- candidates : & mut Vec < Candidate < I > > ,
759+ candidates : & mut Candidates < I > ,
732760 ) {
733761 let cx = self . cx ( ) ;
734762 if !cx. trait_may_be_implemented_via_object ( goal. predicate . trait_def_id ( cx) ) {
@@ -784,7 +812,7 @@ where
784812 }
785813 ty:: ExistentialPredicate :: Projection ( _)
786814 | ty:: ExistentialPredicate :: AutoTrait ( _) => {
787- candidates. extend ( G :: probe_and_consider_object_bound_candidate (
815+ candidates. applicable . extend ( G :: probe_and_consider_object_bound_candidate (
788816 self ,
789817 CandidateSource :: BuiltinImpl ( BuiltinImplSource :: Misc ) ,
790818 goal,
@@ -800,7 +828,7 @@ where
800828 if let Some ( principal) = bounds. principal ( ) {
801829 let principal_trait_ref = principal. with_self_ty ( cx, self_ty) ;
802830 for ( idx, assumption) in elaborate:: supertraits ( cx, principal_trait_ref) . enumerate ( ) {
803- candidates. extend ( G :: probe_and_consider_object_bound_candidate (
831+ candidates. applicable . extend ( G :: probe_and_consider_object_bound_candidate (
804832 self ,
805833 CandidateSource :: BuiltinImpl ( BuiltinImplSource :: Object ( idx) ) ,
806834 goal,
@@ -959,24 +987,30 @@ where
959987 // Even when a trait bound has been proven using a where-bound, we
960988 // still need to consider alias-bounds for normalization, see
961989 // `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`.
962- let mut candidates: Vec < _ > = self
990+ let mut candidates = self
963991 . assemble_and_evaluate_candidates ( goal, AssembleCandidatesFrom :: EnvAndBounds ) ;
964992
965993 // We still need to prefer where-bounds over alias-bounds however.
966994 // See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`.
967- if candidates. iter ( ) . any ( |c| matches ! ( c. source, CandidateSource :: ParamEnv ( _) ) ) {
968- candidates. retain ( |c| matches ! ( c. source, CandidateSource :: ParamEnv ( _) ) ) ;
969- } else if candidates. is_empty ( ) {
995+ if candidates
996+ . applicable
997+ . iter ( )
998+ . any ( |c| matches ! ( c. source, CandidateSource :: ParamEnv ( _) ) )
999+ {
1000+ for ignored in candidates
1001+ . applicable
1002+ . extract_if ( .., |c| !matches ! ( c. source, CandidateSource :: ParamEnv ( _) ) )
1003+ {
1004+ self . ignore_candidate_usages ( ignored. candidate_usages ) ;
1005+ }
1006+ } else if candidates. applicable . is_empty ( ) {
9701007 // If the trait goal has been proven by using the environment, we want to treat
9711008 // aliases as rigid if there are no applicable projection bounds in the environment.
9721009 return inject_normalize_to_rigid_candidate ( self ) ;
9731010 }
9741011
975- if let Some ( response) = self . try_merge_candidates ( & candidates) {
976- Ok ( response)
977- } else {
978- self . flounder ( & candidates)
979- }
1012+ self . try_merge_candidates ( candidates. applicable , vec ! [ ] )
1013+ . or_else ( |candidates| self . flounder ( & candidates) )
9801014 }
9811015 TraitGoalProvenVia :: Misc => {
9821016 let mut candidates =
@@ -985,23 +1019,31 @@ where
9851019 // Prefer "orphaned" param-env normalization predicates, which are used
9861020 // (for example, and ideally only) when proving item bounds for an impl.
9871021 let candidates_from_env: Vec < _ > = candidates
1022+ . applicable
9881023 . extract_if ( .., |c| matches ! ( c. source, CandidateSource :: ParamEnv ( _) ) )
9891024 . collect ( ) ;
990- if let Some ( response) = self . try_merge_candidates ( & candidates_from_env) {
991- return Ok ( response) ;
1025+ if !candidates_from_env. is_empty ( ) {
1026+ match self . try_merge_candidates (
1027+ candidates_from_env,
1028+ candidates. not_applicable_param_env ,
1029+ ) {
1030+ Ok ( response) => return Ok ( response) ,
1031+ Err ( candidates_from_env) => return self . flounder ( & candidates_from_env) ,
1032+ }
9921033 }
9931034
9941035 // We drop specialized impls to allow normalization via a final impl here. In case
9951036 // the specializing impl has different inference constraints from the specialized
9961037 // impl, proving the trait goal is already ambiguous, so we never get here. This
9971038 // means we can just ignore inference constraints and don't have to special-case
9981039 // constraining the normalized-to `term`.
999- self . filter_specialized_impls ( AllowInferenceConstraints :: Yes , & mut candidates) ;
1000- if let Some ( response) = self . try_merge_candidates ( & candidates) {
1001- Ok ( response)
1002- } else {
1003- self . flounder ( & candidates)
1004- }
1040+ self . filter_specialized_impls (
1041+ AllowInferenceConstraints :: Yes ,
1042+ & mut candidates. applicable ,
1043+ ) ;
1044+
1045+ self . try_merge_candidates ( candidates. applicable , vec ! [ ] )
1046+ . or_else ( |candidates| self . flounder ( & candidates) )
10051047 }
10061048 }
10071049 }
0 commit comments