Specialization works only if type annotation is provided
kdy1 opened this issue · 1 comments
kdy1 commented
Playground link: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=a26a9e2af3acda5b9911458a6f54a72d
This trait implementation
impl<T, V, O, E> Validate<[T]> for V
where
Self: Validate<T, Output = Result<O, E>>,
{
type Output = Result<Vec<O>, E>;
fn validate(&mut self, nodes: &[T]) -> Self::Output {
nodes.iter().map(|node| self.validate(node)).collect()
}
}does not like a method defined as
impl Analyzer {
/// Validates and store errors if required.
pub fn check<T, O>(&mut self, node: &T) -> Option<O>
where
Self: Validate<T, Output = Result<O, Error>>,
{
let res: Result<O, _> = self.validate(node);
match res {
Ok(v) => Some(v),
Err(..) => {
// handle error
None
}
}
}
}However, it works if type annotation is provided
fn main() {
let mut a = Analyzer;
let expr = Expr;
// Uncomment this to see impl for [T] explodes
// a.check(&expr);
// This works without error
a.check::<Expr, ()>(&expr);
}LastExceed commented
further isolated:
as soon as any specialization exists, type inference coerces everything thats covered by the blanket default impl to that specialization, regardless of compatibility. workaround is to avoid type inference via explicit type annotation
#![feature(min_specialization)]
trait Consume<T> {
fn consume(_: T);
}
//blanket default impl without any specializations
struct Consumer1;
impl<T> Consume<T> for Consumer1 {
default fn consume(_: T) {
//...
}
}
//blanket default impl with 1 specialization
struct Consumer2;
impl<T> Consume<T> for Consumer2 {
default fn consume(_: T) {
//...
}
}
impl Consume<i32> for Consumer2 {
fn consume(_: i32) {
//...
}
}
fn main() {
Consumer1::consume(true); //ok
Consumer1::consume(42); //ok
Consumer2::consume(true); //error: expected `i32`, found `bool`
Consumer2::consume(42); //ok
//workaround:
<Consumer2 as Consume<bool>>::consume(true); //ok
}