Skip to content

Commit 19be2d3

Browse files
Apply nested goals certainty to InspectGoals for normalizes-to
1 parent c360e21 commit 19be2d3

21 files changed

+153
-99
lines changed

compiler/rustc_trait_selection/src/solve/inspect/analyse.rs

Lines changed: 64 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
1212
use std::assert_matches::assert_matches;
1313

14-
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
14+
use rustc_infer::infer::InferCtxt;
15+
use rustc_infer::traits::Obligation;
1516
use rustc_macros::extension;
1617
use rustc_middle::traits::ObligationCause;
1718
use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult};
@@ -20,7 +21,7 @@ use rustc_middle::{bug, ty};
2021
use rustc_next_trait_solver::resolve::eager_resolve_vars;
2122
use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state};
2223
use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _};
23-
use rustc_span::{DUMMY_SP, Span};
24+
use rustc_span::Span;
2425
use tracing::instrument;
2526

2627
use crate::solve::delegate::SolverDelegate;
@@ -60,28 +61,29 @@ impl<'tcx> NormalizesToTermHack<'tcx> {
6061
/// Relate the `term` with the new `unconstrained_term` created
6162
/// when computing the proof tree for this `NormalizesTo` goals.
6263
/// This handles nested obligations.
63-
fn constrain(
64-
self,
64+
fn constrain_and(
65+
&self,
6566
infcx: &InferCtxt<'tcx>,
6667
span: Span,
6768
param_env: ty::ParamEnv<'tcx>,
69+
f: impl FnOnce(&ObligationCtxt<'_, 'tcx>),
6870
) -> 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+
}
8587
}
8688
}
8789

@@ -180,11 +182,11 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
180182
let () =
181183
instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state);
182184

183-
if let Some(term_hack) = self.goal.normalizes_to_term_hack {
185+
if let Some(term_hack) = &self.goal.normalizes_to_term_hack {
184186
// FIXME: We ignore the expected term of `NormalizesTo` goals
185187
// when computing the result of its candidates. This is
186188
// scuffed.
187-
let _ = term_hack.constrain(infcx, span, param_env);
189+
let _ = term_hack.constrain_and(infcx, span, param_env, |_| {});
188190
}
189191

190192
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> {
218220
// building their proof tree, the expected term was unconstrained, but when
219221
// instantiating the candidate it is already constrained to the result of another
220222
// 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+
});
223251
InspectGoal::new(
224252
infcx,
225253
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)),
228256
source,
229257
)
230258
}
@@ -371,20 +399,21 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
371399
infcx: &'a InferCtxt<'tcx>,
372400
depth: usize,
373401
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+
)>,
375406
source: GoalSource,
376407
) -> Self {
377408
let infcx = <&SolverDelegate<'tcx>>::from(infcx);
378409

379410
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.
380413
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))
388417
});
389418

390419
InspectGoal {
@@ -394,7 +423,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
394423
goal: eager_resolve_vars(infcx, uncanonicalized_goal),
395424
result,
396425
evaluation_kind: evaluation.kind,
397-
normalizes_to_term_hack,
426+
normalizes_to_term_hack: term_hack_and_nested_certainty.map(|(n, _)| n),
398427
source,
399428
}
400429
}

tests/crashes/140571.rs

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
1-
error[E0284]: type annotations needed: cannot satisfy `impl Sized == _`
2-
--> $DIR/auto-trait-selection-freeze.rs:19:5
1+
error[E0283]: type annotations needed
2+
--> $DIR/auto-trait-selection-freeze.rs:19:16
33
|
44
LL | if false { is_trait(foo()) } else { Default::default() }
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `impl Sized == _`
5+
| ^^^^^^^^ ----- type must be known at this point
6+
| |
7+
| cannot infer type of the type parameter `T` declared on the function `is_trait`
8+
|
9+
= note: cannot satisfy `_: Trait<_>`
10+
note: required by a bound in `is_trait`
11+
--> $DIR/auto-trait-selection-freeze.rs:11:16
12+
|
13+
LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
14+
| ^^^^^^^^ required by this bound in `is_trait`
15+
help: consider specifying the generic arguments
16+
|
17+
LL | if false { is_trait::<T, U>(foo()) } else { Default::default() }
18+
| ++++++++
619

720
error: aborting due to 1 previous error
821

9-
For more information about this error, try `rustc --explain E0284`.
22+
For more information about this error, try `rustc --explain E0283`.
Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
1-
error[E0284]: type annotations needed: cannot satisfy `impl Sized == _`
2-
--> $DIR/auto-trait-selection.rs:15:5
1+
error[E0283]: type annotations needed
2+
--> $DIR/auto-trait-selection.rs:15:16
33
|
44
LL | if false { is_trait(foo()) } else { Default::default() }
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `impl Sized == _`
5+
| ^^^^^^^^ ----- type must be known at this point
6+
| |
7+
| cannot infer type of the type parameter `T` declared on the function `is_trait`
8+
|
9+
= note: cannot satisfy `_: Trait<_>`
10+
note: required by a bound in `is_trait`
11+
--> $DIR/auto-trait-selection.rs:7:16
12+
|
13+
LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
14+
| ^^^^^^^^ required by this bound in `is_trait`
15+
help: consider specifying the generic arguments
16+
|
17+
LL | if false { is_trait::<T, U>(foo()) } else { Default::default() }
18+
| ++++++++
619

720
error: aborting due to 1 previous error
821

9-
For more information about this error, try `rustc --explain E0284`.
22+
For more information about this error, try `rustc --explain E0283`.

tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ LL | type LineStream<'c, 'd> = impl Stream;
2525
|
2626
= note: `LineStream` must be used in combination with a concrete type within the same impl
2727

28-
error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()`
28+
error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to ()`
2929
--> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:29:43
3030
|
3131
LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}

tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ impl X for Y {
2929
fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
3030
//~^ ERROR method `line_stream` is not a member of trait `X`
3131
//[current]~^^ ERROR `()` is not a future
32-
//[next]~^^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()`
32+
//[next]~^^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to ()`
3333
//[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _`
3434
//[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _`
3535
}

tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0284]: type annotations needed: cannot satisfy `impl Sized == _`
2-
--> $DIR/recursive-in-exhaustiveness.rs:19:17
1+
error[E0284]: type annotations needed: cannot normalize `build<_>::{opaque#0}`
2+
--> $DIR/recursive-in-exhaustiveness.rs:20:5
33
|
4-
LL | let (x,) = (build(x),);
5-
| ^^^^^^^^ cannot satisfy `impl Sized == _`
4+
LL | build(x)
5+
| ^^^^^^^^ cannot normalize `build<_>::{opaque#0}`
66

77
error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
88
--> $DIR/recursive-in-exhaustiveness.rs:30:6

tests/ui/impl-trait/recursive-in-exhaustiveness.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
fn build<T>(x: T) -> impl Sized {
1818
//[current]~^ ERROR cannot resolve opaque type
1919
let (x,) = (build(x),);
20-
//[next]~^ ERROR type annotations needed
2120
build(x)
21+
//[next]~^ ERROR type annotations needed: cannot normalize `build<_>::{opaque#0}`
2222
}
2323

2424
// Opaque<T> = (Opaque<T>,)
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
error[E0284]: type annotations needed: cannot satisfy `_ == A`
2-
--> $DIR/two_tait_defining_each_other2.rs:12:8
1+
error[E0282]: type annotations needed
2+
--> $DIR/two_tait_defining_each_other2.rs:12:11
33
|
44
LL | fn muh(x: A) -> B {
5-
| ^ cannot satisfy `_ == A`
5+
| ^ cannot infer type
66

77
error: aborting due to 1 previous error
88

9-
For more information about this error, try `rustc --explain E0284`.
9+
For more information about this error, try `rustc --explain E0282`.

tests/ui/impl-trait/two_tait_defining_each_other2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ trait Foo {}
1010

1111
#[define_opaque(A, B)]
1212
fn muh(x: A) -> B {
13-
//[next]~^ ERROR: cannot satisfy `_ == A`
13+
//[next]~^ ERROR: type annotations needed
1414
x // B's hidden type is A (opaquely)
1515
//[current]~^ ERROR opaque type's hidden type cannot be another opaque type
1616
}

tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ fn main() {
1313
}
1414

1515
fn weird0() -> impl Sized + !Sized {}
16-
//~^ ERROR type mismatch resolving
16+
//~^ ERROR the trait bound `(): !Sized` is not satisfied
1717
fn weird1() -> impl !Sized + Sized {}
18-
//~^ ERROR type mismatch resolving
18+
//~^ ERROR the trait bound `(): !Sized` is not satisfied
1919
fn weird2() -> impl !Sized {}
20-
//~^ ERROR type mismatch resolving
20+
//~^ ERROR the trait bound `(): !Sized` is not satisfied
2121
//~| ERROR the size for values of type

tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,23 @@ LL | fn weird2() -> impl !Sized {}
77
= help: the trait `Sized` is not implemented for `impl !Sized`
88
= note: the return type of a function must have a statically known size
99

10-
error[E0271]: type mismatch resolving `impl !Sized + Sized == ()`
10+
error[E0277]: the trait bound `(): !Sized` is not satisfied
1111
--> $DIR/opaque-type-unsatisfied-bound.rs:15:16
1212
|
1313
LL | fn weird0() -> impl Sized + !Sized {}
14-
| ^^^^^^^^^^^^^^^^^^^ types differ
14+
| ^^^^^^^^^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied
1515

16-
error[E0271]: type mismatch resolving `impl !Sized + Sized == ()`
16+
error[E0277]: the trait bound `(): !Sized` is not satisfied
1717
--> $DIR/opaque-type-unsatisfied-bound.rs:17:16
1818
|
1919
LL | fn weird1() -> impl !Sized + Sized {}
20-
| ^^^^^^^^^^^^^^^^^^^ types differ
20+
| ^^^^^^^^^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied
2121

22-
error[E0271]: type mismatch resolving `impl !Sized == ()`
22+
error[E0277]: the trait bound `(): !Sized` is not satisfied
2323
--> $DIR/opaque-type-unsatisfied-bound.rs:19:16
2424
|
2525
LL | fn weird2() -> impl !Sized {}
26-
| ^^^^^^^^^^^ types differ
26+
| ^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied
2727

2828
error[E0277]: the trait bound `impl !Trait: Trait` is not satisfied
2929
--> $DIR/opaque-type-unsatisfied-bound.rs:12:13
@@ -41,5 +41,4 @@ LL | fn consume(_: impl Trait) {}
4141

4242
error: aborting due to 5 previous errors
4343

44-
Some errors have detailed explanations: E0271, E0277.
45-
For more information about an error, try `rustc --explain E0271`.
44+
For more information about this error, try `rustc --explain E0277`.

tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
#![feature(negative_bounds, unboxed_closures)]
44

55
fn produce() -> impl !Fn<(u32,)> {}
6-
//~^ ERROR type mismatch resolving
6+
//~^ ERROR the trait bound `(): !Fn(u32)` is not satisfied
77

88
fn main() {}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
error[E0271]: type mismatch resolving `impl !Fn<(u32,)> == ()`
1+
error[E0277]: the trait bound `(): !Fn(u32)` is not satisfied
22
--> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:17
33
|
44
LL | fn produce() -> impl !Fn<(u32,)> {}
5-
| ^^^^^^^^^^^^^^^^ types differ
5+
| ^^^^^^^^^^^^^^^^ the trait bound `(): !Fn(u32)` is not satisfied
66

77
error: aborting due to 1 previous error
88

9-
For more information about this error, try `rustc --explain E0271`.
9+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
error[E0284]: type annotations needed: cannot satisfy `Foo == _`
1+
error[E0283]: type annotations needed: cannot satisfy `Foo: Send`
22
--> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18
33
|
44
LL | needs_send::<Foo>();
5-
| ^^^ cannot satisfy `Foo == _`
5+
| ^^^
6+
|
7+
= note: cannot satisfy `Foo: Send`
8+
note: required by a bound in `needs_send`
9+
--> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18
10+
|
11+
LL | fn needs_send<T: Send>() {}
12+
| ^^^^ required by this bound in `needs_send`
613

714
error: aborting due to 1 previous error
815

9-
For more information about this error, try `rustc --explain E0284`.
16+
For more information about this error, try `rustc --explain E0283`.

0 commit comments

Comments
 (0)