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
@@ -160,11 +162,11 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
160
162
let ( ) =
161
163
instantiate_canonical_state ( infcx, span, param_env, & mut orig_values, self . final_state ) ;
162
164
163
- if let Some ( term_hack) = self . goal . normalizes_to_term_hack {
165
+ if let Some ( term_hack) = & self . goal . normalizes_to_term_hack {
164
166
// FIXME: We ignore the expected term of `NormalizesTo` goals
165
167
// when computing the result of its candidates. This is
166
168
// scuffed.
167
- let _ = term_hack. constrain ( infcx, span, param_env) ;
169
+ let _ = term_hack. constrain_and ( infcx, span, param_env, |_| { } ) ;
168
170
}
169
171
170
172
instantiated_goals
@@ -240,13 +242,39 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
240
242
// building their proof tree, the expected term was unconstrained, but when
241
243
// instantiating the candidate it is already constrained to the result of another
242
244
// candidate.
243
- let proof_tree = infcx
244
- . probe ( |_| infcx. evaluate_root_goal_raw ( goal, GenerateProofTree :: Yes , None ) . 1 ) ;
245
+ let normalizes_to_term_hack = NormalizesToTermHack { term, unconstrained_term } ;
246
+ let ( proof_tree, nested_goals_result) = infcx. probe ( |_| {
247
+ // Here, if we have any nested goals, then we make sure to apply them
248
+ // considering the constrained RHS, and pass the resulting certainty to
249
+ // `InspectGoal::new` so that the goal has the right result (and maintains
250
+ // the impression that we don't do this normalizes-to infer hack at all).
251
+ let ( nested, proof_tree) =
252
+ infcx. evaluate_root_goal_raw ( goal, GenerateProofTree :: Yes , None ) ;
253
+ let proof_tree = proof_tree. unwrap ( ) ;
254
+ let nested_goals_result = nested. and_then ( |( nested, _) | {
255
+ normalizes_to_term_hack. constrain_and (
256
+ infcx,
257
+ span,
258
+ proof_tree. uncanonicalized_goal . param_env ,
259
+ |ocx| {
260
+ ocx. register_obligations ( nested. 0 . into_iter ( ) . map ( |( _, goal) | {
261
+ Obligation :: new (
262
+ infcx. tcx ,
263
+ ObligationCause :: dummy_with_span ( span) ,
264
+ goal. param_env ,
265
+ goal. predicate ,
266
+ )
267
+ } ) ) ;
268
+ } ,
269
+ )
270
+ } ) ;
271
+ ( proof_tree, nested_goals_result)
272
+ } ) ;
245
273
InspectGoal :: new (
246
274
infcx,
247
275
self . goal . depth + 1 ,
248
- proof_tree. unwrap ( ) ,
249
- Some ( NormalizesToTermHack { term , unconstrained_term } ) ,
276
+ proof_tree,
277
+ Some ( ( normalizes_to_term_hack , nested_goals_result ) ) ,
250
278
source,
251
279
)
252
280
}
@@ -393,20 +421,21 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
393
421
infcx : & ' a InferCtxt < ' tcx > ,
394
422
depth : usize ,
395
423
root : inspect:: GoalEvaluation < TyCtxt < ' tcx > > ,
396
- normalizes_to_term_hack : Option < NormalizesToTermHack < ' tcx > > ,
424
+ term_hack_and_nested_certainty : Option < (
425
+ NormalizesToTermHack < ' tcx > ,
426
+ Result < Certainty , NoSolution > ,
427
+ ) > ,
397
428
source : GoalSource ,
398
429
) -> Self {
399
430
let infcx = <& SolverDelegate < ' tcx > >:: from ( infcx) ;
400
431
401
432
let inspect:: GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root;
433
+ // If there's a normalizes-to goal, AND the evaluation result with the result of
434
+ // constraining the normalizes-to RHS and computing the nested goals.
402
435
let result = evaluation. result . and_then ( |ok| {
403
- if let Some ( term_hack) = normalizes_to_term_hack {
404
- infcx
405
- . probe ( |_| term_hack. constrain ( infcx, DUMMY_SP , uncanonicalized_goal. param_env ) )
406
- . map ( |certainty| ok. value . certainty . and ( certainty) )
407
- } else {
408
- Ok ( ok. value . certainty )
409
- }
436
+ let nested_goals_certainty =
437
+ term_hack_and_nested_certainty. map_or ( Ok ( Certainty :: Yes ) , |( _, c) | c) ?;
438
+ Ok ( ok. value . certainty . and ( nested_goals_certainty) )
410
439
} ) ;
411
440
412
441
InspectGoal {
@@ -416,7 +445,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
416
445
goal : eager_resolve_vars ( infcx, uncanonicalized_goal) ,
417
446
result,
418
447
evaluation_kind : evaluation. kind ,
419
- normalizes_to_term_hack,
448
+ normalizes_to_term_hack : term_hack_and_nested_certainty . map ( | ( n , _ ) | n ) ,
420
449
source,
421
450
}
422
451
}
0 commit comments