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`
This commit is contained in:
commit
ae92125a75
11 changed files with 122 additions and 2 deletions
|
@ -698,6 +698,18 @@ where
|
||||||
if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
|
if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
} else {
|
} 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)
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -432,6 +432,7 @@ pub trait Predicate<I: Interner<Predicate = Self>>:
|
||||||
+ UpcastFrom<I, ty::OutlivesPredicate<I, I::Ty>>
|
+ UpcastFrom<I, ty::OutlivesPredicate<I, I::Ty>>
|
||||||
+ UpcastFrom<I, ty::OutlivesPredicate<I, I::Region>>
|
+ UpcastFrom<I, ty::OutlivesPredicate<I, I::Region>>
|
||||||
+ IntoKind<Kind = ty::Binder<I, ty::PredicateKind<I>>>
|
+ IntoKind<Kind = ty::Binder<I, ty::PredicateKind<I>>>
|
||||||
|
+ Elaboratable<I>
|
||||||
{
|
{
|
||||||
fn as_clause(self) -> Option<I::Clause>;
|
fn as_clause(self) -> Option<I::Clause>;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ LL |
|
||||||
LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
|
LL | impl<S: Iterator> MyTrait<S> for (Box<<(MyType,) as Mirror>::Assoc>, S::Item) {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(Box<(MyType,)>, <_ as Iterator>::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
|
= 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
|
error: aborting due to 1 previous error
|
||||||
|
|
|
@ -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,)>,
|
//~^ ERROR conflicting implementations of trait `MyTrait<_>` for type `(Box<(MyType,)>,
|
||||||
//~| NOTE conflicting implementation for `(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
|
//~| 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() {}
|
fn main() {}
|
||||||
|
|
|
@ -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`.
|
19
tests/ui/coherence/super-traits/super-trait-knowable-1.rs
Normal file
19
tests/ui/coherence/super-traits/super-trait-knowable-1.rs
Normal file
|
@ -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() {}
|
33
tests/ui/coherence/super-traits/super-trait-knowable-2.rs
Normal file
33
tests/ui/coherence/super-traits/super-trait-knowable-2.rs
Normal file
|
@ -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() {}
|
|
@ -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`.
|
22
tests/ui/coherence/super-traits/super-trait-knowable-3.rs
Normal file
22
tests/ui/coherence/super-traits/super-trait-knowable-3.rs
Normal file
|
@ -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() {}
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0119]: conflicting implementations of trait `Clone` for type `Node<[_]>`
|
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)]
|
LL | #[derive(Clone)]
|
||||||
| ^^^^^ conflicting implementation for `Node<[_]>`
|
| ^^^^^ conflicting implementation for `Node<[_]>`
|
|
@ -1,7 +1,12 @@
|
||||||
// Regression test for #48728, an ICE that occurred computing
|
// Regression test for #48728, an ICE that occurred computing
|
||||||
// coherence "help" information.
|
// 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>);
|
struct Node<T: ?Sized>(Box<T>);
|
||||||
|
|
||||||
impl<T: Clone + ?Sized> Clone for Node<[T]> {
|
impl<T: Clone + ?Sized> Clone for Node<[T]> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue