Description
So I seem to have found an error in the type checking for specialization impls when using trait alias bounds
Specifically, this code:
#![feature(specialization)]
#![feature(trait_alias)]
pub trait Marker1<T> {}
pub trait Marker2 {}
pub trait CombinedMarker<T> = Marker1<T> + Marker2;
pub struct Container<T,U> { p: std::marker::PhantomData<(T,U)> }
pub struct Struct;
impl<T> Marker1<T> for Struct {}
pub trait Trait { fn do_thing(&self); }
impl<T, U:Marker1<T>> Trait for Container<T,U> {
default fn do_thing(&self) { println!("default behavior"); }
}
impl<T, U:CombinedMarker<T>> Trait for Container<T,U> {
default fn do_thing(&self) { println!("partially specialized behavior"); }
}
impl<T> Trait for Container<T,Struct> {
fn do_thing(&self) { println!("fully specialized behavior") }
}
gives a type error with output of:
warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
--> src/main.rs:1:12
|
1 | #![feature(specialization)]
| ^^^^^^^^^^^^^^
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
error[E0119]: conflicting implementations of trait `Trait` for type `Container<_, Struct>`:
--> src/main.rs:51:1
|
47 | impl<T, U:CombinedMarker<T>> Trait for Container<T,U> {
| ----------------------------------------------------- first implementation here
...
51 | impl<T> Trait for Container<T,Struct> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Container<_, Struct>`
error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0119`.
However, if you change the bound on the impl
s from CombinedMarker<T>
to Marker1<T>+Marker2
or CombinedMarker<T>+Marker2
it actually compiles, seemingly suggesting that the compiler isn't accurately translating the trait alias over to the bound since all three of those should be equivalent.
Also, before you ask, yes, for some reason, the <T>
generic on Marker1
does seem to have an effect, as if it is removed, both the aliased and non-aliased versions compile. Furthermore, the Container<T>
struct also seems to be important since removing it also fixed the type error.
Finally, for reference, my rustc is on this version:
rustc 1.47.0-nightly (6c8927b0c 2020-07-26)
binary: rustc
commit-hash: 6c8927b0cf80ceee19386026cf9d7fd4fd9d486f
commit-date: 2020-07-26
host: x86_64-unknown-linux-gnu
release: 1.47.0-nightly
LLVM version: 10.0