1111
1212use  std:: assert_matches:: assert_matches; 
1313
14- use  rustc_infer:: infer:: { DefineOpaqueTypes ,  InferCtxt ,  InferOk } ; 
14+ use  rustc_infer:: infer:: InferCtxt ; 
15+ use  rustc_infer:: traits:: Obligation ; 
1516use  rustc_macros:: extension; 
1617use  rustc_middle:: traits:: ObligationCause ; 
1718use  rustc_middle:: traits:: solve:: { Certainty ,  Goal ,  GoalSource ,  NoSolution ,  QueryResult } ; 
@@ -20,7 +21,7 @@ use rustc_middle::{bug, ty};
2021use  rustc_next_trait_solver:: resolve:: eager_resolve_vars; 
2122use  rustc_next_trait_solver:: solve:: inspect:: { self ,  instantiate_canonical_state} ; 
2223use  rustc_next_trait_solver:: solve:: { GenerateProofTree ,  MaybeCause ,  SolverDelegateEvalExt  as  _} ; 
23- use  rustc_span:: { DUMMY_SP ,   Span } ; 
24+ use  rustc_span:: Span ; 
2425use  tracing:: instrument; 
2526
2627use  crate :: solve:: delegate:: SolverDelegate ; 
@@ -60,28 +61,29 @@ impl<'tcx> NormalizesToTermHack<'tcx> {
6061    /// Relate the `term` with the new `unconstrained_term` created 
6162     /// when computing the proof tree for this `NormalizesTo` goals. 
6263     /// This handles nested obligations. 
63-      fn  constrain ( 
64-         self , 
64+      fn  constrain_and ( 
65+         & self , 
6566        infcx :  & InferCtxt < ' tcx > , 
6667        span :  Span , 
6768        param_env :  ty:: ParamEnv < ' tcx > , 
69+         f :  impl  FnOnce ( & ObligationCtxt < ' _ ,  ' tcx > ) , 
6870    )  -> Result < Certainty ,  NoSolution >  { 
69-         infcx
70-              . at ( & ObligationCause :: dummy_with_span ( span ) ,  param_env ) 
71-             . eq ( DefineOpaqueTypes :: Yes ,   self . term ,   self . unconstrained_term ) 
72-             . map_err ( |_|  NoSolution ) 
73-             . and_then ( | InferOk   {   value :   ( ) ,  obligations  } |  { 
74-                  let  ocx =  ObligationCtxt :: new ( infcx ) ; 
75-                 ocx . register_obligations ( obligations ) ; 
76-                  let  errors = ocx . select_all_or_error ( ) ; 
77-                  if  errors . is_empty ( )   { 
78-                      Ok ( Certainty :: Yes ) 
79-                  }   else   if  errors . iter ( ) . all ( |e| !e . is_true_error ( ) )   { 
80-                      Ok ( Certainty :: AMBIGUOUS ) 
81-                  }   else   { 
82-                      Err ( NoSolution ) 
83-                  } 
84-              } ) 
71+         let  ocx =  ObligationCtxt :: new ( infcx) ; 
72+         ocx . eq ( 
73+             & ObligationCause :: dummy_with_span ( span ) , 
74+             param_env , 
75+             self . term , 
76+             self . unconstrained_term , 
77+         ) ? ; 
78+         f ( & ocx ) ; 
79+         let  errors = ocx . select_all_or_error ( ) ; 
80+         if  errors . is_empty ( )   { 
81+             Ok ( Certainty :: Yes ) 
82+         }   else   if  errors . iter ( ) . all ( |e| !e . is_true_error ( ) )   { 
83+             Ok ( Certainty :: AMBIGUOUS ) 
84+         }   else   { 
85+             Err ( NoSolution ) 
86+         } 
8587    } 
8688} 
8789
@@ -180,11 +182,11 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
180182        let  ( )  =
181183            instantiate_canonical_state ( infcx,  span,  param_env,  & mut  orig_values,  self . final_state ) ; 
182184
183-         if  let  Some ( term_hack)  = self . goal . normalizes_to_term_hack  { 
185+         if  let  Some ( term_hack)  = & self . goal . normalizes_to_term_hack  { 
184186            // FIXME: We ignore the expected term of `NormalizesTo` goals 
185187            // when computing the result of its candidates. This is 
186188            // scuffed. 
187-             let  _ = term_hack. constrain ( infcx,  span,  param_env) ; 
189+             let  _ = term_hack. constrain_and ( infcx,  span,  param_env,  |_|  { } ) ; 
188190        } 
189191
190192        let  opt_impl_args = opt_impl_args. map ( |impl_args| eager_resolve_vars ( infcx,  impl_args) ) ; 
@@ -218,13 +220,39 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
218220                // building their proof tree, the expected term was unconstrained, but when 
219221                // instantiating the candidate it is already constrained to the result of another 
220222                // candidate. 
221-                 let  proof_tree = infcx
222-                     . probe ( |_| infcx. evaluate_root_goal_raw ( goal,  GenerateProofTree :: Yes ,  None ) . 1 ) ; 
223+                 let  normalizes_to_term_hack = NormalizesToTermHack  {  term,  unconstrained_term } ; 
224+                 let  ( proof_tree,  nested_goals_result)  = infcx. probe ( |_| { 
225+                     // Here, if we have any nested goals, then we make sure to apply them 
226+                     // considering the constrained RHS, and pass the resulting certainty to 
227+                     // `InspectGoal::new` so that the goal has the right result (and maintains 
228+                     // the impression that we don't do this normalizes-to infer hack at all). 
229+                     let  ( nested,  proof_tree)  =
230+                         infcx. evaluate_root_goal_raw ( goal,  GenerateProofTree :: Yes ,  None ) ; 
231+                     let  proof_tree = proof_tree. unwrap ( ) ; 
232+                     let  nested_goals_result = nested. and_then ( |( nested,  _) | { 
233+                         normalizes_to_term_hack. constrain_and ( 
234+                             infcx, 
235+                             span, 
236+                             proof_tree. uncanonicalized_goal . param_env , 
237+                             |ocx| { 
238+                                 ocx. register_obligations ( nested. 0 . into_iter ( ) . map ( |( _,  goal) | { 
239+                                     Obligation :: new ( 
240+                                         infcx. tcx , 
241+                                         ObligationCause :: dummy_with_span ( span) , 
242+                                         goal. param_env , 
243+                                         goal. predicate , 
244+                                     ) 
245+                                 } ) ) ; 
246+                             } , 
247+                         ) 
248+                     } ) ; 
249+                     ( proof_tree,  nested_goals_result) 
250+                 } ) ; 
223251                InspectGoal :: new ( 
224252                    infcx, 
225253                    self . goal . depth  + 1 , 
226-                     proof_tree. unwrap ( ) , 
227-                     Some ( NormalizesToTermHack   {  term ,  unconstrained_term  } ) , 
254+                     proof_tree, 
255+                     Some ( ( normalizes_to_term_hack ,  nested_goals_result ) ) , 
228256                    source, 
229257                ) 
230258            } 
@@ -371,20 +399,21 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
371399        infcx :  & ' a  InferCtxt < ' tcx > , 
372400        depth :  usize , 
373401        root :  inspect:: GoalEvaluation < TyCtxt < ' tcx > > , 
374-         normalizes_to_term_hack :  Option < NormalizesToTermHack < ' tcx > > , 
402+         term_hack_and_nested_certainty :  Option < ( 
403+             NormalizesToTermHack < ' tcx > , 
404+             Result < Certainty ,  NoSolution > , 
405+         ) > , 
375406        source :  GoalSource , 
376407    )  -> Self  { 
377408        let  infcx = <& SolverDelegate < ' tcx > >:: from ( infcx) ; 
378409
379410        let  inspect:: GoalEvaluation  {  uncanonicalized_goal,  orig_values,  evaluation }  = root; 
411+         // If there's a normalizes-to goal, AND the evaluation result with the result of 
412+         // constraining the normalizes-to RHS and computing the nested goals. 
380413        let  result = evaluation. result . and_then ( |ok| { 
381-             if  let  Some ( term_hack)  = normalizes_to_term_hack { 
382-                 infcx
383-                     . probe ( |_| term_hack. constrain ( infcx,  DUMMY_SP ,  uncanonicalized_goal. param_env ) ) 
384-                     . map ( |certainty| ok. value . certainty . and ( certainty) ) 
385-             }  else  { 
386-                 Ok ( ok. value . certainty ) 
387-             } 
414+             let  nested_goals_certainty =
415+                 term_hack_and_nested_certainty. map_or ( Ok ( Certainty :: Yes ) ,  |( _,  c) | c) ?; 
416+             Ok ( ok. value . certainty . and ( nested_goals_certainty) ) 
388417        } ) ; 
389418
390419        InspectGoal  { 
@@ -394,7 +423,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
394423            goal :  eager_resolve_vars ( infcx,  uncanonicalized_goal) , 
395424            result, 
396425            evaluation_kind :  evaluation. kind , 
397-             normalizes_to_term_hack, 
426+             normalizes_to_term_hack :  term_hack_and_nested_certainty . map ( | ( n ,  _ ) | n ) , 
398427            source, 
399428        } 
400429    } 
0 commit comments