Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specialization works only if type annotation is provided #67918

Open
kdy1 opened this issue Jan 6, 2020 · 1 comment
Open

Specialization works only if type annotation is provided #67918

kdy1 opened this issue Jan 6, 2020 · 1 comment
Labels
F-specialization `#![feature(specialization)]`

Comments

@kdy1
Copy link
Contributor

kdy1 commented Jan 6, 2020

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);
}
@csmoe csmoe added the F-specialization `#![feature(specialization)]` label Jan 6, 2020
@LastExceed
Copy link
Contributor

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
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-specialization `#![feature(specialization)]`
Projects
None yet
Development

No branches or pull requests

3 participants