@@ -45,8 +45,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
4545 projection_ty : goal. predicate . projection_ty ,
4646 term : unconstrained_rhs,
4747 } ) ;
48- let ( _has_changed, normalize_certainty) =
49- self . evaluate_goal ( goal. with ( self . tcx ( ) , unconstrained_predicate) ) ?;
48+ let ( _has_changed, normalize_certainty) = self . in_projection_eq_hack ( |this| {
49+ this. evaluate_goal ( goal. with ( this. tcx ( ) , unconstrained_predicate) )
50+ } ) ?;
5051
5152 let nested_eq_goals =
5253 self . infcx . eq ( goal. param_env , unconstrained_rhs, predicate. term ) ?;
@@ -55,6 +56,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
5556 }
5657 }
5758
59+ /// This sets a flag used by a debug assert in [`EvalCtxt::evaluate_goal`],
60+ /// see the comment in that method for more details.
61+ fn in_projection_eq_hack < T > ( & mut self , f : impl FnOnce ( & mut Self ) -> T ) -> T {
62+ self . in_projection_eq_hack = true ;
63+ let result = f ( self ) ;
64+ self . in_projection_eq_hack = false ;
65+ result
66+ }
67+
5868 /// Is the projection predicate is of the form `exists<T> <Ty as Trait>::Assoc = T`.
5969 ///
6070 /// This is the case if the `term` is an inference variable in the innermost universe
@@ -122,6 +132,28 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
122132 && goal. param_env . visit_with ( & mut visitor) . is_continue ( )
123133 }
124134
135+ /// After normalizing the projection to `normalized_alias` with the given
136+ /// `normalization_certainty`, constrain the inference variable `term` to it
137+ /// and return a query response.
138+ fn eq_term_and_make_canonical_response (
139+ & mut self ,
140+ goal : Goal < ' tcx , ProjectionPredicate < ' tcx > > ,
141+ normalization_certainty : Certainty ,
142+ normalized_alias : impl Into < ty:: Term < ' tcx > > ,
143+ ) -> QueryResult < ' tcx > {
144+ // The term of our goal should be fully unconstrained, so this should never fail.
145+ //
146+ // It can however be ambiguous when the `normalized_alias` contains a projection.
147+ let nested_goals = self
148+ . infcx
149+ . eq ( goal. param_env , goal. predicate . term , normalized_alias. into ( ) )
150+ . expect ( "failed to unify with unconstrained term" ) ;
151+ let rhs_certainty =
152+ self . evaluate_all ( nested_goals) . expect ( "failed to unify with unconstrained term" ) ;
153+
154+ self . make_canonical_response ( normalization_certainty. unify_and ( rhs_certainty) )
155+ }
156+
125157 fn merge_project_candidates (
126158 & mut self ,
127159 mut candidates : Vec < Candidate < ' tcx > > ,
@@ -218,7 +250,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
218250 . map ( |pred| goal. with ( tcx, pred) ) ;
219251
220252 nested_goals. extend ( where_clause_bounds) ;
221- let trait_ref_certainty = ecx. evaluate_all ( nested_goals) ?;
253+ let match_impl_certainty = ecx. evaluate_all ( nested_goals) ?;
222254
223255 // In case the associated item is hidden due to specialization, we have to
224256 // return ambiguity this would otherwise be incomplete, resulting in
@@ -230,7 +262,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
230262 goal. predicate . def_id ( ) ,
231263 impl_def_id
232264 ) ? else {
233- return ecx. make_canonical_response ( trait_ref_certainty . unify_and ( Certainty :: AMBIGUOUS ) ) ;
265+ return ecx. make_canonical_response ( match_impl_certainty . unify_and ( Certainty :: AMBIGUOUS ) ) ;
234266 } ;
235267
236268 if !assoc_def. item . defaultness ( tcx) . has_value ( ) {
@@ -277,17 +309,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
277309 ty. map_bound ( |ty| ty. into ( ) )
278310 } ;
279311
280- // The term of our goal should be fully unconstrained, so this should never fail.
281- //
282- // It can however be ambiguous when the resolved type is a projection.
283- let nested_goals = ecx
284- . infcx
285- . eq ( goal. param_env , goal. predicate . term , term. subst ( tcx, substs) )
286- . expect ( "failed to unify with unconstrained term" ) ;
287- let rhs_certainty =
288- ecx. evaluate_all ( nested_goals) . expect ( "failed to unify with unconstrained term" ) ;
289-
290- ecx. make_canonical_response ( trait_ref_certainty. unify_and ( rhs_certainty) )
312+ ecx. eq_term_and_make_canonical_response ( goal, match_impl_certainty, term. subst ( tcx, substs) )
291313 } )
292314 }
293315
@@ -309,18 +331,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
309331 ) ?;
310332 let subst_certainty = ecx. evaluate_all ( nested_goals) ?;
311333
312- // The term of our goal should be fully unconstrained, so this should never fail.
313- //
314- // It can however be ambiguous when the resolved type is a projection.
315- let nested_goals = ecx
316- . infcx
317- . eq ( goal. param_env , goal. predicate . term , assumption_projection_pred. term )
318- . expect ( "failed to unify with unconstrained term" ) ;
319- let rhs_certainty = ecx
320- . evaluate_all ( nested_goals)
321- . expect ( "failed to unify with unconstrained term" ) ;
322-
323- ecx. make_canonical_response ( subst_certainty. unify_and ( rhs_certainty) )
334+ ecx. eq_term_and_make_canonical_response (
335+ goal,
336+ subst_certainty,
337+ assumption_projection_pred. term ,
338+ )
324339 } )
325340 } else {
326341 Err ( NoSolution )
@@ -437,14 +452,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
437452 [ ty:: GenericArg :: from ( goal. predicate . self_ty ( ) ) ] ,
438453 ) ) ;
439454
440- let mut nested_goals = ecx. infcx . eq (
441- goal. param_env ,
442- goal. predicate . term . ty ( ) . unwrap ( ) ,
455+ let is_sized_certainty = ecx. evaluate_goal ( goal. with ( tcx, sized_predicate) ) ?. 1 ;
456+ return ecx. eq_term_and_make_canonical_response (
457+ goal,
458+ is_sized_certainty,
443459 tcx. types . unit ,
444- ) ?;
445- nested_goals. push ( goal. with ( tcx, sized_predicate) ) ;
446-
447- return ecx. evaluate_all_and_make_canonical_response ( nested_goals) ;
460+ ) ;
448461 }
449462
450463 ty:: Adt ( def, substs) if def. is_struct ( ) => {
@@ -456,7 +469,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
456469 tcx,
457470 ty:: Binder :: dummy ( goal. predicate . with_self_ty ( tcx, self_ty) ) ,
458471 ) ;
459- return ecx. evaluate_all_and_make_canonical_response ( vec ! [ new_goal] ) ;
472+ let ( _, certainty) = ecx. evaluate_goal ( new_goal) ?;
473+ return ecx. make_canonical_response ( certainty) ;
460474 }
461475 }
462476 }
@@ -469,7 +483,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
469483 tcx,
470484 ty:: Binder :: dummy ( goal. predicate . with_self_ty ( tcx, self_ty) ) ,
471485 ) ;
472- return ecx. evaluate_all_and_make_canonical_response ( vec ! [ new_goal] ) ;
486+ let ( _, certainty) = ecx. evaluate_goal ( new_goal) ?;
487+ return ecx. make_canonical_response ( certainty) ;
473488 }
474489 } ,
475490
@@ -482,9 +497,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
482497 ) ,
483498 } ;
484499
485- let nested_goals =
486- ecx. infcx . eq ( goal. param_env , goal. predicate . term . ty ( ) . unwrap ( ) , metadata_ty) ?;
487- ecx. evaluate_all_and_make_canonical_response ( nested_goals)
500+ ecx. eq_term_and_make_canonical_response ( goal, Certainty :: Yes , metadata_ty)
488501 } )
489502 }
490503
0 commit comments