Specialization influnces inference
STR
#![feature(specialization)]
struct My<T>(T);
trait Conv<T> {
fn conv(self) -> T;
}
impl<T> Conv<T> for My<T> {
default fn conv(self) -> T { self.0 }
}
#[cfg(broken)]
impl Conv<u32> for My<u32> {
default fn conv(self) -> u32 { self.0 }
}
fn main() {
let x = My(0);
x.conv() + 0i32;
}
Expected Result
Adding a specialized impl will not affect type inference.
Actual Result
After adding the specialized impl, inference is guided to take it:
error[E0308]: mismatched types
--> <anon>:20:16
|
20 | x.conv() + 0i32;
| ^^^^ expected u32, found i32
error[E0277]: the trait bound `u32: std::ops::Add<i32>` is not satisfied
--> <anon>:20:5
|
20 | x.conv() + 0i32;
| ^^^^^^^^^^^^^^^ trait `u32: std::ops::Add<i32>` not satisfied
|
= help: the following implementations were found:
= help: <u32 as std::ops::Add>
= help: <&'a u32 as std::ops::Add<u32>>
= help: <u32 as std::ops::Add<&'a u32>>
= help: <&'b u32 as std::ops::Add<&'a u32>>
error: aborting due to 2 previous errors
cc @aturon @nikomatsakis
Another example:
#![feature(specialization)] use std::marker::PhantomData; trait Trait { type A; type B; fn foo(&self, a: Self::A, b: Self::B); } struct Foo<A, B> { a: PhantomData<A>, b: PhantomData<B>, } impl<A, B> Foo<A, B> { fn new() -> Self { Foo { a: PhantomData, b: PhantomData, } } } impl<A, B> Trait for Foo<A, B> { type A = A; type B = B; default fn foo(&self, _: A, _: B) { println!("default impl"); } } // Specialized impl<A, B: Eq> Trait for Foo<A, B> { fn foo(&self, _: A, _: B) { println!("specialized"); } } fn main() { let a = "a"; let b = "b"; let f = Foo::new(); // Need to specify concrete type here to compile f.foo(a, b); }Mark Rousskov at 2017-05-13 04:19:38
I don't have an sscce, but I produced this small patch for the current master branch of rust, which breaks type inference regarding specialization of iterators. The interesting thing is, if I don't directly specialize the iterator, but instead create a new trait which I specialize, it compiles just fine. The patch for this can be found here.
Jaro Fietz at 2017-12-20 22:12:51
I have a patch specializing
SliceConcatExt<T>forT: Copywhich causes type inference to fail on a call to concat inside rustc. It happens even if I don't actually specialize anything. If I delete the empty impl block and leave the general impl block as-is, including thedefaults, it works. Just the existence of the specializing impl block is enough to break it.Edit: I've misinterpreted the issue. Explanation at the end
// general block impl<T: Clone, V: Borrow<[T]>> SliceConcatExt<T> for [V] { type Output = Vec<T>; default fn concat(&self) -> Vec<T> { ... } /* other methods */ } // specializing block impl<T: Copy, V: Borrow<[T]>> SliceConcatExt<T> for [V] { /* empty */ }The call where inference breaks is src/librustc_typeck/collect.rs Line 1299
The error is:
type annotations required: cannot resolve `<[&[rustc::ty::Predicate<'_>]] as std::slice::SliceConcatExt<_>>::Output == std::vec::Vec<rustc::ty::Predicate<'_>>`~Previously only one impl of
SliceConcatExt<T>could produce aVec<_>. With the specialization it's two, but one is a subset of the other.~Edit: Actually, the issue has not to do with the associated type but with the generic
T.concathas no information aboutT.joinhas aTseparator parameter and does not have the inference problem but concat could work for anyTfor whichV: Borrow<[T]>. That genericity might require one to add a turbofish but in that case above in the stdlib, it was not necessary. The specialization should not change that.Emerentius at 2018-05-12 23:29:34