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