Skip to content

Commit 4192cb6

Browse files
Deeply normalize obligations in BestObligation
1 parent ef3043d commit 4192cb6

File tree

12 files changed

+174
-62
lines changed

12 files changed

+174
-62
lines changed

compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as
1313
use rustc_type_ir::solve::NoSolution;
1414
use tracing::{instrument, trace};
1515

16-
use crate::solve::Certainty;
1716
use crate::solve::delegate::SolverDelegate;
1817
use crate::solve::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
18+
use crate::solve::{Certainty, deeply_normalize_for_diagnostics};
1919
use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf};
2020

2121
pub(super) fn fulfillment_error_for_no_solution<'tcx>(
@@ -151,7 +151,7 @@ fn find_best_leaf_obligation<'tcx>(
151151
//
152152
// We should probably fix the visitor to not do so instead, as this also
153153
// means the leaf obligation may be incorrect.
154-
infcx
154+
let obligation = infcx
155155
.fudge_inference_if_ok(|| {
156156
infcx
157157
.visit_proof_tree(
@@ -161,7 +161,8 @@ fn find_best_leaf_obligation<'tcx>(
161161
.break_value()
162162
.ok_or(())
163163
})
164-
.unwrap_or(obligation)
164+
.unwrap_or(obligation);
165+
deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation)
165166
}
166167

167168
struct BestObligation<'tcx> {
@@ -508,7 +509,13 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
508509
&& !projection_clause.bound_vars().is_empty()
509510
{
510511
let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx));
511-
self.with_derived_obligation(self.obligation.with(tcx, pred), |this| {
512+
let obligation = Obligation::new(
513+
tcx,
514+
self.obligation.cause.clone(),
515+
goal.goal().param_env,
516+
deeply_normalize_for_diagnostics(goal.infcx(), goal.goal().param_env, pred),
517+
);
518+
self.with_derived_obligation(obligation, |this| {
512519
goal.infcx().visit_proof_tree_at_depth(
513520
goal.goal().with(tcx, pred),
514521
goal.depth() + 1,

compiler/rustc_trait_selection/src/solve/normalize.rs

+20-12
Original file line numberDiff line numberDiff line change
@@ -253,20 +253,28 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_,
253253
}
254254

255255
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
256-
deeply_normalize_with_skipped_universes(
257-
self.at,
258-
ty,
259-
vec![None; ty.outer_exclusive_binder().as_usize()],
260-
)
261-
.unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ty.super_fold_with(self))
256+
let infcx = self.at.infcx;
257+
infcx
258+
.commit_if_ok(|_| {
259+
deeply_normalize_with_skipped_universes(
260+
self.at,
261+
ty,
262+
vec![None; ty.outer_exclusive_binder().as_usize()],
263+
)
264+
})
265+
.unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ty.super_fold_with(self))
262266
}
263267

264268
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
265-
deeply_normalize_with_skipped_universes(
266-
self.at,
267-
ct,
268-
vec![None; ct.outer_exclusive_binder().as_usize()],
269-
)
270-
.unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ct.super_fold_with(self))
269+
let infcx = self.at.infcx;
270+
infcx
271+
.commit_if_ok(|_| {
272+
deeply_normalize_with_skipped_universes(
273+
self.at,
274+
ct,
275+
vec![None; ct.outer_exclusive_binder().as_usize()],
276+
)
277+
})
278+
.unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ct.super_fold_with(self))
271279
}
272280
}

tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
error[E0277]: the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
1+
error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
22
--> $DIR/as_expression.rs:56:21
33
|
44
LL | SelectInt.check("bar");
5-
| ----- ^^^^^ the trait `AsExpression<<SelectInt as Expression>::SqlType>` is not implemented for `&str`
5+
| ----- ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
66
| |
77
| required by a bound introduced by this call
88
|
9-
= help: the trait `AsExpression<Text>` is implemented for `&str`
9+
= help: the trait `AsExpression<Integer>` is not implemented for `&str`
10+
but trait `AsExpression<Text>` is implemented for it
11+
= help: for that trait implementation, expected `Text`, found `Integer`
1012
note: required by a bound in `Foo::check`
1113
--> $DIR/as_expression.rs:47:12
1214
|
@@ -16,11 +18,11 @@ LL | where
1618
LL | T: AsExpression<Self::SqlType>,
1719
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
1820

19-
error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Text`
21+
error[E0271]: type mismatch resolving `Integer == Text`
2022
--> $DIR/as_expression.rs:56:5
2123
|
2224
LL | SelectInt.check("bar");
23-
| ^^^^^^^^^^^^^^^^^^^^^^ expected `Text`, found `Integer`
25+
| ^^^^^^^^^^^^^^^^^^^^^^ types differ
2426

2527
error: aborting due to 2 previous errors
2628

tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ impl<T> Foo for T where T: Expression {}
5454

5555
fn main() {
5656
SelectInt.check("bar");
57-
//[current]~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
58-
//[next]~^^ ERROR the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
57+
//~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
5958
//[next]~| ERROR type mismatch
6059
}

tests/ui/mismatched_types/closure-mismatch.next.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ LL | baz(|_| ());
77
| required by a bound introduced by this call
88
|
99
= help: the trait `for<'a> FnOnce(&'a ())` is not implemented for closure `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}`
10-
= note: expected a closure with arguments `(&(),)`
11-
found a closure with arguments `(&(),)`
10+
= note: expected a closure with signature `for<'a> fn(&'a ())`
11+
found a closure with signature `fn(&())`
1212
note: this is a known limitation of the trait solver that will be lifted in the future
1313
--> $DIR/closure-mismatch.rs:12:9
1414
|
@@ -39,8 +39,8 @@ LL | baz(|x| ());
3939
| required by a bound introduced by this call
4040
|
4141
= help: the trait `for<'a> FnOnce(&'a ())` is not implemented for closure `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}`
42-
= note: expected a closure with arguments `(&(),)`
43-
found a closure with arguments `(&(),)`
42+
= note: expected a closure with signature `for<'a> fn(&'a ())`
43+
found a closure with signature `fn(&())`
4444
note: this is a known limitation of the trait solver that will be lifted in the future
4545
--> $DIR/closure-mismatch.rs:16:9
4646
|

tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr

+121-17
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,134 @@ LL | #![feature(const_trait_impl, generic_const_exprs)]
66
|
77
= help: remove one of these features
88

9-
error[E0277]: the trait bound `T: const Trait` is not satisfied
10-
--> $DIR/unsatisfied-const-trait-bound.rs:29:37
9+
error[E0391]: cycle detected when evaluating type-level constant
10+
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
1111
|
1212
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
13-
| ^
13+
| ^^^^^^^^^^^^^
14+
|
15+
note: ...which requires const-evaluating + checking `accept0::{constant#0}`...
16+
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
17+
|
18+
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
19+
| ^^^^^^^^^^^^^
20+
note: ...which requires caching mir of `accept0::{constant#0}` for CTFE...
21+
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
22+
|
23+
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
24+
| ^^^^^^^^^^^^^
25+
note: ...which requires elaborating drops for `accept0::{constant#0}`...
26+
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
27+
|
28+
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
29+
| ^^^^^^^^^^^^^
30+
note: ...which requires borrow-checking `accept0::{constant#0}`...
31+
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
32+
|
33+
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
34+
| ^^^^^^^^^^^^^
35+
note: ...which requires promoting constants in MIR for `accept0::{constant#0}`...
36+
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
37+
|
38+
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
39+
| ^^^^^^^^^^^^^
40+
note: ...which requires const checking `accept0::{constant#0}`...
41+
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
42+
|
43+
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
44+
| ^^^^^^^^^^^^^
45+
note: ...which requires building MIR for `accept0::{constant#0}`...
46+
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
47+
|
48+
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
49+
| ^^^^^^^^^^^^^
50+
note: ...which requires building an abstract representation for `accept0::{constant#0}`...
51+
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
52+
|
53+
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
54+
| ^^^^^^^^^^^^^
55+
note: ...which requires building THIR for `accept0::{constant#0}`...
56+
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
57+
|
58+
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
59+
| ^^^^^^^^^^^^^
60+
note: ...which requires type-checking `accept0::{constant#0}`...
61+
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
62+
|
63+
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
64+
| ^^^^^^^^^^^^^
65+
= note: ...which again requires evaluating type-level constant, completing the cycle
66+
note: cycle used when checking that `accept0` is well-formed
67+
--> $DIR/unsatisfied-const-trait-bound.rs:29:1
68+
|
69+
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
70+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
71+
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
1472

15-
error[E0277]: the trait bound `T: const Trait` is not satisfied
16-
--> $DIR/unsatisfied-const-trait-bound.rs:33:50
73+
error[E0391]: cycle detected when caching mir of `accept1::{constant#0}` for CTFE
74+
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
1775
|
1876
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
19-
| ^
20-
21-
error[E0277]: the trait bound `Ty: const Trait` is not satisfied
22-
--> $DIR/unsatisfied-const-trait-bound.rs:22:15
77+
| ^^^^^^^^^^^^^
78+
|
79+
note: ...which requires elaborating drops for `accept1::{constant#0}`...
80+
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
81+
|
82+
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
83+
| ^^^^^^^^^^^^^
84+
note: ...which requires borrow-checking `accept1::{constant#0}`...
85+
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
86+
|
87+
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
88+
| ^^^^^^^^^^^^^
89+
note: ...which requires promoting constants in MIR for `accept1::{constant#0}`...
90+
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
91+
|
92+
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
93+
| ^^^^^^^^^^^^^
94+
note: ...which requires const checking `accept1::{constant#0}`...
95+
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
96+
|
97+
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
98+
| ^^^^^^^^^^^^^
99+
note: ...which requires building MIR for `accept1::{constant#0}`...
100+
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
23101
|
24-
LL | require::<Ty>();
25-
| ^^
102+
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
103+
| ^^^^^^^^^^^^^
104+
note: ...which requires building an abstract representation for `accept1::{constant#0}`...
105+
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
106+
|
107+
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
108+
| ^^^^^^^^^^^^^
109+
note: ...which requires building THIR for `accept1::{constant#0}`...
110+
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
26111
|
27-
note: required by a bound in `require`
28-
--> $DIR/unsatisfied-const-trait-bound.rs:8:15
112+
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
113+
| ^^^^^^^^^^^^^
114+
note: ...which requires type-checking `accept1::{constant#0}`...
115+
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
116+
|
117+
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
118+
| ^^^^^^^^^^^^^
119+
note: ...which requires evaluating type-level constant...
120+
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
29121
|
30-
LL | fn require<T: const Trait>() {}
31-
| ^^^^^^^^^^^ required by this bound in `require`
122+
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
123+
| ^^^^^^^^^^^^^
124+
note: ...which requires const-evaluating + checking `accept1::{constant#0}`...
125+
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
126+
|
127+
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
128+
| ^^^^^^^^^^^^^
129+
= note: ...which again requires caching mir of `accept1::{constant#0}` for CTFE, completing the cycle
130+
note: cycle used when const-evaluating + checking `accept1::{constant#0}`
131+
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
132+
|
133+
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
134+
| ^^^^^^^^^^^^^
135+
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
32136

33-
error: aborting due to 4 previous errors
137+
error: aborting due to 3 previous errors
34138

35-
For more information about this error, try `rustc --explain E0277`.
139+
For more information about this error, try `rustc --explain E0391`.

tests/ui/traits/next-solver/async.fail.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0271]: expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()`
1+
error[E0271]: type mismatch resolving `() == i32`
22
--> $DIR/async.rs:12:17
33
|
44
LL | needs_async(async {});
5-
| ----------- ^^^^^^^^ expected `i32`, found `()`
5+
| ----------- ^^^^^^^^ types differ
66
| |
77
| required by a bound introduced by this call
88
|

tests/ui/traits/next-solver/async.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ fn needs_async(_: impl Future<Output = i32>) {}
1010
#[cfg(fail)]
1111
fn main() {
1212
needs_async(async {});
13-
//[fail]~^ ERROR expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()`
13+
//[fail]~^ ERROR type mismatch resolving `() == i32`
1414
}
1515

1616
#[cfg(pass)]

tests/ui/traits/next-solver/more-object-bound.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ trait Trait: SuperTrait<A = <Self as SuperTrait>::B> {}
1010

1111
fn transmute<A, B>(x: A) -> B {
1212
foo::<A, B, dyn Trait<A = A, B = B>>(x)
13-
//~^ ERROR type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
13+
//~^ ERROR type mismatch resolving `A == B`
1414
}
1515

1616
fn foo<A, B, T: ?Sized>(x: T::A) -> B

tests/ui/traits/next-solver/more-object-bound.stderr

+2-10
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,9 @@
1-
error[E0271]: type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
1+
error[E0271]: type mismatch resolving `A == B`
22
--> $DIR/more-object-bound.rs:12:5
33
|
4-
LL | fn transmute<A, B>(x: A) -> B {
5-
| - - expected type parameter
6-
| |
7-
| found type parameter
84
LL | foo::<A, B, dyn Trait<A = A, B = B>>(x)
9-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `B`, found type parameter `A`
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
106
|
11-
= note: expected type parameter `B`
12-
found type parameter `A`
13-
= note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
14-
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
157
= note: required because it appears within the type `dyn Trait<A = A, B = B>`
168
note: required by a bound in `foo`
179
--> $DIR/more-object-bound.rs:18:8

tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn needs_bar<S: Bar>() {}
1313

1414
fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() {
1515
needs_bar::<T::Assoc1>();
16-
//~^ ERROR the trait bound `<T as Foo1>::Assoc1: Bar` is not satisfied
16+
//~^ ERROR the trait bound `<T as Foo2>::Assoc2: Bar` is not satisfied
1717
}
1818

1919
fn main() {}

tests/ui/traits/next-solver/overflow/recursive-self-normalization-2.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0277]: the trait bound `<T as Foo1>::Assoc1: Bar` is not satisfied
1+
error[E0277]: the trait bound `<T as Foo2>::Assoc2: Bar` is not satisfied
22
--> $DIR/recursive-self-normalization-2.rs:15:17
33
|
44
LL | needs_bar::<T::Assoc1>();
5-
| ^^^^^^^^^ the trait `Bar` is not implemented for `<T as Foo1>::Assoc1`
5+
| ^^^^^^^^^ the trait `Bar` is not implemented for `<T as Foo2>::Assoc2`
66
|
77
note: required by a bound in `needs_bar`
88
--> $DIR/recursive-self-normalization-2.rs:12:17
@@ -11,7 +11,7 @@ LL | fn needs_bar<S: Bar>() {}
1111
| ^^^ required by this bound in `needs_bar`
1212
help: consider further restricting the associated type
1313
|
14-
LL | fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() where <T as Foo1>::Assoc1: Bar {
14+
LL | fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() where <T as Foo2>::Assoc2: Bar {
1515
| ++++++++++++++++++++++++++++++
1616

1717
error: aborting due to 1 previous error

0 commit comments

Comments
 (0)