@@ -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,54 @@ 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
+ 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
+ }
41
90
}
42
91
43
92
pub struct InspectCandidate < ' a , ' tcx > {
@@ -115,42 +164,47 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
115
164
self . final_state ,
116
165
) ;
117
166
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
+
118
174
instantiated_goals
119
175
. 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
+ ) ,
154
208
} )
155
209
. collect ( )
156
210
}
@@ -172,7 +226,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
172
226
}
173
227
174
228
pub fn result ( & self ) -> Result < Certainty , NoSolution > {
175
- self . evaluation . result . map ( |c| c . value . certainty )
229
+ self . result
176
230
}
177
231
178
232
fn candidates_recur (
@@ -229,11 +283,11 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
229
283
230
284
pub fn candidates ( & ' a self ) -> Vec < InspectCandidate < ' a , ' tcx > > {
231
285
let mut candidates = vec ! [ ] ;
232
- let last_eval_step = match self . evaluation . kind {
286
+ let last_eval_step = match self . evaluation_kind {
233
287
inspect:: CanonicalGoalEvaluationKind :: Overflow
234
288
| inspect:: CanonicalGoalEvaluationKind :: CycleInStack
235
289
| inspect:: CanonicalGoalEvaluationKind :: ProvisionalCacheHit => {
236
- warn ! ( "unexpected root evaluation: {:?}" , self . evaluation ) ;
290
+ warn ! ( "unexpected root evaluation: {:?}" , self . evaluation_kind ) ;
237
291
return vec ! [ ] ;
238
292
}
239
293
inspect:: CanonicalGoalEvaluationKind :: Evaluation { revisions } => {
@@ -262,17 +316,33 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
262
316
candidates. pop ( ) . filter ( |_| candidates. is_empty ( ) )
263
317
}
264
318
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 {
266
325
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,
276
346
}
277
347
}
278
348
}
@@ -299,6 +369,6 @@ impl<'tcx> InferCtxt<'tcx> {
299
369
) -> V :: Result {
300
370
let ( _, proof_tree) = self . evaluate_root_goal ( goal, GenerateProofTree :: Yes ) ;
301
371
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 ) )
303
373
}
304
374
}
0 commit comments