@@ -60,6 +60,20 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
6060mod candidate_assembly;
6161mod confirmation;
6262
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+
6377#[ derive( Clone , Debug , Eq , PartialEq , Hash ) ]
6478pub enum IntercrateAmbiguityCause < ' tcx > {
6579 DownstreamCrate { trait_ref : ty:: TraitRef < ' tcx > , self_ty : Option < Ty < ' tcx > > } ,
@@ -384,7 +398,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
384398 let mut no_candidates_apply = true ;
385399
386400 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+ {
388405 no_candidates_apply = false ;
389406 break ;
390407 }
@@ -455,7 +472,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
455472 // is needed for specialization. Propagate overflow if it occurs.
456473 let mut candidates = candidates
457474 . into_iter ( )
458- . map ( |c| match self . evaluate_candidate ( stack, & c) {
475+ . map ( |c| match self . evaluate_candidate ( stack, & c, LeakCheckHigherRankedGoal :: No ) {
459476 Ok ( eval) if eval. may_apply ( ) => {
460477 Ok ( Some ( EvaluatedCandidate { candidate : c, evaluation : eval } ) )
461478 }
@@ -545,7 +562,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
545562 obligation : & PredicateObligation < ' tcx > ,
546563 ) -> Result < EvaluationResult , OverflowError > {
547564 debug_assert ! ( !self . infcx. next_trait_solver( ) ) ;
548- self . evaluation_probe ( |this| {
565+ self . evaluation_probe ( |this, _outer_universe | {
549566 let goal =
550567 this. infcx . resolve_vars_if_possible ( ( obligation. predicate , obligation. param_env ) ) ;
551568 let mut result = this. evaluate_predicate_recursively (
@@ -561,13 +578,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
561578 } )
562579 }
563580
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.
564586 fn evaluation_probe (
565587 & mut self ,
566- op : impl FnOnce ( & mut Self ) -> Result < EvaluationResult , OverflowError > ,
588+ op : impl FnOnce ( & mut Self , & mut ty :: UniverseIndex ) -> Result < EvaluationResult , OverflowError > ,
567589 ) -> Result < EvaluationResult , OverflowError > {
568590 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 ) ?;
571593
572594 match self . infcx . leak_check ( outer_universe, Some ( snapshot) ) {
573595 Ok ( ( ) ) => { }
@@ -586,9 +608,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
586608 } )
587609 }
588610
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
591613 /// is run within an inference probe.
614+ /// `probe`.
592615 #[ instrument( skip( self , stack) , level = "debug" ) ]
593616 fn evaluate_predicates_recursively < ' o , I > (
594617 & mut self ,
@@ -1194,7 +1217,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
11941217 }
11951218
11961219 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 ) ,
11981221 Ok ( None ) => Ok ( EvaluatedToAmbig ) ,
11991222 Err ( Overflow ( OverflowError :: Canonical ) ) => Err ( OverflowError :: Canonical ) ,
12001223 Err ( ..) => Ok ( EvaluatedToErr ) ,
@@ -1219,6 +1242,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12191242 /// Further evaluates `candidate` to decide whether all type parameters match and whether nested
12201243 /// obligations are met. Returns whether `candidate` remains viable after this further
12211244 /// 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.
12221249 #[ instrument(
12231250 level = "debug" ,
12241251 skip( self , stack) ,
@@ -1229,10 +1256,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
12291256 & mut self ,
12301257 stack : & TraitObligationStack < ' o , ' tcx > ,
12311258 candidate : & SelectionCandidate < ' tcx > ,
1259+ leak_check_higher_ranked_goal : LeakCheckHigherRankedGoal ,
12321260 ) -> 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 ( ) ) {
12361278 Ok ( selection) => {
12371279 debug ! ( ?selection) ;
12381280 this. evaluate_predicates_recursively (
@@ -1657,8 +1699,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16571699 stack : & TraitObligationStack < ' o , ' tcx > ,
16581700 where_clause_trait_ref : ty:: PolyTraitRef < ' tcx > ,
16591701 ) -> 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) {
16621710 Ok ( obligations) => this. evaluate_predicates_recursively ( stack. list ( ) , obligations) ,
16631711 Err ( ( ) ) => Ok ( EvaluatedToErr ) ,
16641712 }
0 commit comments