diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-07-30 04:31:54 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-30 04:31:54 +0200 |
| commit | ae92125a75e9bab924d2b79703bf3ecec2107bf5 (patch) | |
| tree | 797993018bc2614c97b10b8ae559f6eb52777c74 | |
| parent | 368e2fd458a22d0cc133d0c254f2612ee999744f (diff) | |
| parent | fe0bd76a8bdb80f4460dd59612076cf91370f7a1 (diff) | |
| download | rust-ae92125a75e9bab924d2b79703bf3ecec2107bf5.tar.gz rust-ae92125a75e9bab924d2b79703bf3ecec2107bf5.zip | |
Rollup merge of #127574 - lcnr:coherence-check-supertrait, r=compiler-errors
elaborate unknowable goals
A reimplemented version of #124532 affecting only the new solver. Always trying to prove super traits ends up causing a fatal overflow error in diesel, so we cannot land this in the old solver.
The following test currently does not pass coherence:
```rust
trait Super {}
trait Sub<T>: Super {}
trait Overlap<T> {}
impl<T, U: Sub<T>> Overlap<T> for U {}
impl<T> Overlap<T> for () {}
fn main() {}
```
We check whether `(): Sub<?t>` holds. This stalls with ambiguity as downstream crates may add an impl for `(): Sub<Local>`. However, its super trait bound `(): Super` cannot be implemented downstream, so this one is known not to hold.
By trying to prove that all the super bounds of a trait before adding a coherence unknowable candidate, this compiles. This is necessary to prevent breakage from enabling `-Znext-solver=coherence` (#121848), see tests/ui/coherence/super-traits/super-trait-knowable-2.rs for more details. The idea is that while there may be an impl of the trait itself we don't know about, if we're able to prove that a super trait is definitely not implemented, then that impl would also never apply/not be well-formed.
This approach is different from #124532 as it allows tests/ui/coherence/super-traits/super-trait-knowable-3.rs to compile. The approach in #124532 only elaborating the root obligations while this approach tries it for all unknowable trait goals.
r? `@compiler-errors`
| -rw-r--r-- | compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_type_ir/src/inherent.rs | 1 | ||||
| -rw-r--r-- | tests/ui/coherence/normalize-for-errors.next.stderr | 1 | ||||
| -rw-r--r-- | tests/ui/coherence/normalize-for-errors.rs | 1 | ||||
| -rw-r--r-- | tests/ui/coherence/super-traits/super-trait-knowable-1.current.stderr | 13 | ||||
| -rw-r--r-- | tests/ui/coherence/super-traits/super-trait-knowable-1.rs | 19 | ||||
| -rw-r--r-- | tests/ui/coherence/super-traits/super-trait-knowable-2.rs | 33 | ||||
| -rw-r--r-- | tests/ui/coherence/super-traits/super-trait-knowable-3.current.stderr | 13 | ||||
| -rw-r--r-- | tests/ui/coherence/super-traits/super-trait-knowable-3.rs | 22 | ||||
| -rw-r--r-- | tests/ui/issues/issue-48728.current.stderr (renamed from tests/ui/issues/issue-48728.stderr) | 2 | ||||
| -rw-r--r-- | tests/ui/issues/issue-48728.rs | 7 |
11 files changed, 122 insertions, 2 deletions
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 4aba7ab5e61..84921e87fb3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -698,6 +698,18 @@ where if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? { Err(NoSolution) } else { + // While the trait bound itself may be unknowable, we may be able to + // prove that a super trait is not implemented. For this, we recursively + // prove the super trait bounds of the current goal. + // + // We skip the goal itself as that one would cycle. + let predicate: I::Predicate = trait_ref.upcast(cx); + ecx.add_goals( + GoalSource::Misc, + elaborate::elaborate(cx, [predicate]) + .skip(1) + .map(|predicate| goal.with(cx, predicate)), + ); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } }, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 63ad36efc85..e1a3764fa76 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -432,6 +432,7 @@ pub trait Predicate<I: Interner<Predicate = Self>>: + UpcastFrom<I, ty::OutlivesPredicate<I, I::Ty>> + UpcastFrom<I, ty::OutlivesPredicate<I, I::Region>> + IntoKind<Kind = ty::Binder<I, ty::PredicateKind<I>>> + + Elaboratable<I> { fn as_clause(self) -> Option<I::Clause>; diff --git a/tests/ui/coherence/normalize-for-errors.next.stderr b/tests/ui/coherence/normalize-for-errors.next.stderr index 6c56a917741..634a10b7a14 100644 --- a/tests/ui/coherence/normalize-for-errors.next.stderr +++ b/tests/ui/coherence/normalize-for-errors.next.stderr @@ -7,6 +7,7 @@ LL | LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, <_ as Iterator>::Item)` | + = note: upstream crates may add a new impl of trait `std::clone::Clone` for type `(MyType,)` in future versions = note: upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions error: aborting due to 1 previous error diff --git a/tests/ui/coherence/normalize-for-errors.rs b/tests/ui/coherence/normalize-for-errors.rs index 2288118676a..4188389a3ad 100644 --- a/tests/ui/coherence/normalize-for-errors.rs +++ b/tests/ui/coherence/normalize-for-errors.rs @@ -18,5 +18,6 @@ impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {} //~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>, //~| NOTE conflicting implementation for `(Box<(MyType,)>, //~| NOTE upstream crates may add a new impl of trait `std::marker::Copy` for type `std::boxed::Box<(MyType,)>` in future versions +//[next]~| NOTE upstream crates may add a new impl of trait `std::clone::Clone` for type `(MyType,)` in future versions fn main() {} diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-1.current.stderr b/tests/ui/coherence/super-traits/super-trait-knowable-1.current.stderr new file mode 100644 index 00000000000..fb01cf158d9 --- /dev/null +++ b/tests/ui/coherence/super-traits/super-trait-knowable-1.current.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Overlap<_>` for type `()` + --> $DIR/super-trait-knowable-1.rs:16:1 + | +LL | impl<T, U: Sub<T>> Overlap<T> for U {} + | ----------------------------------- first implementation here +LL | impl<T> Overlap<T> for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` + | + = note: downstream crates may implement trait `Sub<_>` for type `()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-1.rs b/tests/ui/coherence/super-traits/super-trait-knowable-1.rs new file mode 100644 index 00000000000..80df8c19ee5 --- /dev/null +++ b/tests/ui/coherence/super-traits/super-trait-knowable-1.rs @@ -0,0 +1,19 @@ +// Added in #124532. While `(): Super` is knowable, `(): Sub<?t>` is not. +// +// We therefore elaborate super trait bounds in the implicit negative +// overlap check. + +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + +trait Super {} +trait Sub<T>: Super {} + +trait Overlap<T> {} +impl<T, U: Sub<T>> Overlap<T> for U {} +impl<T> Overlap<T> for () {} +//[current]~^ ERROR conflicting implementations + +fn main() {} diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-2.rs b/tests/ui/coherence/super-traits/super-trait-knowable-2.rs new file mode 100644 index 00000000000..d1f2e8d1c1a --- /dev/null +++ b/tests/ui/coherence/super-traits/super-trait-knowable-2.rs @@ -0,0 +1,33 @@ +// A regression test for pyella-0.1.5 which broke when +// enabling the new solver in coherence. +// +// `Tensor: TensorValue` is knowable while `Tensor: TensorOp<?t2>` +// may be implemented downstream. We previously didn't check the +// super trait bound in coherence, causing these impls to overlap. +// +// However, we did fail to normalize `<Tensor as TensorValue::Unmasked` +// which caused the old solver to emit a `Tensor: TensorValue` goal in +// `fn normalize_to_error` which then failed, causing this test to pass. + +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass + +pub trait TensorValue { + type Unmasked; +} + +trait TensorCompare<T> {} +pub trait TensorOp<T>: TensorValue {} + +pub struct Tensor; +impl<T2> TensorCompare<T2> for Tensor {} +impl<T1, T2> TensorCompare<T2> for T1 +where + T1: TensorOp<T2>, + T1::Unmasked: Sized, +{} + + +fn main() {} diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-3.current.stderr b/tests/ui/coherence/super-traits/super-trait-knowable-3.current.stderr new file mode 100644 index 00000000000..542edb8b7f6 --- /dev/null +++ b/tests/ui/coherence/super-traits/super-trait-knowable-3.current.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Overlap<_>` for type `()` + --> $DIR/super-trait-knowable-3.rs:19:1 + | +LL | impl<T, U: Bound<W<T>>> Overlap<T> for U {} + | ---------------------------------------- first implementation here +LL | impl<T> Overlap<T> for () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `()` + | + = note: downstream crates may implement trait `Sub<_>` for type `()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/coherence/super-traits/super-trait-knowable-3.rs b/tests/ui/coherence/super-traits/super-trait-knowable-3.rs new file mode 100644 index 00000000000..295d7ac48d8 --- /dev/null +++ b/tests/ui/coherence/super-traits/super-trait-knowable-3.rs @@ -0,0 +1,22 @@ +// Unlike in `super-trait-knowable-1.rs`, the knowable +// super trait bound is in a nested goal so this would not +// compile if we were to only elaborate root goals. + +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + +trait Super {} +trait Sub<T>: Super {} + +struct W<T>(T); +trait Bound<T> {} +impl<T: Sub<U>, U> Bound<W<U>> for T {} + +trait Overlap<T> {} +impl<T, U: Bound<W<T>>> Overlap<T> for U {} +impl<T> Overlap<T> for () {} +//[current]~^ ERROR conflicting implementations of trait `Overlap<_>` for type `()` + +fn main() {} diff --git a/tests/ui/issues/issue-48728.stderr b/tests/ui/issues/issue-48728.current.stderr index 6b4247f1d79..2a1b4ff7818 100644 --- a/tests/ui/issues/issue-48728.stderr +++ b/tests/ui/issues/issue-48728.current.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Clone` for type `Node<[_]>` - --> $DIR/issue-48728.rs:4:10 + --> $DIR/issue-48728.rs:9:10 | LL | #[derive(Clone)] | ^^^^^ conflicting implementation for `Node<[_]>` diff --git a/tests/ui/issues/issue-48728.rs b/tests/ui/issues/issue-48728.rs index cbdc10bd2e1..7ef05f4277b 100644 --- a/tests/ui/issues/issue-48728.rs +++ b/tests/ui/issues/issue-48728.rs @@ -1,7 +1,12 @@ // Regression test for #48728, an ICE that occurred computing // coherence "help" information. -#[derive(Clone)] //~ ERROR conflicting implementations of trait `Clone` +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[next] check-pass + +#[derive(Clone)] //[current]~ ERROR conflicting implementations of trait `Clone` struct Node<T: ?Sized>(Box<T>); impl<T: Clone + ?Sized> Clone for Node<[T]> { |
