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
@@ -160,11 +162,11 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
160162 let ( ) =
161163 instantiate_canonical_state ( infcx, span, param_env, & mut orig_values, self . final_state ) ;
162164
163- if let Some ( term_hack) = self . goal . normalizes_to_term_hack {
165+ if let Some ( term_hack) = & self . goal . normalizes_to_term_hack {
164166 // FIXME: We ignore the expected term of `NormalizesTo` goals
165167 // when computing the result of its candidates. This is
166168 // scuffed.
167- let _ = term_hack. constrain ( infcx, span, param_env) ;
169+ let _ = term_hack. constrain_and ( infcx, span, param_env, |_| { } ) ;
168170 }
169171
170172 instantiated_goals
@@ -240,13 +242,39 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
240242 // building their proof tree, the expected term was unconstrained, but when
241243 // instantiating the candidate it is already constrained to the result of another
242244 // candidate.
243- let proof_tree = infcx
244- . probe ( |_| infcx. evaluate_root_goal_raw ( goal, GenerateProofTree :: Yes , None ) . 1 ) ;
245+ let normalizes_to_term_hack = NormalizesToTermHack { term, unconstrained_term } ;
246+ let ( proof_tree, nested_goals_result) = infcx. probe ( |_| {
247+ // Here, if we have any nested goals, then we make sure to apply them
248+ // considering the constrained RHS, and pass the resulting certainty to
249+ // `InspectGoal::new` so that the goal has the right result (and maintains
250+ // the impression that we don't do this normalizes-to infer hack at all).
251+ let ( nested, proof_tree) =
252+ infcx. evaluate_root_goal_raw ( goal, GenerateProofTree :: Yes , None ) ;
253+ let proof_tree = proof_tree. unwrap ( ) ;
254+ let nested_goals_result = nested. and_then ( |( nested, _) | {
255+ normalizes_to_term_hack. constrain_and (
256+ infcx,
257+ span,
258+ proof_tree. uncanonicalized_goal . param_env ,
259+ |ocx| {
260+ ocx. register_obligations ( nested. 0 . into_iter ( ) . map ( |( _, goal) | {
261+ Obligation :: new (
262+ infcx. tcx ,
263+ ObligationCause :: dummy_with_span ( span) ,
264+ goal. param_env ,
265+ goal. predicate ,
266+ )
267+ } ) ) ;
268+ } ,
269+ )
270+ } ) ;
271+ ( proof_tree, nested_goals_result)
272+ } ) ;
245273 InspectGoal :: new (
246274 infcx,
247275 self . goal . depth + 1 ,
248- proof_tree. unwrap ( ) ,
249- Some ( NormalizesToTermHack { term , unconstrained_term } ) ,
276+ proof_tree,
277+ Some ( ( normalizes_to_term_hack , nested_goals_result ) ) ,
250278 source,
251279 )
252280 }
@@ -393,20 +421,21 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
393421 infcx : & ' a InferCtxt < ' tcx > ,
394422 depth : usize ,
395423 root : inspect:: GoalEvaluation < TyCtxt < ' tcx > > ,
396- normalizes_to_term_hack : Option < NormalizesToTermHack < ' tcx > > ,
424+ term_hack_and_nested_certainty : Option < (
425+ NormalizesToTermHack < ' tcx > ,
426+ Result < Certainty , NoSolution > ,
427+ ) > ,
397428 source : GoalSource ,
398429 ) -> Self {
399430 let infcx = <& SolverDelegate < ' tcx > >:: from ( infcx) ;
400431
401432 let inspect:: GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root;
433+ // If there's a normalizes-to goal, AND the evaluation result with the result of
434+ // constraining the normalizes-to RHS and computing the nested goals.
402435 let result = evaluation. result . and_then ( |ok| {
403- if let Some ( term_hack) = normalizes_to_term_hack {
404- infcx
405- . probe ( |_| term_hack. constrain ( infcx, DUMMY_SP , uncanonicalized_goal. param_env ) )
406- . map ( |certainty| ok. value . certainty . and ( certainty) )
407- } else {
408- Ok ( ok. value . certainty )
409- }
436+ let nested_goals_certainty =
437+ term_hack_and_nested_certainty. map_or ( Ok ( Certainty :: Yes ) , |( _, c) | c) ?;
438+ Ok ( ok. value . certainty . and ( nested_goals_certainty) )
410439 } ) ;
411440
412441 InspectGoal {
@@ -416,7 +445,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
416445 goal : eager_resolve_vars ( infcx, uncanonicalized_goal) ,
417446 result,
418447 evaluation_kind : evaluation. kind ,
419- normalizes_to_term_hack,
448+ normalizes_to_term_hack : term_hack_and_nested_certainty . map ( | ( n , _ ) | n ) ,
420449 source,
421450 }
422451 }
0 commit comments