Does the selected method when using specialization is wrong?


#1

Playing with (play link) code posted on stack overflow i got a strange result.

I understand that it is not possible to specialize on lifetimes, but this seems to be another problem.

In case 2 the MyString::from implementation selected (impl 2) requires Into<&'static str>, but &'a str does not implement it. If the other (impl 1, less restricted) implementation was chosen, the code should compile.

What I’m missing here?

#![feature(specialization)]

use std::borrow::Cow;

struct MyString {
    inner: Cow<'static, str>,
}

// impl 1
impl<T: Into<String>> From<T> for MyString {
    default fn from(x: T) -> Self {
        MyString { inner: Cow::Owned(x.into()) }
    }
}

// impl 2
impl<T: Into<String> + Into<&'static str>> From<T> for MyString {
    fn from(x: T) -> Self {
        MyString { inner: Cow::Borrowed(x.into()) }
    }
}

fn main() {
    // case 1
    match MyString::from("foo").inner {
        Cow::Borrowed(..) => (),
        _ => { panic!(); }
    }

    // case 2
    let s = String::from("bar");
    let r = s.as_ref();
    match MyString::from(r).inner {
        Cow::Owned(..) => (),
        _ => { panic!(); }
    }   

    // case 3
    match MyString::from(String::from("qux")).inner {
        Cow::Owned(..) => (),
        _ => { panic!(); }
    }
}

#2

Since &'a str implements Into<&'a str>, if you ignore lifetimes the second implementation matches any &str. So arguably you are trying to specialize on lifetimes?


#3

Specialization will not allow dispatching based on lifetimes, according to the RFC