@@ -60,6 +60,20 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
60
60
mod candidate_assembly;
61
61
mod confirmation;
62
62
63
+ /// Whether to consider the binder of higher ranked goals for the `leak_check` when
64
+ /// evaluating higher-ranked goals. See #119820 for more info.
65
+ ///
66
+ /// While this is a bit hacky, it is necessary to match the behavior of the new solver:
67
+ /// We eagerly instantiate binders in the new solver, outside of candidate selection, so
68
+ /// the leak check inside of candidates does not consider any bound vars from the higher
69
+ /// ranked goal. However, we do exit the binder once we're completely finished with a goal,
70
+ /// so the leak-check can be used in evaluate by causing nested higher-ranked goals to fail.
71
+ #[ derive( Debug , Copy , Clone ) ]
72
+ enum LeakCheckHigherRankedGoal {
73
+ No ,
74
+ Yes ,
75
+ }
76
+
63
77
#[ derive( Clone , Debug , Eq , PartialEq , Hash ) ]
64
78
pub enum IntercrateAmbiguityCause < ' tcx > {
65
79
DownstreamCrate { trait_ref : ty:: TraitRef < ' tcx > , self_ty : Option < Ty < ' tcx > > } ,
@@ -384,7 +398,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
384
398
let mut no_candidates_apply = true ;
385
399
386
400
for c in candidate_set. vec . iter ( ) {
387
- if self . evaluate_candidate ( stack, c) ?. may_apply ( ) {
401
+ if self
402
+ . evaluate_candidate ( stack, c, LeakCheckHigherRankedGoal :: No ) ?
403
+ . may_apply ( )
404
+ {
388
405
no_candidates_apply = false ;
389
406
break ;
390
407
}
@@ -455,7 +472,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
455
472
// is needed for specialization. Propagate overflow if it occurs.
456
473
let mut candidates = candidates
457
474
. into_iter ( )
458
- . map ( |c| match self . evaluate_candidate ( stack, & c) {
475
+ . map ( |c| match self . evaluate_candidate ( stack, & c, LeakCheckHigherRankedGoal :: No ) {
459
476
Ok ( eval) if eval. may_apply ( ) => {
460
477
Ok ( Some ( EvaluatedCandidate { candidate : c, evaluation : eval } ) )
461
478
}
@@ -545,7 +562,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
545
562
obligation : & PredicateObligation < ' tcx > ,
546
563
) -> Result < EvaluationResult , OverflowError > {
547
564
debug_assert ! ( !self . infcx. next_trait_solver( ) ) ;
548
- self . evaluation_probe ( |this| {
565
+ self . evaluation_probe ( |this, _outer_universe | {
549
566
let goal =
550
567
this. infcx . resolve_vars_if_possible ( ( obligation. predicate , obligation. param_env ) ) ;
551
568
let mut result = this. evaluate_predicate_recursively (
@@ -561,13 +578,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
561
578
} )
562
579
}
563
580
581
+ /// Computes the evaluation result of `op`, discarding any constraints.
582
+ ///
583
+ /// This also runs for leak check to allow higher ranked region errors to impact
584
+ /// selection. By default it checks for leaks from all universes created inside of
585
+ /// `op`, but this can be overwritten if necessary.
564
586
fn evaluation_probe (
565
587
& mut self ,
566
- op : impl FnOnce ( & mut Self ) -> Result < EvaluationResult , OverflowError > ,
588
+ op : impl FnOnce ( & mut Self , & mut ty :: UniverseIndex ) -> Result < EvaluationResult , OverflowError > ,
567
589
) -> Result < EvaluationResult , OverflowError > {
568
590
self . infcx . probe ( |snapshot| -> Result < EvaluationResult , OverflowError > {
569
- let outer_universe = self . infcx . universe ( ) ;
570
- let result = op ( self ) ?;
591
+ let mut outer_universe = self . infcx . universe ( ) ;
592
+ let result = op ( self , & mut outer_universe ) ?;
571
593
572
594
match self . infcx . leak_check ( outer_universe, Some ( snapshot) ) {
573
595
Ok ( ( ) ) => { }
@@ -586,9 +608,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
586
608
} )
587
609
}
588
610
589
- /// Evaluates the predicates in `predicates` recursively. Note that
590
- /// this applies projections in the predicates, and therefore
611
+ /// Evaluates the predicates in `predicates` recursively. This may
612
+ /// guide inference. If this is not desired, run it inside of a
591
613
/// is run within an inference probe.
614
+ /// `probe`.
592
615
#[ instrument( skip( self , stack) , level = "debug" ) ]
593
616
fn evaluate_predicates_recursively < ' o , I > (
594
617
& mut self ,
@@ -1194,7 +1217,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
1194
1217
}
1195
1218
1196
1219
match self . candidate_from_obligation ( stack) {
1197
- Ok ( Some ( c) ) => self . evaluate_candidate ( stack, & c) ,
1220
+ Ok ( Some ( c) ) => self . evaluate_candidate ( stack, & c, LeakCheckHigherRankedGoal :: Yes ) ,
1198
1221
Ok ( None ) => Ok ( EvaluatedToAmbig ) ,
1199
1222
Err ( Overflow ( OverflowError :: Canonical ) ) => Err ( OverflowError :: Canonical ) ,
1200
1223
Err ( ..) => Ok ( EvaluatedToErr ) ,
@@ -1219,6 +1242,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
1219
1242
/// Further evaluates `candidate` to decide whether all type parameters match and whether nested
1220
1243
/// obligations are met. Returns whether `candidate` remains viable after this further
1221
1244
/// scrutiny.
1245
+ ///
1246
+ /// Depending on the value of [LeakCheckHigherRankedGoal], we may ignore the binder of the goal
1247
+ /// when eagerly detecting higher ranked region errors via the `leak_check`. See that enum for
1248
+ /// more info.
1222
1249
#[ instrument(
1223
1250
level = "debug" ,
1224
1251
skip( self , stack) ,
@@ -1229,10 +1256,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
1229
1256
& mut self ,
1230
1257
stack : & TraitObligationStack < ' o , ' tcx > ,
1231
1258
candidate : & SelectionCandidate < ' tcx > ,
1259
+ leak_check_higher_ranked_goal : LeakCheckHigherRankedGoal ,
1232
1260
) -> Result < EvaluationResult , OverflowError > {
1233
- let mut result = self . evaluation_probe ( |this| {
1234
- let candidate = ( * candidate) . clone ( ) ;
1235
- match this. confirm_candidate ( stack. obligation , candidate) {
1261
+ let mut result = self . evaluation_probe ( |this, outer_universe| {
1262
+ // We eagerly instantiate higher ranked goals to prevent universe errors
1263
+ // from impacting candidate selection. This matches the behavior of the new
1264
+ // solver. This slightly weakens type inference.
1265
+ //
1266
+ // In case there are no unresolved type or const variables this
1267
+ // should still not be necessary to select a unique impl as any overlap
1268
+ // relying on a universe error from higher ranked goals should have resulted
1269
+ // in an overlap error in coherence.
1270
+ let p = self . infcx . enter_forall_and_leak_universe ( stack. obligation . predicate ) ;
1271
+ let obligation = stack. obligation . with ( this. tcx ( ) , ty:: Binder :: dummy ( p) ) ;
1272
+ match leak_check_higher_ranked_goal {
1273
+ LeakCheckHigherRankedGoal :: No => * outer_universe = self . infcx . universe ( ) ,
1274
+ LeakCheckHigherRankedGoal :: Yes => { }
1275
+ }
1276
+
1277
+ match this. confirm_candidate ( & obligation, candidate. clone ( ) ) {
1236
1278
Ok ( selection) => {
1237
1279
debug ! ( ?selection) ;
1238
1280
this. evaluate_predicates_recursively (
@@ -1657,8 +1699,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
1657
1699
stack : & TraitObligationStack < ' o , ' tcx > ,
1658
1700
where_clause_trait_ref : ty:: PolyTraitRef < ' tcx > ,
1659
1701
) -> Result < EvaluationResult , OverflowError > {
1660
- self . evaluation_probe ( |this| {
1661
- match this. match_where_clause_trait_ref ( stack. obligation , where_clause_trait_ref) {
1702
+ self . evaluation_probe ( |this, outer_universe| {
1703
+ // Eagerly instantiate higher ranked goals.
1704
+ //
1705
+ // See the comment in `evaluate_candidate` to see why.
1706
+ let p = self . infcx . enter_forall_and_leak_universe ( stack. obligation . predicate ) ;
1707
+ let obligation = stack. obligation . with ( this. tcx ( ) , ty:: Binder :: dummy ( p) ) ;
1708
+ * outer_universe = self . infcx . universe ( ) ;
1709
+ match this. match_where_clause_trait_ref ( & obligation, where_clause_trait_ref) {
1662
1710
Ok ( obligations) => this. evaluate_predicates_recursively ( stack. list ( ) , obligations) ,
1663
1711
Err ( ( ) ) => Ok ( EvaluatedToErr ) ,
1664
1712
}
0 commit comments