@@ -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,52 @@ 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+ /// The expected term of a `NormalizesTo` goal. It gets
45+ /// replaced with an unconstrained inference variable when
46+ /// computing `NormalizesTo` goals and we return the nested
47+ /// goals to the caller, who also equates the actual term
48+ /// with the expected.
49+ ///
50+ /// This is an implementation detail of the trait solver and
51+ /// not something we want to leak to users. We therefore
52+ /// treat `NormalizesTo` goals as if they apply the expected
53+ /// type at the end of each candidate.
54+ normalizes_to_term_hack : Option < NormalizesToTermHack < ' tcx > > ,
55+ }
56+
57+ #[ derive( Copy , Clone ) ]
58+ struct NormalizesToTermHack < ' tcx > {
59+ term : ty:: Term < ' tcx > ,
60+ unconstrained_term : ty:: Term < ' tcx > ,
61+ }
62+
63+ impl < ' tcx > NormalizesToTermHack < ' tcx > {
64+ fn relate (
65+ self ,
66+ infcx : & InferCtxt < ' tcx > ,
67+ span : Span ,
68+ param_env : ty:: ParamEnv < ' tcx > ,
69+ ) -> Result < Certainty , NoSolution > {
70+ infcx
71+ . at ( & ObligationCause :: dummy_with_span ( span) , param_env)
72+ . eq ( DefineOpaqueTypes :: Yes , self . term , self . unconstrained_term )
73+ . map_err ( |_| NoSolution )
74+ . and_then ( |InferOk { value : ( ) , obligations } | {
75+ let mut fulfill_cx = FulfillmentCtxt :: new ( infcx) ;
76+ fulfill_cx. register_predicate_obligations ( infcx, obligations) ;
77+ if fulfill_cx. select_where_possible ( infcx) . is_empty ( ) {
78+ if fulfill_cx. pending_obligations ( ) . is_empty ( ) {
79+ Ok ( Certainty :: Yes )
80+ } else {
81+ Ok ( Certainty :: AMBIGUOUS )
82+ }
83+ } else {
84+ Err ( NoSolution )
85+ }
86+ } )
87+ }
4188}
4289
4390pub struct InspectCandidate < ' a , ' tcx > {
@@ -115,42 +162,47 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
115162 self . final_state ,
116163 ) ;
117164
165+ if let Some ( term_hack) = self . goal . normalizes_to_term_hack {
166+ // FIXME: We ignore the expected term of `NormalizesTo` goals
167+ // when computing the result of its candidates. This is
168+ // scuffed.
169+ let _ = term_hack. relate ( infcx, span, param_env) ;
170+ }
171+
118172 instantiated_goals
119173 . 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 ( ) )
174+ . map ( |goal| match goal. predicate . kind ( ) . no_bound_vars ( ) {
175+ Some ( ty:: PredicateKind :: NormalizesTo ( ty:: NormalizesTo { alias, term } ) ) => {
176+ let unconstrained_term = match term. unpack ( ) {
177+ ty:: TermKind :: Ty ( _) => infcx
178+ . next_ty_var ( TypeVariableOrigin { param_def_id : None , span } )
179+ . into ( ) ,
180+ ty:: TermKind :: Const ( ct) => infcx
181+ . next_const_var (
182+ ct. ty ( ) ,
183+ ConstVariableOrigin { param_def_id : None , span } ,
184+ )
185+ . into ( ) ,
186+ } ;
187+ let goal =
188+ goal. with ( infcx. tcx , ty:: NormalizesTo { alias, term : unconstrained_term } ) ;
189+ let proof_tree = EvalCtxt :: enter_root ( infcx, GenerateProofTree :: Yes , |ecx| {
190+ ecx. evaluate_goal_raw ( GoalEvaluationKind :: Root , GoalSource :: Misc , goal)
191+ } )
192+ . 1 ;
193+ InspectGoal :: new (
194+ infcx,
195+ self . goal . depth + 1 ,
196+ proof_tree. unwrap ( ) ,
197+ Some ( NormalizesToTermHack { term, unconstrained_term } ) ,
198+ )
199+ }
200+ _ => InspectGoal :: new (
201+ infcx,
202+ self . goal . depth + 1 ,
203+ infcx. evaluate_root_goal ( goal, GenerateProofTree :: Yes ) . 1 . unwrap ( ) ,
204+ None ,
205+ ) ,
154206 } )
155207 . collect ( )
156208 }
@@ -172,7 +224,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
172224 }
173225
174226 pub fn result ( & self ) -> Result < Certainty , NoSolution > {
175- self . evaluation . result . map ( |c| c . value . certainty )
227+ self . result
176228 }
177229
178230 fn candidates_recur (
@@ -229,11 +281,11 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
229281
230282 pub fn candidates ( & ' a self ) -> Vec < InspectCandidate < ' a , ' tcx > > {
231283 let mut candidates = vec ! [ ] ;
232- let last_eval_step = match self . evaluation . kind {
284+ let last_eval_step = match self . evaluation_kind {
233285 inspect:: CanonicalGoalEvaluationKind :: Overflow
234286 | inspect:: CanonicalGoalEvaluationKind :: CycleInStack
235287 | inspect:: CanonicalGoalEvaluationKind :: ProvisionalCacheHit => {
236- warn ! ( "unexpected root evaluation: {:?}" , self . evaluation ) ;
288+ warn ! ( "unexpected root evaluation: {:?}" , self . evaluation_kind ) ;
237289 return vec ! [ ] ;
238290 }
239291 inspect:: CanonicalGoalEvaluationKind :: Evaluation { revisions } => {
@@ -262,17 +314,33 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
262314 candidates. pop ( ) . filter ( |_| candidates. is_empty ( ) )
263315 }
264316
265- fn new ( infcx : & ' a InferCtxt < ' tcx > , depth : usize , root : inspect:: GoalEvaluation < ' tcx > ) -> Self {
317+ fn new (
318+ infcx : & ' a InferCtxt < ' tcx > ,
319+ depth : usize ,
320+ root : inspect:: GoalEvaluation < ' tcx > ,
321+ normalizes_to_term_hack : Option < NormalizesToTermHack < ' tcx > > ,
322+ ) -> Self {
266323 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 ! ( ) ,
324+ let inspect:: GoalEvaluationKind :: Root { orig_values } = kind else { unreachable ! ( ) } ;
325+
326+ let result = evaluation. result . and_then ( |ok| {
327+ if let Some ( term_hack) = normalizes_to_term_hack {
328+ infcx
329+ . probe ( |_| term_hack. relate ( infcx, DUMMY_SP , uncanonicalized_goal. param_env ) )
330+ . map ( |certainty| ok. value . certainty . unify_with ( certainty) )
331+ } else {
332+ Ok ( ok. value . certainty )
333+ }
334+ } ) ;
335+
336+ InspectGoal {
337+ infcx,
338+ depth,
339+ orig_values,
340+ goal : uncanonicalized_goal. fold_with ( & mut EagerResolver :: new ( infcx) ) ,
341+ result,
342+ evaluation_kind : evaluation. kind ,
343+ normalizes_to_term_hack,
276344 }
277345 }
278346}
@@ -299,6 +367,6 @@ impl<'tcx> InferCtxt<'tcx> {
299367 ) -> V :: Result {
300368 let ( _, proof_tree) = self . evaluate_root_goal ( goal, GenerateProofTree :: Yes ) ;
301369 let proof_tree = proof_tree. unwrap ( ) ;
302- visitor. visit_goal ( & InspectGoal :: new ( self , 0 , proof_tree) )
370+ visitor. visit_goal ( & InspectGoal :: new ( self , 0 , proof_tree, None ) )
303371 }
304372}
0 commit comments