@@ -14,6 +14,7 @@ use rustc_ast_ir::visit::VisitorResult;
14
14
use rustc_infer:: infer:: resolve:: EagerResolver ;
15
15
use rustc_infer:: infer:: type_variable:: TypeVariableOrigin ;
16
16
use rustc_infer:: infer:: { DefineOpaqueTypes , InferCtxt , InferOk } ;
17
+ use rustc_infer:: traits:: { TraitEngine , TraitEngineExt } ;
17
18
use rustc_macros:: extension;
18
19
use rustc_middle:: infer:: unify_key:: ConstVariableOrigin ;
19
20
use rustc_middle:: traits:: query:: NoSolution ;
@@ -22,9 +23,10 @@ use rustc_middle::traits::solve::{Certainty, Goal};
22
23
use rustc_middle:: traits:: ObligationCause ;
23
24
use rustc_middle:: ty;
24
25
use rustc_middle:: ty:: TypeFoldable ;
25
- use rustc_span:: Span ;
26
+ use rustc_span:: { Span , DUMMY_SP } ;
26
27
27
28
use crate :: solve:: eval_ctxt:: canonical;
29
+ use crate :: solve:: FulfillmentCtxt ;
28
30
use crate :: solve:: { EvalCtxt , GoalEvaluationKind , GoalSource } ;
29
31
use crate :: solve:: { GenerateProofTree , InferCtxtEvalExt } ;
30
32
@@ -37,7 +39,52 @@ pub struct InspectGoal<'a, 'tcx> {
37
39
depth : usize ,
38
40
orig_values : Vec < ty:: GenericArg < ' tcx > > ,
39
41
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
+ }
41
88
}
42
89
43
90
pub struct InspectCandidate < ' a , ' tcx > {
@@ -115,42 +162,47 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
115
162
self . final_state ,
116
163
) ;
117
164
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
+
118
172
instantiated_goals
119
173
. 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
+ ) ,
154
206
} )
155
207
. collect ( )
156
208
}
@@ -172,7 +224,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
172
224
}
173
225
174
226
pub fn result ( & self ) -> Result < Certainty , NoSolution > {
175
- self . evaluation . result . map ( |c| c . value . certainty )
227
+ self . result
176
228
}
177
229
178
230
fn candidates_recur (
@@ -229,11 +281,11 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
229
281
230
282
pub fn candidates ( & ' a self ) -> Vec < InspectCandidate < ' a , ' tcx > > {
231
283
let mut candidates = vec ! [ ] ;
232
- let last_eval_step = match self . evaluation . kind {
284
+ let last_eval_step = match self . evaluation_kind {
233
285
inspect:: CanonicalGoalEvaluationKind :: Overflow
234
286
| inspect:: CanonicalGoalEvaluationKind :: CycleInStack
235
287
| inspect:: CanonicalGoalEvaluationKind :: ProvisionalCacheHit => {
236
- warn ! ( "unexpected root evaluation: {:?}" , self . evaluation ) ;
288
+ warn ! ( "unexpected root evaluation: {:?}" , self . evaluation_kind ) ;
237
289
return vec ! [ ] ;
238
290
}
239
291
inspect:: CanonicalGoalEvaluationKind :: Evaluation { revisions } => {
@@ -262,17 +314,33 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
262
314
candidates. pop ( ) . filter ( |_| candidates. is_empty ( ) )
263
315
}
264
316
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 {
266
323
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,
276
344
}
277
345
}
278
346
}
@@ -299,6 +367,6 @@ impl<'tcx> InferCtxt<'tcx> {
299
367
) -> V :: Result {
300
368
let ( _, proof_tree) = self . evaluate_root_goal ( goal, GenerateProofTree :: Yes ) ;
301
369
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 ) )
303
371
}
304
372
}
0 commit comments