Open
Description
The following compiles but should not
use std::marker::Unpin;
fn is_unpin<T: Unpin>() {}
trait OtherTrait {
type Assoc
where
Self: Unpin;
}
struct LocalTy;
impl Unpin for LocalTy
where
Self: OtherTrait<Assoc = LocalTy>,
{}
impl<T> OtherTrait for T {
type Assoc = T
where
Self: Unpin;
}
fn main() {
is_unpin::<LocalTy>()
}
proving LocalTy: Unpin
results in the following cycle:
LocalTy: Unpin
LocalTy: OtherTrait
(trivially true)<LocalTy as OtherTrait>::Assoc = LocalTy
LocalTy: Unpin
(cycle!)
While it's sound for this cycle to be coinductive, with our current rules it should not be. The new solver will also start out with this being inductive. Fulfill correctly detects this as an inductive cycle. Evaluate does not.
Note that using that is incredibly fragile as it depends on the following performance optimization to avoid fulfill:
rust/compiler/rustc_trait_selection/src/traits/fulfill.rs
Lines 604 to 614 in cce9e72
So the following code does result in the expected error 😁
use std::marker::Unpin;
fn is_unpin<T: Unpin>() {}
trait OtherTrait {
type Assoc
where
Self: Unpin;
}
struct LocalTy<'a>(&'a ());
impl<'a> Unpin for LocalTy<'a>
where
Self: OtherTrait<Assoc = LocalTy<'a>>,
{}
impl<T> OtherTrait for T {
type Assoc = T
where
Self: Unpin;
}
fn main() {
is_unpin::<LocalTy<'static>>()
}
error[E0275]: overflow evaluating the requirement `LocalTy<'_>: OtherTrait`
--> src/main.rs:12:10
|
12 | impl<'a> Unpin for LocalTy<'a>
| ^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`test1`)
note: required for `LocalTy<'_>` to implement `Unpin`
--> src/main.rs:12:10
|
12 | impl<'a> Unpin for LocalTy<'a>
| ^^^^^ ^^^^^^^^^^^
note: required by a bound in `OtherTrait::Assoc`
--> src/main.rs:8:15
|
6 | type Assoc
| ----- required by a bound in this
7 | where
8 | Self: Unpin;
| ^^^^^ required by this bound in `OtherTrait::Assoc`