From 578bcc8cf1856bcbf80521c8f280647b9847e3dc Mon Sep 17 00:00:00 2001 From: Adwin White Date: Wed, 12 Nov 2025 19:03:03 +0800 Subject: [PATCH] show env normalization differences under two solvers --- .../src/solve/normalize.rs | 12 +++ .../rustc_trait_selection/src/traits/mod.rs | 62 ++++++++++- .../fuzzed/fuzzing-ice-134905.rs | 6 +- .../fuzzed/fuzzing-ice-134905.stderr | 4 +- tests/ui/specialization/issue-38091-2.rs | 9 +- tests/ui/specialization/issue-38091-2.stderr | 27 ++++- tests/ui/specialization/issue-38091.rs | 7 +- tests/ui/specialization/issue-38091.stderr | 37 ++++++- .../unsatisfied-const-trait-bound.stderr | 100 ++++-------------- .../normalize-param-env-4.current.stderr | 22 ++++ .../normalize-param-env-4.next.stderr | 2 +- .../normalize/normalize-param-env-4.rs | 3 +- 12 files changed, 192 insertions(+), 99 deletions(-) create mode 100644 tests/ui/traits/next-solver/normalize/normalize-param-env-4.current.stderr diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 567f660a59383..f1f9325b33cb5 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -222,6 +222,10 @@ where } let ty::ConstKind::Unevaluated(..) = ct.kind() else { return ct.try_super_fold_with(self) }; + // FIXME: `generic_const_exprs` not implemented in the next solver. + if ct.has_non_region_param() { + return Ok(ct); + } if ct.has_escaping_bound_vars() { let (ct, mapped_regions, mapped_types, mapped_consts) = @@ -240,6 +244,14 @@ where Ok(ensure_sufficient_stack(|| self.normalize_alias_term(ct.into()))?.expect_const()) } } + + #[instrument(level = "trace", skip(self), ret)] + fn try_fold_predicate( + &mut self, + p: ty::Predicate<'tcx>, + ) -> Result, Self::Error> { + if p.allow_normalization() { p.try_super_fold_with(self) } else { Ok(p) } + } } // Deeply normalize a value and return it diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 308d533e68991..1693cc721210b 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -257,6 +257,7 @@ fn do_normalize_predicates<'tcx>( predicates: Vec>, ) -> Result>, ErrorGuaranteed> { let span = cause.span; + let original_predicates = predicates.clone(); // FIXME. We should really... do something with these region // obligations. But this call just continues the older @@ -296,8 +297,8 @@ fn do_normalize_predicates<'tcx>( ); } - match infcx.fully_resolve(predicates) { - Ok(predicates) => Ok(predicates), + let predicates = match infcx.fully_resolve(predicates) { + Ok(predicates) => predicates, Err(fixup_err) => { // If we encounter a fixup error, it means that some type // variable wound up unconstrained. I actually don't know @@ -314,7 +315,64 @@ fn do_normalize_predicates<'tcx>( fixup_err ); } + }; + // The next solver returns nothing for values that contains type error. + // And type error should cause failure later. So we skip the consistency check. + // `generic_const_exprs` is incompatible with next solver now. + if !tcx.next_trait_solver_globally() + && !predicates.references_error() + && !tcx.features().generic_const_exprs() + { + let infcx = tcx + .infer_ctxt() + .with_next_trait_solver(true) + .ignoring_regions() + .build(TypingMode::non_body_analysis()); + let predicates_by_next: Vec> = original_predicates + .iter() + .cloned() + .map(|p| { + crate::solve::deeply_normalize::<_, ScrubbedTraitError<'tcx>>( + infcx.at(&cause, elaborated_env), + p, + ) + .ok() + }) + .collect(); + + // FIXME: next solver adds region constraints that contains placeholders to infcx. + // `infcx.considering_regions` is not checked. + let _errors = infcx.resolve_regions(cause.body_id, elaborated_env, []); + + let predicates_by_next = match infcx.fully_resolve(predicates_by_next) { + Ok(predicates) => predicates, + Err(fixup_err) => { + span_bug!( + span, + "inference variables in normalized parameter environment: {}", + fixup_err + ); + } + }; + + for ((orig_pred, old_pred), next_pred) in + original_predicates.iter().zip(&predicates).zip(&predicates_by_next) + { + if let Some(next_pred) = next_pred + && next_pred == old_pred + { + continue; + } + tcx.dcx().span_err( + span, + format!( + "inconsistency during normalizing env `{:#?}`, old={:#?}, next={:#?}", + orig_pred, old_pred, next_pred + ), + ); + } } + Ok(predicates) } // FIXME: this is gonna need to be removed ... diff --git a/tests/ui/specialization/fuzzed/fuzzing-ice-134905.rs b/tests/ui/specialization/fuzzed/fuzzing-ice-134905.rs index 559c23455275b..2fe608c583c74 100644 --- a/tests/ui/specialization/fuzzed/fuzzing-ice-134905.rs +++ b/tests/ui/specialization/fuzzed/fuzzing-ice-134905.rs @@ -14,8 +14,12 @@ where } trait Check {} -impl<'a, T> Eq for T where >::Ty: Valid {} +impl<'a, T> Eq for T //~^ ERROR type parameter `T` must be used as the type parameter for some local type +where + T: Iterate<'a>, + >::Ty: Valid, +{} trait Valid {} diff --git a/tests/ui/specialization/fuzzed/fuzzing-ice-134905.stderr b/tests/ui/specialization/fuzzed/fuzzing-ice-134905.stderr index 611fef1df66bf..edd7ffc7e3274 100644 --- a/tests/ui/specialization/fuzzed/fuzzing-ice-134905.stderr +++ b/tests/ui/specialization/fuzzed/fuzzing-ice-134905.stderr @@ -15,7 +15,7 @@ LL | default type Ty = (); | ^^ the trait `Valid` is not implemented for `()` | help: this trait has no implementations, consider adding one - --> $DIR/fuzzing-ice-134905.rs:20:1 + --> $DIR/fuzzing-ice-134905.rs:24:1 | LL | trait Valid {} | ^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | type Ty: Valid; error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) --> $DIR/fuzzing-ice-134905.rs:17:10 | -LL | impl<'a, T> Eq for T where >::Ty: Valid {} +LL | impl<'a, T> Eq for T | ^ type parameter `T` must be used as the type parameter for some local type | = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local diff --git a/tests/ui/specialization/issue-38091-2.rs b/tests/ui/specialization/issue-38091-2.rs index da276031378db..2a36382764a3d 100644 --- a/tests/ui/specialization/issue-38091-2.rs +++ b/tests/ui/specialization/issue-38091-2.rs @@ -1,6 +1,3 @@ -//@ build-fail -//~^ ERROR overflow evaluating the requirement `i32: Check` - #![feature(specialization)] //~^ WARN the feature `specialization` is incomplete @@ -17,7 +14,11 @@ where } trait Check {} -impl<'a, T> Check for T where >::Ty: Valid {} +impl<'a, T> Check for T +//~^ ERROR: overflow evaluating the requirement `T: Check` +where + T: Iterate<'a>, + >::Ty: Valid {} trait Valid {} diff --git a/tests/ui/specialization/issue-38091-2.stderr b/tests/ui/specialization/issue-38091-2.stderr index 828a8e933994b..0cd498d5ae760 100644 --- a/tests/ui/specialization/issue-38091-2.stderr +++ b/tests/ui/specialization/issue-38091-2.stderr @@ -1,5 +1,5 @@ warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-38091-2.rs:4:12 + --> $DIR/issue-38091-2.rs:1:12 | LL | #![feature(specialization)] | ^^^^^^^^^^^^^^ @@ -8,16 +8,35 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete = note: `#[warn(incomplete_features)]` on by default -error[E0275]: overflow evaluating the requirement `i32: Check` +error[E0275]: overflow evaluating the requirement `T: Check` + --> $DIR/issue-38091-2.rs:17:1 | -note: required for `i32` to implement `Iterate<'_>` - --> $DIR/issue-38091-2.rs:11:13 +LL | / impl<'a, T> Check for T +LL | | +LL | | where +LL | | T: Iterate<'a>, +LL | | >::Ty: Valid {} + | |_________________________________^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_38091_2`) +note: required for `T` to implement `Iterate<'_>` + --> $DIR/issue-38091-2.rs:8:13 | LL | impl<'a, T> Iterate<'a> for T | ^^^^^^^^^^^ ^ LL | where LL | T: Check, | ----- unsatisfied trait bound introduced here +note: required for `T` to implement `Check` + --> $DIR/issue-38091-2.rs:17:13 + | +LL | impl<'a, T> Check for T + | ^^^^^ ^ +... +LL | >::Ty: Valid {} + | ----- unsatisfied trait bound introduced here + = note: 125 redundant requirements hidden + = note: required for `T` to implement `Iterate<'a>` error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/specialization/issue-38091.rs b/tests/ui/specialization/issue-38091.rs index 5b398368a6733..61736921c534a 100644 --- a/tests/ui/specialization/issue-38091.rs +++ b/tests/ui/specialization/issue-38091.rs @@ -15,7 +15,12 @@ where } trait Check {} -impl<'a, T> Check for T where >::Ty: Valid {} +impl<'a, T> Check for T +//~^ ERROR: overflow evaluating the requirement `T: Check` +where + T: Iterate<'a>, + >::Ty: Valid, +{} trait Valid {} diff --git a/tests/ui/specialization/issue-38091.stderr b/tests/ui/specialization/issue-38091.stderr index eb64383e18bbd..fd4f43101d63d 100644 --- a/tests/ui/specialization/issue-38091.stderr +++ b/tests/ui/specialization/issue-38091.stderr @@ -15,7 +15,7 @@ LL | default type Ty = (); | ^^ the trait `Valid` is not implemented for `()` | help: this trait has no implementations, consider adding one - --> $DIR/issue-38091.rs:20:1 + --> $DIR/issue-38091.rs:25:1 | LL | trait Valid {} | ^^^^^^^^^^^ @@ -25,6 +25,37 @@ note: required by a bound in `Iterate::Ty` LL | type Ty: Valid; | ^^^^^ required by this bound in `Iterate::Ty` -error: aborting due to 1 previous error; 1 warning emitted +error[E0275]: overflow evaluating the requirement `T: Check` + --> $DIR/issue-38091.rs:18:1 + | +LL | / impl<'a, T> Check for T +LL | | +LL | | where +LL | | T: Iterate<'a>, +LL | | >::Ty: Valid, + | |__________________________________^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_38091`) +note: required for `T` to implement `Iterate<'_>` + --> $DIR/issue-38091.rs:8:13 + | +LL | impl<'a, T> Iterate<'a> for T + | ^^^^^^^^^^^ ^ +LL | where +LL | T: Check, + | ----- unsatisfied trait bound introduced here +note: required for `T` to implement `Check` + --> $DIR/issue-38091.rs:18:13 + | +LL | impl<'a, T> Check for T + | ^^^^^ ^ +... +LL | >::Ty: Valid, + | ----- unsatisfied trait bound introduced here + = note: 125 redundant requirements hidden + = note: required for `T` to implement `Iterate<'a>` + +error: aborting due to 2 previous errors; 1 warning emitted -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0275, E0277. +For more information about an error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr index 1a2bc6c2c5f59..92728f6e9bfdf 100644 --- a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr +++ b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr @@ -6,94 +6,34 @@ LL | #![feature(const_trait_impl, generic_const_exprs)] | = help: remove one of these features -error[E0391]: cycle detected when evaluating type-level constant - --> $DIR/unsatisfied-const-trait-bound.rs:28:35 +error[E0277]: the trait bound `T: const Trait` is not satisfied + --> $DIR/unsatisfied-const-trait-bound.rs:28:37 | LL | fn accept0(_: Container<{ T::make() }>) {} - | ^^^^^^^^^^^^^ - | -note: ...which requires const-evaluating + checking `accept0::{constant#0}`... - --> $DIR/unsatisfied-const-trait-bound.rs:28:35 - | -LL | fn accept0(_: Container<{ T::make() }>) {} - | ^^^^^^^^^^^^^ -note: ...which requires checking if `accept0::{constant#0}` is a trivial const... - --> $DIR/unsatisfied-const-trait-bound.rs:28:35 - | -LL | fn accept0(_: Container<{ T::make() }>) {} - | ^^^^^^^^^^^^^ -note: ...which requires building MIR for `accept0::{constant#0}`... - --> $DIR/unsatisfied-const-trait-bound.rs:28:35 - | -LL | fn accept0(_: Container<{ T::make() }>) {} - | ^^^^^^^^^^^^^ -note: ...which requires building an abstract representation for `accept0::{constant#0}`... - --> $DIR/unsatisfied-const-trait-bound.rs:28:35 - | -LL | fn accept0(_: Container<{ T::make() }>) {} - | ^^^^^^^^^^^^^ -note: ...which requires building THIR for `accept0::{constant#0}`... - --> $DIR/unsatisfied-const-trait-bound.rs:28:35 - | -LL | fn accept0(_: Container<{ T::make() }>) {} - | ^^^^^^^^^^^^^ -note: ...which requires type-checking `accept0::{constant#0}`... - --> $DIR/unsatisfied-const-trait-bound.rs:28:35 - | -LL | fn accept0(_: 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:28:35 - | -LL | fn accept0(_: 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[E0391]: cycle detected when checking if `accept1::{constant#0}` is a trivial const - --> $DIR/unsatisfied-const-trait-bound.rs:32:49 - | -LL | const fn accept1(_: Container<{ T::make() }>) {} - | ^^^^^^^^^^^^^ - | -note: ...which requires building MIR for `accept1::{constant#0}`... - --> $DIR/unsatisfied-const-trait-bound.rs:32:49 +error[E0277]: the trait bound `T: const Trait` is not satisfied + --> $DIR/unsatisfied-const-trait-bound.rs:32:51 | LL | const fn accept1(_: Container<{ T::make() }>) {} - | ^^^^^^^^^^^^^ -note: ...which requires building an abstract representation for `accept1::{constant#0}`... - --> $DIR/unsatisfied-const-trait-bound.rs:32:49 - | -LL | const fn accept1(_: Container<{ T::make() }>) {} - | ^^^^^^^^^^^^^ -note: ...which requires building THIR for `accept1::{constant#0}`... - --> $DIR/unsatisfied-const-trait-bound.rs:32:49 - | -LL | const fn accept1(_: Container<{ T::make() }>) {} - | ^^^^^^^^^^^^^ -note: ...which requires type-checking `accept1::{constant#0}`... - --> $DIR/unsatisfied-const-trait-bound.rs:32:49 + | ^ + +error[E0277]: the trait bound `Ty: const Trait` is not satisfied + --> $DIR/unsatisfied-const-trait-bound.rs:21:15 | -LL | const fn accept1(_: Container<{ T::make() }>) {} - | ^^^^^^^^^^^^^ -note: ...which requires evaluating type-level constant... - --> $DIR/unsatisfied-const-trait-bound.rs:32:49 +LL | require::(); + | ^^ | -LL | const fn accept1(_: Container<{ T::make() }>) {} - | ^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `accept1::{constant#0}`... - --> $DIR/unsatisfied-const-trait-bound.rs:32:49 +note: required by a bound in `require` + --> $DIR/unsatisfied-const-trait-bound.rs:8:15 | -LL | const fn accept1(_: Container<{ T::make() }>) {} - | ^^^^^^^^^^^^^ - = note: ...which again requires checking if `accept1::{constant#0}` is a trivial const, completing the cycle -note: cycle used when const-evaluating + checking `accept1::{constant#0}` - --> $DIR/unsatisfied-const-trait-bound.rs:32:49 +LL | fn require() {} + | ^^^^^^^^^^^ required by this bound in `require` +help: make the `impl` of trait `Trait` `const` | -LL | const fn accept1(_: 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 +LL | impl const Trait for Ty { + | +++++ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0391`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.current.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.current.stderr new file mode 100644 index 0000000000000..7408a1642c150 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.current.stderr @@ -0,0 +1,22 @@ +error: inconsistency during normalizing env `Binder { value: TraitPredicate(<::Assoc as Trait>, polarity:Positive), bound_vars: [] }`, old=Binder { value: TraitPredicate(, polarity:Positive), bound_vars: [] }, next=None + --> $DIR/normalize-param-env-4.rs:16:1 + | +LL | / fn foo() +LL | | +LL | | +LL | | where +LL | | ::Assoc: Trait, + | |_______________________________^ + +error: inconsistency during normalizing env `Binder { value: TraitPredicate(<::Assoc as std::marker::MetaSized>, polarity:Positive), bound_vars: [] }`, old=Binder { value: TraitPredicate(, polarity:Positive), bound_vars: [] }, next=None + --> $DIR/normalize-param-env-4.rs:16:1 + | +LL | / fn foo() +LL | | +LL | | +LL | | where +LL | | ::Assoc: Trait, + | |_______________________________^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr index f5fd9ce9864ce..d76a9b9726953 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow evaluating the requirement `::Assoc: Trait` - --> $DIR/normalize-param-env-4.rs:19:26 + --> $DIR/normalize-param-env-4.rs:20:26 | LL | ::Assoc: Trait, | ^^^^^ diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.rs b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.rs index ed7f6899bdee6..ca9c365da37c9 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.rs +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.rs @@ -2,7 +2,6 @@ //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver //@[next] known-bug: #92505 -//@[current] check-pass trait Trait { type Assoc; @@ -15,6 +14,8 @@ impl Trait for T { fn impls_trait() {} fn foo() + //[current]~^ ERROR: inconsistency during normalizing env + //[current]~| ERROR: inconsistency during normalizing env where ::Assoc: Trait, {