11
11
12
12
use std:: assert_matches:: assert_matches;
13
13
14
- use rustc_infer:: infer:: { DefineOpaqueTypes , InferCtxt , InferOk } ;
14
+ use rustc_infer:: infer:: InferCtxt ;
15
+ use rustc_infer:: traits:: Obligation ;
15
16
use rustc_macros:: extension;
16
17
use rustc_middle:: traits:: ObligationCause ;
17
18
use rustc_middle:: traits:: solve:: { Certainty , Goal , GoalSource , NoSolution , QueryResult } ;
@@ -20,7 +21,7 @@ use rustc_middle::{bug, ty};
20
21
use rustc_next_trait_solver:: resolve:: eager_resolve_vars;
21
22
use rustc_next_trait_solver:: solve:: inspect:: { self , instantiate_canonical_state} ;
22
23
use rustc_next_trait_solver:: solve:: { GenerateProofTree , MaybeCause , SolverDelegateEvalExt as _} ;
23
- use rustc_span:: { DUMMY_SP , Span } ;
24
+ use rustc_span:: Span ;
24
25
use tracing:: instrument;
25
26
26
27
use crate :: solve:: delegate:: SolverDelegate ;
@@ -60,28 +61,29 @@ impl<'tcx> NormalizesToTermHack<'tcx> {
60
61
/// Relate the `term` with the new `unconstrained_term` created
61
62
/// when computing the proof tree for this `NormalizesTo` goals.
62
63
/// This handles nested obligations.
63
- fn constrain (
64
- self ,
64
+ fn constrain_and (
65
+ & self ,
65
66
infcx : & InferCtxt < ' tcx > ,
66
67
span : Span ,
67
68
param_env : ty:: ParamEnv < ' tcx > ,
69
+ f : impl FnOnce ( & ObligationCtxt < ' _ , ' tcx > ) ,
68
70
) -> 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
+ }
85
87
}
86
88
}
87
89
@@ -180,11 +182,11 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
180
182
let ( ) =
181
183
instantiate_canonical_state ( infcx, span, param_env, & mut orig_values, self . final_state ) ;
182
184
183
- if let Some ( term_hack) = self . goal . normalizes_to_term_hack {
185
+ if let Some ( term_hack) = & self . goal . normalizes_to_term_hack {
184
186
// FIXME: We ignore the expected term of `NormalizesTo` goals
185
187
// when computing the result of its candidates. This is
186
188
// scuffed.
187
- let _ = term_hack. constrain ( infcx, span, param_env) ;
189
+ let _ = term_hack. constrain_and ( infcx, span, param_env, |_| { } ) ;
188
190
}
189
191
190
192
let opt_impl_args = opt_impl_args. map ( |impl_args| eager_resolve_vars ( infcx, impl_args) ) ;
@@ -218,13 +220,39 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
218
220
// building their proof tree, the expected term was unconstrained, but when
219
221
// instantiating the candidate it is already constrained to the result of another
220
222
// candidate.
221
- let proof_tree = infcx
222
- . probe ( |_| infcx. evaluate_root_goal_raw ( goal, GenerateProofTree :: Yes , None ) . 1 ) ;
223
+ let normalizes_to_term_hack = NormalizesToTermHack { term, unconstrained_term } ;
224
+ let ( proof_tree, nested_goals_result) = infcx. probe ( |_| {
225
+ // Here, if we have any nested goals, then we make sure to apply them
226
+ // considering the constrained RHS, and pass the resulting certainty to
227
+ // `InspectGoal::new` so that the goal has the right result (and maintains
228
+ // the impression that we don't do this normalizes-to infer hack at all).
229
+ let ( nested, proof_tree) =
230
+ infcx. evaluate_root_goal_raw ( goal, GenerateProofTree :: Yes , None ) ;
231
+ let proof_tree = proof_tree. unwrap ( ) ;
232
+ let nested_goals_result = nested. and_then ( |( nested, _) | {
233
+ normalizes_to_term_hack. constrain_and (
234
+ infcx,
235
+ span,
236
+ proof_tree. uncanonicalized_goal . param_env ,
237
+ |ocx| {
238
+ ocx. register_obligations ( nested. 0 . into_iter ( ) . map ( |( _, goal) | {
239
+ Obligation :: new (
240
+ infcx. tcx ,
241
+ ObligationCause :: dummy_with_span ( span) ,
242
+ goal. param_env ,
243
+ goal. predicate ,
244
+ )
245
+ } ) ) ;
246
+ } ,
247
+ )
248
+ } ) ;
249
+ ( proof_tree, nested_goals_result)
250
+ } ) ;
223
251
InspectGoal :: new (
224
252
infcx,
225
253
self . goal . depth + 1 ,
226
- proof_tree. unwrap ( ) ,
227
- Some ( NormalizesToTermHack { term , unconstrained_term } ) ,
254
+ proof_tree,
255
+ Some ( ( normalizes_to_term_hack , nested_goals_result ) ) ,
228
256
source,
229
257
)
230
258
}
@@ -371,20 +399,21 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
371
399
infcx : & ' a InferCtxt < ' tcx > ,
372
400
depth : usize ,
373
401
root : inspect:: GoalEvaluation < TyCtxt < ' tcx > > ,
374
- normalizes_to_term_hack : Option < NormalizesToTermHack < ' tcx > > ,
402
+ term_hack_and_nested_certainty : Option < (
403
+ NormalizesToTermHack < ' tcx > ,
404
+ Result < Certainty , NoSolution > ,
405
+ ) > ,
375
406
source : GoalSource ,
376
407
) -> Self {
377
408
let infcx = <& SolverDelegate < ' tcx > >:: from ( infcx) ;
378
409
379
410
let inspect:: GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root;
411
+ // If there's a normalizes-to goal, AND the evaluation result with the result of
412
+ // constraining the normalizes-to RHS and computing the nested goals.
380
413
let result = evaluation. result . and_then ( |ok| {
381
- if let Some ( term_hack) = normalizes_to_term_hack {
382
- infcx
383
- . probe ( |_| term_hack. constrain ( infcx, DUMMY_SP , uncanonicalized_goal. param_env ) )
384
- . map ( |certainty| ok. value . certainty . and ( certainty) )
385
- } else {
386
- Ok ( ok. value . certainty )
387
- }
414
+ let nested_goals_certainty =
415
+ term_hack_and_nested_certainty. map_or ( Ok ( Certainty :: Yes ) , |( _, c) | c) ?;
416
+ Ok ( ok. value . certainty . and ( nested_goals_certainty) )
388
417
} ) ;
389
418
390
419
InspectGoal {
@@ -394,7 +423,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
394
423
goal : eager_resolve_vars ( infcx, uncanonicalized_goal) ,
395
424
result,
396
425
evaluation_kind : evaluation. kind ,
397
- normalizes_to_term_hack,
426
+ normalizes_to_term_hack : term_hack_and_nested_certainty . map ( | ( n , _ ) | n ) ,
398
427
source,
399
428
}
400
429
}
0 commit comments