about summary refs log tree commit diff
diff options
context:
space:
mode:
authorlcnr <rust@lcnr.de>2024-07-10 16:03:20 +0200
committerlcnr <rust@lcnr.de>2024-07-10 16:16:48 +0200
commitfe0bd76a8bdb80f4460dd59612076cf91370f7a1 (patch)
treeb8e4f4e9a0e3f8d1172ff590656adfb13c35ddee
parent0fdfb61795b40037955154638fe35f20b16c8e55 (diff)
downloadrust-fe0bd76a8bdb80f4460dd59612076cf91370f7a1.tar.gz
rust-fe0bd76a8bdb80f4460dd59612076cf91370f7a1.zip
elaborate unknowable goals
if a trait is unknowable, but its super trait
is definitely not implemented, then the trait
itself is definitely also not implemented.
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs12
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs1
-rw-r--r--tests/ui/coherence/normalize-for-errors.next.stderr1
-rw-r--r--tests/ui/coherence/normalize-for-errors.rs1
-rw-r--r--tests/ui/coherence/super-traits/super-trait-knowable-1.current.stderr13
-rw-r--r--tests/ui/coherence/super-traits/super-trait-knowable-1.rs19
-rw-r--r--tests/ui/coherence/super-traits/super-trait-knowable-2.rs33
-rw-r--r--tests/ui/coherence/super-traits/super-trait-knowable-3.current.stderr13
-rw-r--r--tests/ui/coherence/super-traits/super-trait-knowable-3.rs22
-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.rs7
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 01dde9ca587..4e1a3558a9c 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -699,6 +699,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 de86a8536f7..2b6ccc8e430 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -433,6 +433,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]> {