Deeply normalize obligations in BestObligation

This commit is contained in:
Michael Goulet 2025-04-09 17:25:46 +00:00
parent 62d5fb85ac
commit decd7ecd1e
11 changed files with 172 additions and 60 deletions

View File

@ -13,9 +13,9 @@ use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as
use rustc_type_ir::solve::NoSolution;
use tracing::{instrument, trace};
use crate::solve::Certainty;
use crate::solve::delegate::SolverDelegate;
use crate::solve::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
use crate::solve::{Certainty, deeply_normalize_for_diagnostics};
use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf};
pub(super) fn fulfillment_error_for_no_solution<'tcx>(
@ -151,7 +151,7 @@ fn find_best_leaf_obligation<'tcx>(
//
// We should probably fix the visitor to not do so instead, as this also
// means the leaf obligation may be incorrect.
infcx
let obligation = infcx
.fudge_inference_if_ok(|| {
infcx
.visit_proof_tree(
@ -161,7 +161,8 @@ fn find_best_leaf_obligation<'tcx>(
.break_value()
.ok_or(())
})
.unwrap_or(obligation)
.unwrap_or(obligation);
deeply_normalize_for_diagnostics(infcx, obligation.param_env, obligation)
}
struct BestObligation<'tcx> {
@ -298,7 +299,7 @@ impl<'tcx> BestObligation<'tcx> {
/// `NormalizesTo` goal, so we don't fall back to the rigid projection check
/// that should catch when a projection goal fails due to an unsatisfied trait
/// goal.
fn detect_error_in_higher_ranked_projection(
fn detect_trait_error_in_higher_ranked_projection(
&mut self,
goal: &inspect::InspectGoal<'_, 'tcx>,
) -> ControlFlow<PredicateObligation<'tcx>> {
@ -307,7 +308,13 @@ impl<'tcx> BestObligation<'tcx> {
&& !projection_clause.bound_vars().is_empty()
{
let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx));
self.with_derived_obligation(self.obligation.with(tcx, pred), |this| {
let obligation = Obligation::new(
tcx,
self.obligation.cause.clone(),
goal.goal().param_env,
deeply_normalize_for_diagnostics(goal.infcx(), goal.goal().param_env, pred),
);
self.with_derived_obligation(obligation, |this| {
goal.infcx().visit_proof_tree_at_depth(
goal.goal().with(tcx, pred),
goal.depth() + 1,
@ -526,7 +533,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
)?;
}
self.detect_error_in_higher_ranked_projection(goal)?;
self.detect_trait_error_in_higher_ranked_projection(goal)?;
ControlFlow::Break(self.obligation.clone())
}

View File

@ -253,20 +253,28 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_,
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
deeply_normalize_with_skipped_universes(
self.at,
ty,
vec![None; ty.outer_exclusive_binder().as_usize()],
)
.unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ty.super_fold_with(self))
let infcx = self.at.infcx;
infcx
.commit_if_ok(|_| {
deeply_normalize_with_skipped_universes(
self.at,
ty,
vec![None; ty.outer_exclusive_binder().as_usize()],
)
})
.unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ty.super_fold_with(self))
}
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
deeply_normalize_with_skipped_universes(
self.at,
ct,
vec![None; ct.outer_exclusive_binder().as_usize()],
)
.unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ct.super_fold_with(self))
let infcx = self.at.infcx;
infcx
.commit_if_ok(|_| {
deeply_normalize_with_skipped_universes(
self.at,
ct,
vec![None; ct.outer_exclusive_binder().as_usize()],
)
})
.unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ct.super_fold_with(self))
}
}

View File

@ -1,12 +1,14 @@
error[E0277]: the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
--> $DIR/as_expression.rs:56:21
|
LL | SelectInt.check("bar");
| ----- ^^^^^ the trait `AsExpression<<SelectInt as Expression>::SqlType>` is not implemented for `&str`
| ----- ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
| |
| required by a bound introduced by this call
|
= help: the trait `AsExpression<Text>` is implemented for `&str`
= help: the trait `AsExpression<Integer>` is not implemented for `&str`
but trait `AsExpression<Text>` is implemented for it
= help: for that trait implementation, expected `Text`, found `Integer`
note: required by a bound in `Foo::check`
--> $DIR/as_expression.rs:47:12
|
@ -16,11 +18,11 @@ LL | where
LL | T: AsExpression<Self::SqlType>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Text`
error[E0271]: type mismatch resolving `Integer == Text`
--> $DIR/as_expression.rs:56:5
|
LL | SelectInt.check("bar");
| ^^^^^^^^^^^^^^^^^^^^^^ expected `Text`, found `Integer`
| ^^^^^^^^^^^^^^^^^^^^^^ types differ
error: aborting due to 2 previous errors

View File

@ -54,7 +54,6 @@ impl<T> Foo for T where T: Expression {}
fn main() {
SelectInt.check("bar");
//[current]~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
//[next]~^^ ERROR the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
//~^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
//[next]~| ERROR type mismatch
}

View File

@ -6,30 +6,134 @@ LL | #![feature(const_trait_impl, generic_const_exprs)]
|
= help: remove one of these features
error[E0277]: the trait bound `T: const Trait` is not satisfied
--> $DIR/unsatisfied-const-trait-bound.rs:29:37
error[E0391]: cycle detected when evaluating type-level constant
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^
| ^^^^^^^^^^^^^
|
note: ...which requires const-evaluating + checking `accept0::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires caching mir of `accept0::{constant#0}` for CTFE...
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires elaborating drops for `accept0::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires borrow-checking `accept0::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires promoting constants in MIR for `accept0::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires const checking `accept0::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires building MIR for `accept0::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires building an abstract representation for `accept0::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires building THIR for `accept0::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires type-checking `accept0::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
= note: ...which again requires evaluating type-level constant, completing the cycle
note: cycle used when checking that `accept0` is well-formed
--> $DIR/unsatisfied-const-trait-bound.rs:29:1
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= 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
error[E0277]: the trait bound `T: const Trait` is not satisfied
--> $DIR/unsatisfied-const-trait-bound.rs:33:50
error[E0391]: cycle detected when caching mir of `accept1::{constant#0}` for CTFE
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
| ^
error[E0277]: the trait bound `Ty: const Trait` is not satisfied
--> $DIR/unsatisfied-const-trait-bound.rs:22:15
| ^^^^^^^^^^^^^
|
LL | require::<Ty>();
| ^^
note: ...which requires elaborating drops for `accept1::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
note: required by a bound in `require`
--> $DIR/unsatisfied-const-trait-bound.rs:8:15
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires borrow-checking `accept1::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
LL | fn require<T: const Trait>() {}
| ^^^^^^^^^^^ required by this bound in `require`
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires promoting constants in MIR for `accept1::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires const checking `accept1::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires building MIR for `accept1::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires building an abstract representation for `accept1::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires building THIR for `accept1::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires type-checking `accept1::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires evaluating type-level constant...
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `accept1::{constant#0}`...
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
= note: ...which again requires caching mir of `accept1::{constant#0}` for CTFE, completing the cycle
note: cycle used when const-evaluating + checking `accept1::{constant#0}`
--> $DIR/unsatisfied-const-trait-bound.rs:33:48
|
LL | const fn accept1<T: ~const Trait>(_: Container<{ T::make() }>) {}
| ^^^^^^^^^^^^^
= 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
error: aborting due to 4 previous errors
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.
For more information about this error, try `rustc --explain E0391`.

View File

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

View File

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

View File

@ -10,7 +10,7 @@ trait Trait: SuperTrait<A = <Self as SuperTrait>::B> {}
fn transmute<A, B>(x: A) -> B {
foo::<A, B, dyn Trait<A = A, B = B>>(x)
//~^ ERROR type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
//~^ ERROR type mismatch resolving `A == B`
}
fn foo<A, B, T: ?Sized>(x: T::A) -> B

View File

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

View File

@ -13,7 +13,7 @@ fn needs_bar<S: Bar>() {}
fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() {
needs_bar::<T::Assoc1>();
//~^ ERROR the trait bound `<T as Foo1>::Assoc1: Bar` is not satisfied
//~^ ERROR the trait bound `<T as Foo2>::Assoc2: Bar` is not satisfied
}
fn main() {}

View File

@ -1,8 +1,8 @@
error[E0277]: the trait bound `<T as Foo1>::Assoc1: Bar` is not satisfied
error[E0277]: the trait bound `<T as Foo2>::Assoc2: Bar` is not satisfied
--> $DIR/recursive-self-normalization-2.rs:15:17
|
LL | needs_bar::<T::Assoc1>();
| ^^^^^^^^^ the trait `Bar` is not implemented for `<T as Foo1>::Assoc1`
| ^^^^^^^^^ the trait `Bar` is not implemented for `<T as Foo2>::Assoc2`
|
note: required by a bound in `needs_bar`
--> $DIR/recursive-self-normalization-2.rs:12:17
@ -11,7 +11,7 @@ LL | fn needs_bar<S: Bar>() {}
| ^^^ required by this bound in `needs_bar`
help: consider further restricting the associated type
|
LL | fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() where <T as Foo1>::Assoc1: Bar {
LL | fn test<T: Foo1<Assoc1 = <T as Foo2>::Assoc2> + Foo2<Assoc2 = <T as Foo1>::Assoc1>>() where <T as Foo2>::Assoc2: Bar {
| ++++++++++++++++++++++++++++++
error: aborting due to 1 previous error