@@ -8,6 +8,7 @@ use std::ops::ControlFlow;
8
8
use derive_where:: derive_where;
9
9
use rustc_type_ir:: inherent:: * ;
10
10
use rustc_type_ir:: lang_items:: TraitSolverLangItem ;
11
+ use rustc_type_ir:: search_graph:: CandidateHeadUsages ;
11
12
use rustc_type_ir:: solve:: SizedTraitKind ;
12
13
use rustc_type_ir:: {
13
14
self as ty, Interner , TypeFlags , TypeFoldable , TypeSuperVisitable , TypeVisitable ,
@@ -33,10 +34,11 @@ enum AliasBoundKind {
33
34
///
34
35
/// It consists of both the `source`, which describes how that goal would be proven,
35
36
/// and the `result` when using the given `source`.
36
- #[ derive_where( Clone , Debug ; I : Interner ) ]
37
+ #[ derive_where( Debug ; I : Interner ) ]
37
38
pub ( super ) struct Candidate < I : Interner > {
38
39
pub ( super ) source : CandidateSource < I > ,
39
40
pub ( super ) result : CanonicalResponse < I > ,
41
+ pub ( super ) head_usages : CandidateHeadUsages ,
40
42
}
41
43
42
44
/// Methods used to assemble candidates for either trait or projection goals.
@@ -116,8 +118,11 @@ where
116
118
ecx : & mut EvalCtxt < ' _ , D > ,
117
119
goal : Goal < I , Self > ,
118
120
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
+ }
121
126
122
127
// Dealing with `ParamEnv` candidates is a bit of a mess as we need to lazily
123
128
// check whether the candidate is global while considering normalization.
@@ -126,18 +131,23 @@ where
126
131
// in `probe` even if the candidate does not apply before we get there. We handle this
127
132
// by using a `Cell` here. We only ever write into it inside of `match_assumption`.
128
133
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,
138
138
} )
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
+ }
141
151
}
142
152
143
153
/// Try equating an assumption predicate against a goal's predicate. If it
@@ -355,6 +365,19 @@ pub(super) enum AssembleCandidatesFrom {
355
365
EnvAndBounds ,
356
366
}
357
367
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
+
358
381
impl < D , I > EvalCtxt < ' _ , D >
359
382
where
360
383
D : SolverDelegate < Interner = I > ,
@@ -364,16 +387,20 @@ where
364
387
& mut self ,
365
388
goal : Goal < I , G > ,
366
389
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 ( ) } ;
368
394
let Ok ( normalized_self_ty) =
369
395
self . structurally_normalize_ty ( goal. param_env , goal. predicate . self_ty ( ) )
370
396
else {
371
- return vec ! [ ] ;
397
+ return ( candidates , failed_candidate_info ) ;
372
398
} ;
373
399
374
400
if normalized_self_ty. is_ty_var ( ) {
375
401
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) ;
377
404
}
378
405
379
406
let goal: Goal < I , G > = goal
@@ -382,16 +409,15 @@ where
382
409
// normalizing the self type as well, since type variables are not uniquified.
383
410
let goal = self . resolve_vars_if_possible ( goal) ;
384
411
385
- let mut candidates = vec ! [ ] ;
386
-
387
412
if let TypingMode :: Coherence = self . typing_mode ( )
388
413
&& let Ok ( candidate) = self . consider_coherence_unknowable_candidate ( goal)
389
414
{
390
- return vec ! [ candidate] ;
415
+ candidates. push ( candidate) ;
416
+ return ( candidates, failed_candidate_info) ;
391
417
}
392
418
393
419
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 ) ;
395
421
396
422
match assemble_from {
397
423
AssembleCandidatesFrom :: All => {
@@ -423,7 +449,7 @@ where
423
449
AssembleCandidatesFrom :: EnvAndBounds => { }
424
450
}
425
451
426
- candidates
452
+ ( candidates, failed_candidate_info )
427
453
}
428
454
429
455
pub ( super ) fn forced_ambiguity (
@@ -584,9 +610,15 @@ where
584
610
& mut self ,
585
611
goal : Goal < I , G > ,
586
612
candidates : & mut Vec < Candidate < I > > ,
613
+ failed_candidate_info : & mut FailedCandidateInfo ,
587
614
) {
588
615
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
+ }
590
622
}
591
623
}
592
624
@@ -661,7 +693,11 @@ where
661
693
if let Ok ( result) =
662
694
self . evaluate_added_goals_and_make_canonical_response ( Certainty :: AMBIGUOUS )
663
695
{
664
- candidates. push ( Candidate { source : CandidateSource :: AliasBound , result } ) ;
696
+ candidates. push ( Candidate {
697
+ source : CandidateSource :: AliasBound ,
698
+ result,
699
+ head_usages : CandidateHeadUsages :: default ( ) ,
700
+ } ) ;
665
701
}
666
702
return ;
667
703
}
@@ -959,7 +995,7 @@ where
959
995
// Even when a trait bound has been proven using a where-bound, we
960
996
// still need to consider alias-bounds for normalization, see
961
997
// `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`.
962
- let mut candidates: Vec < _ > = self
998
+ let ( mut candidates, _ ) = self
963
999
. assemble_and_evaluate_candidates ( goal, AssembleCandidatesFrom :: EnvAndBounds ) ;
964
1000
965
1001
// We still need to prefer where-bounds over alias-bounds however.
@@ -972,23 +1008,20 @@ where
972
1008
return inject_normalize_to_rigid_candidate ( self ) ;
973
1009
}
974
1010
975
- if let Some ( response) = self . try_merge_candidates ( & candidates) {
1011
+ if let Some ( ( response, _ ) ) = self . try_merge_candidates ( & candidates) {
976
1012
Ok ( response)
977
1013
} else {
978
1014
self . flounder ( & candidates)
979
1015
}
980
1016
}
981
1017
TraitGoalProvenVia :: Misc => {
982
- let mut candidates =
1018
+ let ( mut candidates, _ ) =
983
1019
self . assemble_and_evaluate_candidates ( goal, AssembleCandidatesFrom :: All ) ;
984
1020
985
1021
// Prefer "orphaned" param-env normalization predicates, which are used
986
1022
// (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 ( _) ) ) ;
992
1025
}
993
1026
994
1027
// We drop specialized impls to allow normalization via a final impl here. In case
@@ -997,7 +1030,7 @@ where
997
1030
// means we can just ignore inference constraints and don't have to special-case
998
1031
// constraining the normalized-to `term`.
999
1032
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) {
1001
1034
Ok ( response)
1002
1035
} else {
1003
1036
self . flounder ( & candidates)
0 commit comments