1
Fork 0

normalizing where-clauses is also coinductive, add tests

This commit is contained in:
lcnr 2025-02-21 10:11:56 +01:00
parent a7970c0b27
commit 7eb677e7eb
17 changed files with 255 additions and 20 deletions

View file

@ -264,7 +264,10 @@ where
pub(super) fn step_kind_for_source(&self, source: GoalSource) -> PathKind {
match (self.current_goal_kind, source) {
(CurrentGoalKind::CoinductiveTrait, GoalSource::ImplWhereBound) => PathKind::Coinductive,
(_, GoalSource::NormalizeGoal(step_kind)) => step_kind,
(CurrentGoalKind::CoinductiveTrait, GoalSource::ImplWhereBound) => {
PathKind::Coinductive
}
_ => PathKind::Inductive,
}
}
@ -670,8 +673,11 @@ where
#[instrument(level = "trace", skip(self))]
pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<I, ty::NormalizesTo<I>>) {
goal.predicate =
goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, goal.param_env));
goal.predicate = goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(
self,
GoalSource::Misc,
goal.param_env,
));
self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal);
self.nested_goals.normalizes_to_goals.push(goal);
}
@ -679,7 +685,7 @@ where
#[instrument(level = "debug", skip(self))]
pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal<I, I::Predicate>) {
goal.predicate =
goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, goal.param_env));
goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, source, goal.param_env));
self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal);
self.nested_goals.goals.push((source, goal));
}
@ -1100,6 +1106,7 @@ where
{
ecx: &'me mut EvalCtxt<'a, D>,
param_env: I::ParamEnv,
normalization_goal_source: GoalSource,
cache: HashMap<I::Ty, I::Ty>,
}
@ -1108,8 +1115,18 @@ where
D: SolverDelegate<Interner = I>,
I: Interner,
{
fn new(ecx: &'me mut EvalCtxt<'a, D>, param_env: I::ParamEnv) -> Self {
ReplaceAliasWithInfer { ecx, param_env, cache: Default::default() }
fn new(
ecx: &'me mut EvalCtxt<'a, D>,
for_goal_source: GoalSource,
param_env: I::ParamEnv,
) -> Self {
let step_kind = ecx.step_kind_for_source(for_goal_source);
ReplaceAliasWithInfer {
ecx,
param_env,
normalization_goal_source: GoalSource::NormalizeGoal(step_kind),
cache: Default::default(),
}
}
}
@ -1132,7 +1149,7 @@ where
ty::AliasRelationDirection::Equate,
);
self.ecx.add_goal(
GoalSource::Misc,
self.normalization_goal_source,
Goal::new(self.cx(), self.param_env, normalizes_to),
);
infer_ty
@ -1161,7 +1178,7 @@ where
ty::AliasRelationDirection::Equate,
);
self.ecx.add_goal(
GoalSource::Misc,
self.normalization_goal_source,
Goal::new(self.cx(), self.param_env, normalizes_to),
);
infer_ct

View file

@ -438,7 +438,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
let obligation;
match (child_mode, nested_goal.source()) {
(ChildMode::Trait(_) | ChildMode::Host(_), GoalSource::Misc) => {
(
ChildMode::Trait(_) | ChildMode::Host(_),
GoalSource::Misc | GoalSource::NormalizeGoal(_),
) => {
continue;
}
(ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {

View file

@ -19,6 +19,8 @@ use std::marker::PhantomData;
use derive_where::derive_where;
use rustc_index::{Idx, IndexVec};
#[cfg(feature = "nightly")]
use rustc_macros::HashStable_NoContext;
use tracing::debug;
use crate::data_structures::HashMap;
@ -109,7 +111,8 @@ pub trait Delegate {
/// In the initial iteration of a cycle, we do not yet have a provisional
/// result. In the case we return an initial provisional result depending
/// on the kind of cycle.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
pub enum PathKind {
Coinductive,
Inductive,

View file

@ -8,6 +8,7 @@ use derive_where::derive_where;
use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
use crate::search_graph::PathKind;
use crate::{self as ty, Canonical, CanonicalVarValues, Interner, Upcast};
pub type CanonicalInput<I, T = <I as Interner>::Predicate> =
@ -78,6 +79,14 @@ pub enum GoalSource {
/// This is used in two places: projecting to an opaque whose hidden type
/// is already registered in the opaque type storage, and for rigid projections.
AliasWellFormed,
/// In case normalizing aliases in nested goals cycles, eagerly normalizing these
/// aliases in the context of the parent may incorrectly change the cycle kind.
/// Normalizing aliases in goals therefore tracks the original path kind for this
/// nested goal.
///
/// This is necessary for tests/ui/sized/coinductive-1.rs to compile.
NormalizeGoal(PathKind),
}
#[derive_where(Clone; I: Interner, Goal<I, P>: Clone)]

View file

@ -6,30 +6,90 @@ LL | #![feature(const_trait_impl, generic_const_exprs)]
|
= help: remove one of these features
error[E0284]: type annotations needed: cannot satisfy `the constant `name_len::<T>()` can be evaluated`
error[E0275]: overflow evaluating the requirement `&T: ~const ConstName`
--> $DIR/issue-88119.rs:19:49
|
LL | impl<T: ?Sized + ConstName> const ConstName for &T
| ^^
error[E0275]: overflow evaluating the requirement `&T: ConstName`
--> $DIR/issue-88119.rs:19:49
|
LL | impl<T: ?Sized + ConstName> const ConstName for &T
| ^^
error[E0275]: overflow evaluating the requirement `[(); name_len::<T>()] well-formed`
--> $DIR/issue-88119.rs:21:5
|
LL | [(); name_len::<T>()]:,
| ^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `name_len::<T>()` can be evaluated`
| ^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `<&T as ConstName>`
--> $DIR/issue-88119.rs:21:5
|
LL | [(); name_len::<T>()]:,
| ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<&T as ConstName>`
error[E0275]: overflow evaluating the requirement `[(); name_len::<T>()] well-formed`
--> $DIR/issue-88119.rs:21:10
|
LL | [(); name_len::<T>()]:,
| ^^^^^^^^^^^^^^^ required by this bound in `<&T as ConstName>`
| ^^^^^^^^^^^^^^^
|
note: required by a bound in `<&T as ConstName>`
--> $DIR/issue-88119.rs:21:5
|
LL | [(); name_len::<T>()]:,
| ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<&T as ConstName>`
error[E0284]: type annotations needed: cannot satisfy `the constant `name_len::<T>()` can be evaluated`
error[E0275]: overflow evaluating the requirement `&mut T: ~const ConstName`
--> $DIR/issue-88119.rs:26:49
|
LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
| ^^^^^^
error[E0275]: overflow evaluating the requirement `&mut T: ConstName`
--> $DIR/issue-88119.rs:26:49
|
LL | impl<T: ?Sized + ConstName> const ConstName for &mut T
| ^^^^^^
error[E0275]: overflow evaluating the requirement `[(); name_len::<T>()] well-formed`
--> $DIR/issue-88119.rs:28:5
|
LL | [(); name_len::<T>()]:,
| ^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `name_len::<T>()` can be evaluated`
| ^^^^^^^^^^^^^^^^^^^^^
|
note: required by a bound in `<&mut T as ConstName>`
--> $DIR/issue-88119.rs:28:5
|
LL | [(); name_len::<T>()]:,
| ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<&mut T as ConstName>`
error[E0275]: overflow evaluating the requirement `[(); name_len::<T>()] well-formed`
--> $DIR/issue-88119.rs:28:10
|
LL | [(); name_len::<T>()]:,
| ^^^^^^^^^^^^^^^ required by this bound in `<&mut T as ConstName>`
| ^^^^^^^^^^^^^^^
|
note: required by a bound in `<&mut T as ConstName>`
--> $DIR/issue-88119.rs:28:5
|
LL | [(); name_len::<T>()]:,
| ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<&mut T as ConstName>`
error: aborting due to 3 previous errors
error[E0275]: overflow evaluating the requirement `&&mut u8: ConstName`
--> $DIR/issue-88119.rs:33:35
|
LL | pub const ICE_1: &'static [u8] = <&&mut u8 as ConstName>::NAME_BYTES;
| ^^^^^^^^
For more information about this error, try `rustc --explain E0284`.
error[E0275]: overflow evaluating the requirement `&mut &u8: ConstName`
--> $DIR/issue-88119.rs:34:35
|
LL | pub const ICE_2: &'static [u8] = <&mut &u8 as ConstName>::NAME_BYTES;
| ^^^^^^^^
error: aborting due to 11 previous errors
For more information about this error, try `rustc --explain E0275`.

View file

@ -1,4 +1,7 @@
//@ check-pass
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
struct Node<C: Trait<Self>>(C::Assoc);
trait Trait<T> {

View file

@ -0,0 +1,23 @@
error[E0275]: overflow evaluating the requirement `Vec<u8>: Trait<String>`
--> $DIR/item-bound-via-impl-where-clause.rs:31:21
|
LL | let s: String = transmute::<_, String>(vec![65_u8, 66, 67]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required for `Vec<u8>` to implement `Trait<String>`
--> $DIR/item-bound-via-impl-where-clause.rs:22:12
|
LL | impl<L, R> Trait<R> for L
| ^^^^^^^^ ^
LL | where
LL | L: Trait<R>,
| -------- unsatisfied trait bound introduced here
note: required by a bound in `transmute`
--> $DIR/item-bound-via-impl-where-clause.rs:29:17
|
LL | fn transmute<L: Trait<R>, R>(r: L) -> <L::Proof as Trait<R>>::Proof { r }
| ^^^^^^^^ required by this bound in `transmute`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0275`.

View file

@ -0,0 +1,49 @@
error[E0275]: overflow evaluating the requirement `Vec<u8>: Trait<String>`
--> $DIR/item-bound-via-impl-where-clause.rs:31:33
|
LL | let s: String = transmute::<_, String>(vec![65_u8, 66, 67]);
| ^
|
note: required by a bound in `transmute`
--> $DIR/item-bound-via-impl-where-clause.rs:29:17
|
LL | fn transmute<L: Trait<R>, R>(r: L) -> <L::Proof as Trait<R>>::Proof { r }
| ^^^^^^^^ required by this bound in `transmute`
error[E0275]: overflow evaluating the requirement `<<Vec<u8> as Trait<String>>::Proof as Trait<String>>::Proof == _`
--> $DIR/item-bound-via-impl-where-clause.rs:31:21
|
LL | let s: String = transmute::<_, String>(vec![65_u8, 66, 67]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0275]: overflow evaluating the requirement `<<Vec<u8> as Trait<String>>::Proof as Trait<String>>::Proof == String`
--> $DIR/item-bound-via-impl-where-clause.rs:31:21
|
LL | let s: String = transmute::<_, String>(vec![65_u8, 66, 67]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0275]: overflow evaluating the requirement `<<Vec<u8> as Trait<String>>::Proof as Trait<String>>::Proof: Sized`
--> $DIR/item-bound-via-impl-where-clause.rs:31:21
|
LL | let s: String = transmute::<_, String>(vec![65_u8, 66, 67]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the return type of a function must have a statically known size
error[E0275]: overflow evaluating the requirement `<<Vec<u8> as Trait<String>>::Proof as Trait<String>>::Proof well-formed`
--> $DIR/item-bound-via-impl-where-clause.rs:31:21
|
LL | let s: String = transmute::<_, String>(vec![65_u8, 66, 67]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0275]: overflow evaluating the requirement `<<Vec<u8> as Trait<String>>::Proof as Trait<String>>::Proof == _`
--> $DIR/item-bound-via-impl-where-clause.rs:31:21
|
LL | let s: String = transmute::<_, String>(vec![65_u8, 66, 67]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0275`.

View file

@ -0,0 +1,39 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
// A variation of #135246 where the cyclic bounds are part of
// the impl instead of the impl associated item.
trait Trait<R>: Sized {
type Proof: Trait<R, Proof = Self>;
}
// We need to use indirection here as we otherwise normalize
// `<L::Proof as Trait<R>>::Proof` before recursing into
// `R: Trait<R, Proof = <L::Proof as Trait<R>>::Proof>`.
trait Indir<L: Trait<R>, R>: Trait<R, Proof = <L::Proof as Trait<R>>::Proof> {}
impl<L, R> Indir<L, R> for R
where
L: Trait<R>,
R: Trait<R, Proof = <L::Proof as Trait<R>>::Proof>,
{}
impl<L, R> Trait<R> for L
where
L: Trait<R>,
R: Indir<L, R>,
{
type Proof = R;
}
fn transmute<L: Trait<R>, R>(r: L) -> <L::Proof as Trait<R>>::Proof { r }
fn main() {
let s: String = transmute::<_, String>(vec![65_u8, 66, 67]);
//~^ ERROR overflow evaluating the requirement `Vec<u8>: Trait<String>`
//[next]~| ERROR overflow evaluating the requirement `<<Vec<u8> as Trait<String>>::Proof as Trait<String>>::Proof == _`
//[next]~| ERROR overflow evaluating the requirement `<<Vec<u8> as Trait<String>>::Proof as Trait<String>>::Proof == String`
//[next]~| ERROR overflow evaluating the requirement `<<Vec<u8> as Trait<String>>::Proof as Trait<String>>::Proof: Sized`
//[next]~| ERROR overflow evaluating the requirement `<<Vec<u8> as Trait<String>>::Proof as Trait<String>>::Proof well-formed`
//[next]~| ERROR overflow evaluating the requirement `<<Vec<u8> as Trait<String>>::Proof as Trait<String>>::Proof == _`
println!("{}", s); // ABC
}

View file

@ -0,0 +1,10 @@
error[E0391]: cycle detected when computing layout of `<[Hello] as Normalize>::Assoc`
|
= note: ...which requires computing layout of `Hello`...
= note: ...which again requires computing layout of `<[Hello] as Normalize>::Assoc`, completing the cycle
= note: cycle used when computing layout of `Hello`
= 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 1 previous error
For more information about this error, try `rustc --explain E0391`.

View file

@ -1,6 +1,10 @@
// Regression test for #129541
//~^ ERROR cycle detected when computing layout of `<[Hello] as Normalize>::Assoc` [E0391]
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
trait Bound {}
trait Normalize {
type Assoc;

View file

@ -1,6 +1,9 @@
// Regression test for #129541
//@ revisions: unique multiple
//@ revisions: unique_curr unique_next multiple_curr multiple_next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[unique_next] compile-flags: -Znext-solver
//@[multiple_next] compile-flags: -Znext-solver
//@ error-pattern: reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
trait Bound {}
@ -8,7 +11,7 @@ trait Normalize {
type Assoc;
}
#[cfg(multiple)]
#[cfg(any(multiple_curr, multiple_next))]
impl<T: Bound> Normalize for T {
type Assoc = T;
}

View file

@ -0,0 +1,6 @@
error: reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]`
error: aborting due to 1 previous error

View file

@ -0,0 +1,6 @@
error: reached the recursion limit finding the struct tail for `<[Hello] as Normalize>::Assoc`
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]`
error: aborting due to 1 previous error