@@ -14,6 +14,7 @@ use rustc_ast_ir::visit::VisitorResult;
1414use rustc_infer:: infer:: resolve:: EagerResolver ;
1515use rustc_infer:: infer:: type_variable:: TypeVariableOrigin ;
1616use rustc_infer:: infer:: { DefineOpaqueTypes , InferCtxt , InferOk } ;
17+ use rustc_infer:: traits:: { TraitEngine , TraitEngineExt } ;
1718use rustc_macros:: extension;
1819use rustc_middle:: infer:: unify_key:: ConstVariableOrigin ;
1920use rustc_middle:: traits:: query:: NoSolution ;
@@ -22,9 +23,10 @@ use rustc_middle::traits::solve::{Certainty, Goal};
2223use rustc_middle:: traits:: ObligationCause ;
2324use rustc_middle:: ty;
2425use rustc_middle:: ty:: TypeFoldable ;
25- use rustc_span:: Span ;
26+ use rustc_span:: { Span , DUMMY_SP } ;
2627
2728use crate :: solve:: eval_ctxt:: canonical;
29+ use crate :: solve:: FulfillmentCtxt ;
2830use crate :: solve:: { EvalCtxt , GoalEvaluationKind , GoalSource } ;
2931use crate :: solve:: { GenerateProofTree , InferCtxtEvalExt } ;
3032
@@ -37,7 +39,54 @@ pub struct InspectGoal<'a, 'tcx> {
3739 depth : usize ,
3840 orig_values : Vec < ty:: GenericArg < ' tcx > > ,
3941 goal : Goal < ' tcx , ty:: Predicate < ' tcx > > ,
40- evaluation : inspect:: CanonicalGoalEvaluation < ' tcx > ,
42+ result : Result < Certainty , NoSolution > ,
43+ evaluation_kind : inspect:: CanonicalGoalEvaluationKind < ' tcx > ,
44+ normalizes_to_term_hack : Option < NormalizesToTermHack < ' tcx > > ,
45+ }
46+
47+ /// The expected term of a `NormalizesTo` goal gets replaced
48+ /// with an unconstrained inference variable when computing
49+ /// `NormalizesTo` goals and we return the nested goals to the
50+ /// caller, who also equates the actual term with the expected.
51+ ///
52+ /// This is an implementation detail of the trait solver and
53+ /// not something we want to leak to users. We therefore
54+ /// treat `NormalizesTo` goals as if they apply the expected
55+ /// type at the end of each candidate.
56+ #[ derive( Copy , Clone ) ]
57+ struct NormalizesToTermHack < ' tcx > {
58+ term : ty:: Term < ' tcx > ,
59+ unconstrained_term : ty:: Term < ' tcx > ,
60+ }
61+
62+ impl < ' tcx > NormalizesToTermHack < ' tcx > {
63+ /// Relate the `term` with the new `unconstrained_term` created
64+ /// when computing the proof tree for this `NormalizesTo` goals.
65+ /// This handles nested obligations.
66+ fn constrain (
67+ self ,
68+ infcx : & InferCtxt < ' tcx > ,
69+ span : Span ,
70+ param_env : ty:: ParamEnv < ' tcx > ,
71+ ) -> Result < Certainty , NoSolution > {
72+ infcx
73+ . at ( & ObligationCause :: dummy_with_span ( span) , param_env)
74+ . eq ( DefineOpaqueTypes :: Yes , self . term , self . unconstrained_term )
75+ . map_err ( |_| NoSolution )
76+ . and_then ( |InferOk { value : ( ) , obligations } | {
77+ let mut fulfill_cx = FulfillmentCtxt :: new ( infcx) ;
78+ fulfill_cx. register_predicate_obligations ( infcx, obligations) ;
79+ if fulfill_cx. select_where_possible ( infcx) . is_empty ( ) {
80+ if fulfill_cx. pending_obligations ( ) . is_empty ( ) {
81+ Ok ( Certainty :: Yes )
82+ } else {
83+ Ok ( Certainty :: AMBIGUOUS )
84+ }
85+ } else {
86+ Err ( NoSolution )
87+ }
88+ } )
89+ }
4190}
4291
4392pub struct InspectCandidate < ' a , ' tcx > {
@@ -115,42 +164,47 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
115164 self . final_state ,
116165 ) ;
117166
167+ if let Some ( term_hack) = self . goal . normalizes_to_term_hack {
168+ // FIXME: We ignore the expected term of `NormalizesTo` goals
169+ // when computing the result of its candidates. This is
170+ // scuffed.
171+ let _ = term_hack. constrain ( infcx, span, param_env) ;
172+ }
173+
118174 instantiated_goals
119175 . into_iter ( )
120- . map ( |goal| {
121- let proof_tree = match goal. predicate . kind ( ) . no_bound_vars ( ) {
122- Some ( ty:: PredicateKind :: NormalizesTo ( ty:: NormalizesTo { alias, term } ) ) => {
123- let unconstrained_term = match term. unpack ( ) {
124- ty:: TermKind :: Ty ( _) => infcx
125- . next_ty_var ( TypeVariableOrigin { param_def_id : None , span } )
126- . into ( ) ,
127- ty:: TermKind :: Const ( ct) => infcx
128- . next_const_var (
129- ct. ty ( ) ,
130- ConstVariableOrigin { param_def_id : None , span } ,
131- )
132- . into ( ) ,
133- } ;
134- let goal = goal
135- . with ( infcx. tcx , ty:: NormalizesTo { alias, term : unconstrained_term } ) ;
136- let proof_tree =
137- EvalCtxt :: enter_root ( infcx, GenerateProofTree :: Yes , |ecx| {
138- ecx. evaluate_goal_raw (
139- GoalEvaluationKind :: Root ,
140- GoalSource :: Misc ,
141- goal,
142- )
143- } )
144- . 1 ;
145- let InferOk { value : ( ) , obligations : _ } = infcx
146- . at ( & ObligationCause :: dummy_with_span ( span) , param_env)
147- . eq ( DefineOpaqueTypes :: Yes , term, unconstrained_term)
148- . unwrap ( ) ;
149- proof_tree
150- }
151- _ => infcx. evaluate_root_goal ( goal, GenerateProofTree :: Yes ) . 1 ,
152- } ;
153- InspectGoal :: new ( infcx, self . goal . depth + 1 , proof_tree. unwrap ( ) )
176+ . map ( |goal| match goal. predicate . kind ( ) . no_bound_vars ( ) {
177+ Some ( ty:: PredicateKind :: NormalizesTo ( ty:: NormalizesTo { alias, term } ) ) => {
178+ let unconstrained_term = match term. unpack ( ) {
179+ ty:: TermKind :: Ty ( _) => infcx
180+ . next_ty_var ( TypeVariableOrigin { param_def_id : None , span } )
181+ . into ( ) ,
182+ ty:: TermKind :: Const ( ct) => infcx
183+ . next_const_var (
184+ ct. ty ( ) ,
185+ ConstVariableOrigin { param_def_id : None , span } ,
186+ )
187+ . into ( ) ,
188+ } ;
189+ let goal =
190+ goal. with ( infcx. tcx , ty:: NormalizesTo { alias, term : unconstrained_term } ) ;
191+ let proof_tree = EvalCtxt :: enter_root ( infcx, GenerateProofTree :: Yes , |ecx| {
192+ ecx. evaluate_goal_raw ( GoalEvaluationKind :: Root , GoalSource :: Misc , goal)
193+ } )
194+ . 1 ;
195+ InspectGoal :: new (
196+ infcx,
197+ self . goal . depth + 1 ,
198+ proof_tree. unwrap ( ) ,
199+ Some ( NormalizesToTermHack { term, unconstrained_term } ) ,
200+ )
201+ }
202+ _ => InspectGoal :: new (
203+ infcx,
204+ self . goal . depth + 1 ,
205+ infcx. evaluate_root_goal ( goal, GenerateProofTree :: Yes ) . 1 . unwrap ( ) ,
206+ None ,
207+ ) ,
154208 } )
155209 . collect ( )
156210 }
@@ -172,7 +226,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
172226 }
173227
174228 pub fn result ( & self ) -> Result < Certainty , NoSolution > {
175- self . evaluation . result . map ( |c| c . value . certainty )
229+ self . result
176230 }
177231
178232 fn candidates_recur (
@@ -229,11 +283,11 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
229283
230284 pub fn candidates ( & ' a self ) -> Vec < InspectCandidate < ' a , ' tcx > > {
231285 let mut candidates = vec ! [ ] ;
232- let last_eval_step = match self . evaluation . kind {
286+ let last_eval_step = match self . evaluation_kind {
233287 inspect:: CanonicalGoalEvaluationKind :: Overflow
234288 | inspect:: CanonicalGoalEvaluationKind :: CycleInStack
235289 | inspect:: CanonicalGoalEvaluationKind :: ProvisionalCacheHit => {
236- warn ! ( "unexpected root evaluation: {:?}" , self . evaluation ) ;
290+ warn ! ( "unexpected root evaluation: {:?}" , self . evaluation_kind ) ;
237291 return vec ! [ ] ;
238292 }
239293 inspect:: CanonicalGoalEvaluationKind :: Evaluation { revisions } => {
@@ -262,17 +316,33 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
262316 candidates. pop ( ) . filter ( |_| candidates. is_empty ( ) )
263317 }
264318
265- fn new ( infcx : & ' a InferCtxt < ' tcx > , depth : usize , root : inspect:: GoalEvaluation < ' tcx > ) -> Self {
319+ fn new (
320+ infcx : & ' a InferCtxt < ' tcx > ,
321+ depth : usize ,
322+ root : inspect:: GoalEvaluation < ' tcx > ,
323+ normalizes_to_term_hack : Option < NormalizesToTermHack < ' tcx > > ,
324+ ) -> Self {
266325 let inspect:: GoalEvaluation { uncanonicalized_goal, kind, evaluation } = root;
267- match kind {
268- inspect:: GoalEvaluationKind :: Root { orig_values } => InspectGoal {
269- infcx,
270- depth,
271- orig_values,
272- goal : uncanonicalized_goal. fold_with ( & mut EagerResolver :: new ( infcx) ) ,
273- evaluation,
274- } ,
275- inspect:: GoalEvaluationKind :: Nested { .. } => unreachable ! ( ) ,
326+ let inspect:: GoalEvaluationKind :: Root { orig_values } = kind else { unreachable ! ( ) } ;
327+
328+ let result = evaluation. result . and_then ( |ok| {
329+ if let Some ( term_hack) = normalizes_to_term_hack {
330+ infcx
331+ . probe ( |_| term_hack. constrain ( infcx, DUMMY_SP , uncanonicalized_goal. param_env ) )
332+ . map ( |certainty| ok. value . certainty . unify_with ( certainty) )
333+ } else {
334+ Ok ( ok. value . certainty )
335+ }
336+ } ) ;
337+
338+ InspectGoal {
339+ infcx,
340+ depth,
341+ orig_values,
342+ goal : uncanonicalized_goal. fold_with ( & mut EagerResolver :: new ( infcx) ) ,
343+ result,
344+ evaluation_kind : evaluation. kind ,
345+ normalizes_to_term_hack,
276346 }
277347 }
278348}
@@ -299,6 +369,6 @@ impl<'tcx> InferCtxt<'tcx> {
299369 ) -> V :: Result {
300370 let ( _, proof_tree) = self . evaluate_root_goal ( goal, GenerateProofTree :: Yes ) ;
301371 let proof_tree = proof_tree. unwrap ( ) ;
302- visitor. visit_goal ( & InspectGoal :: new ( self , 0 , proof_tree) )
372+ visitor. visit_goal ( & InspectGoal :: new ( self , 0 , proof_tree, None ) )
303373 }
304374}
0 commit comments