Adding a specialized impl can break inference.
Relevant to #31844. This is how it happens:
#![feature(specialization)]
trait B { fn b(&self) -> Self; }
// Impl 1
impl<T> B for Option<T> where T: Default
{
default fn b(&self) -> Option<T> { Some(T::default()) }
}
// Removing one of the two concrete impls makes inference succeed.
// Impl 2
impl B for Option<String>
{
fn b(&self) -> Self { Some("special".into()) }
}
// Impl 3
impl B for Option<i32>
{
fn b(&self) -> Self { Some(0) }
}
fn main() {
// Cannot infer `T` in `Option<T>`.
None.b();
}
This issue does not originate from specialization, since if we removed Impl 1 the same problem would occur. But with specialization if those impls were added in order, the story would be a bit confusing:
- With
Impl 1, inference fails. - Added
Impl 2, yay inference succeeds. - Added
Impl 3, inference is back to failing.
The only fix would be to make inference fail in step 2. Even if it's not something we want fix it still seems worth noting somewhere that we are ok with specializaton breaking inference.
Is this the same issue that's causing this error? https://github.com/rust-lang/rust/pull/51464#issuecomment-396008009
There used to be a bunch of specific impls for
SliceIndexfor various types. That PR adds a default impl (so the old specific impls are now specializations of the default impl). The error in question is a test case that used to pass that now fails inference.Joshua Liebow-Feeser at 2018-06-10 04:01:20
I'm running into this when playing around with stdlib. For a type that accepts either
i32or any other integer type, inference fails because the compiler sees thati32is a valid option and automatically chooses that without actually trying to solve the inference.Jacob Pratt at 2021-04-01 08:13:37