@@ -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:: CandidateHeadUsages ;
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 ) head_usages : CandidateHeadUsages ,
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 > , CandidateHeadUsages > {
122+ match Self :: fast_reject_assumption ( ecx, goal, assumption) {
123+ Ok ( ( ) ) => { }
124+ Err ( NoSolution ) => return Err ( CandidateHeadUsages :: 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, head_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_single_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, head_usages } ) ,
149+ Err ( NoSolution ) => Err ( head_usages) ,
150+ }
141151 }
142152
143153 /// Try equating an assumption predicate against a goal's predicate. If it
@@ -355,6 +365,19 @@ pub(super) enum AssembleCandidatesFrom {
355365 EnvAndBounds ,
356366}
357367
368+ /// This is currently used to track the [CandidateHeadUsages] of all failed `ParamEnv`
369+ /// candidates. This is then used to ignore their head usages in case there's another
370+ /// always applicable `ParamEnv` candidate. Look at how `param_env_head_usages` is
371+ /// used in the code for more details.
372+ ///
373+ /// We could easily extend this to also ignore head usages of other ignored candidates.
374+ /// However, we currently don't have any tests where this matters and the complexity of
375+ /// doing so does not feel worth it for now.
376+ #[ derive( Debug ) ]
377+ pub ( super ) struct FailedCandidateInfo {
378+ pub param_env_head_usages : CandidateHeadUsages ,
379+ }
380+
358381impl < D , I > EvalCtxt < ' _ , D >
359382where
360383 D : SolverDelegate < Interner = I > ,
@@ -364,16 +387,20 @@ where
364387 & mut self ,
365388 goal : Goal < I , G > ,
366389 assemble_from : AssembleCandidatesFrom ,
367- ) -> Vec < Candidate < I > > {
390+ ) -> ( Vec < Candidate < I > > , FailedCandidateInfo ) {
391+ let mut candidates = vec ! [ ] ;
392+ let mut failed_candidate_info =
393+ FailedCandidateInfo { param_env_head_usages : CandidateHeadUsages :: default ( ) } ;
368394 let Ok ( normalized_self_ty) =
369395 self . structurally_normalize_ty ( goal. param_env , goal. predicate . self_ty ( ) )
370396 else {
371- return vec ! [ ] ;
397+ return ( candidates , failed_candidate_info ) ;
372398 } ;
373399
374400 if normalized_self_ty. is_ty_var ( ) {
375401 debug ! ( "self type has been normalized to infer" ) ;
376- return self . forced_ambiguity ( MaybeCause :: Ambiguity ) . into_iter ( ) . collect ( ) ;
402+ candidates. extend ( self . forced_ambiguity ( MaybeCause :: Ambiguity ) ) ;
403+ return ( candidates, failed_candidate_info) ;
377404 }
378405
379406 let goal: Goal < I , G > = goal
@@ -382,16 +409,15 @@ where
382409 // normalizing the self type as well, since type variables are not uniquified.
383410 let goal = self . resolve_vars_if_possible ( goal) ;
384411
385- let mut candidates = vec ! [ ] ;
386-
387412 if let TypingMode :: Coherence = self . typing_mode ( )
388413 && let Ok ( candidate) = self . consider_coherence_unknowable_candidate ( goal)
389414 {
390- return vec ! [ candidate] ;
415+ candidates. push ( candidate) ;
416+ return ( candidates, failed_candidate_info) ;
391417 }
392418
393419 self . assemble_alias_bound_candidates ( goal, & mut candidates) ;
394- self . assemble_param_env_candidates ( goal, & mut candidates) ;
420+ self . assemble_param_env_candidates ( goal, & mut candidates, & mut failed_candidate_info ) ;
395421
396422 match assemble_from {
397423 AssembleCandidatesFrom :: All => {
@@ -423,7 +449,7 @@ where
423449 AssembleCandidatesFrom :: EnvAndBounds => { }
424450 }
425451
426- candidates
452+ ( candidates, failed_candidate_info )
427453 }
428454
429455 pub ( super ) fn forced_ambiguity (
@@ -584,9 +610,15 @@ where
584610 & mut self ,
585611 goal : Goal < I , G > ,
586612 candidates : & mut Vec < Candidate < I > > ,
613+ failed_candidate_info : & mut FailedCandidateInfo ,
587614 ) {
588615 for assumption in goal. param_env . caller_bounds ( ) . iter ( ) {
589- candidates. extend ( G :: probe_and_consider_param_env_candidate ( self , goal, assumption) ) ;
616+ match G :: probe_and_consider_param_env_candidate ( self , goal, assumption) {
617+ Ok ( candidate) => candidates. push ( candidate) ,
618+ Err ( head_usages) => {
619+ failed_candidate_info. param_env_head_usages . merge_usages ( head_usages)
620+ }
621+ }
590622 }
591623 }
592624
@@ -661,7 +693,11 @@ where
661693 if let Ok ( result) =
662694 self . evaluate_added_goals_and_make_canonical_response ( Certainty :: AMBIGUOUS )
663695 {
664- candidates. push ( Candidate { source : CandidateSource :: AliasBound , result } ) ;
696+ candidates. push ( Candidate {
697+ source : CandidateSource :: AliasBound ,
698+ result,
699+ head_usages : CandidateHeadUsages :: default ( ) ,
700+ } ) ;
665701 }
666702 return ;
667703 }
@@ -959,7 +995,7 @@ where
959995 // Even when a trait bound has been proven using a where-bound, we
960996 // still need to consider alias-bounds for normalization, see
961997 // `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`.
962- let mut candidates: Vec < _ > = self
998+ let ( mut candidates, _ ) = self
963999 . assemble_and_evaluate_candidates ( goal, AssembleCandidatesFrom :: EnvAndBounds ) ;
9641000
9651001 // We still need to prefer where-bounds over alias-bounds however.
@@ -972,23 +1008,20 @@ where
9721008 return inject_normalize_to_rigid_candidate ( self ) ;
9731009 }
9741010
975- if let Some ( response) = self . try_merge_candidates ( & candidates) {
1011+ if let Some ( ( response, _ ) ) = self . try_merge_candidates ( & candidates) {
9761012 Ok ( response)
9771013 } else {
9781014 self . flounder ( & candidates)
9791015 }
9801016 }
9811017 TraitGoalProvenVia :: Misc => {
982- let mut candidates =
1018+ let ( mut candidates, _ ) =
9831019 self . assemble_and_evaluate_candidates ( goal, AssembleCandidatesFrom :: All ) ;
9841020
9851021 // Prefer "orphaned" param-env normalization predicates, which are used
9861022 // (for example, and ideally only) when proving item bounds for an impl.
987- let candidates_from_env: Vec < _ > = candidates
988- . extract_if ( .., |c| matches ! ( c. source, CandidateSource :: ParamEnv ( _) ) )
989- . collect ( ) ;
990- if let Some ( response) = self . try_merge_candidates ( & candidates_from_env) {
991- return Ok ( response) ;
1023+ if candidates. iter ( ) . any ( |c| matches ! ( c. source, CandidateSource :: ParamEnv ( _) ) ) {
1024+ candidates. retain ( |c| matches ! ( c. source, CandidateSource :: ParamEnv ( _) ) ) ;
9921025 }
9931026
9941027 // We drop specialized impls to allow normalization via a final impl here. In case
@@ -997,7 +1030,7 @@ where
9971030 // means we can just ignore inference constraints and don't have to special-case
9981031 // constraining the normalized-to `term`.
9991032 self . filter_specialized_impls ( AllowInferenceConstraints :: Yes , & mut candidates) ;
1000- if let Some ( response) = self . try_merge_candidates ( & candidates) {
1033+ if let Some ( ( response, _ ) ) = self . try_merge_candidates ( & candidates) {
10011034 Ok ( response)
10021035 } else {
10031036 self . flounder ( & candidates)
0 commit comments