Rust fails to see that type is local?

I am implementing the trait From for a local type taking a not-local parameter. This should work, as there is a guarantee of trait coherence. No other crate can implement this, as the type I am using is local.

Is what I am seeing a Rust compiler limitation, or am I wrong in thinking that this should compile?

#![feature(zero_one)]

use std::num::Zero;

pub struct MyInt<S: Zero> {
    _x: S
}

impl<S: Zero> From<MyInt<S>> for [S; 6] {
    fn from(_n: MyInt<S>) -> Self {
        panic!()
    }
}

fn main() {}

You can test the code in the Rust playpen.

It seems you can't implement for [S; 6]. I tried to wrap this into a tuple struct and now it compiles.

pub struct List<S: Zero>(pub [S; 6]);

impl<T: Zero> From<MyInt<T>> for List<T> {
    fn from(n: MyInt<T>) -> List<T> {
        unimplemented!()
    }
}

For this particular case, I would recommend implementing Into<[S; 6]> for MyInt<S> instead. This is one case where Into is useful to implement manually (instead of implementing From): Rust Playground.

I'm not sure whether or not implementing From actually should be valid - but in any case, implementing Into instead does work.

1 Like

Rust's orphan rules are unfortunately quite a complex problem. Even having read about them a lot, I'm not at all sure whether or not your impl should be accepted.

1 Like

Indeed, From<MyInt<S>> shouldn't be implemented for [S; 6]. Taking an example from the article about orphan rules, this wouldn't be accepted:

struct MyHeader<T> { }
...
impl<T> Modifier<MyHeader<T>> for Vec<T> { }

Because T comes first regarding to Response, which is a local type.

So, doing this:

impl<S: Zero> From<MyInt<S>> for [S; 6] {  }

Seems to be the same problem: you're actually creating this S (which could be an external type), then putting it in MyInt<_> (which is OK, due to the covering) and then trying to implement it for [S; 6] (which too could be an external type).

S is covered by MyInt though so as I own what I am implementing it should work?

The problem is that S comes first, and you're trying to implement From<MyInt<S>> for [S; 6]. It should work if you implement From<[S; 6]> for MyInt<S>, due to the ordering.

Anyway, you can try to implement Into<[S; 6]> for MyInt, so that you get a From implementation too (but .into() does exactly what you want).

edit: Implementing Into instead of From was mentioned earlier, btw.

1 Like

Implementing Into doesn't seem to provide a From implement. I have errors saying From<T> isn't implemented for U while I do have Into<U> implemented for T.

1 Like

It doesn't. There is a blanket impl<A, B> Into<A> for B where A: From<B> {...} however, the reverse doesn't exist. As a matter of fact, the reverse would be impossible without specialization.

1 Like

@stebalien
Oh, sorry. I didn't know about that.

@Binero
Well, at least Into<[S; 6]> for MyInt<S> does the job as well.