"unconstrained type parameter" but appears in self type

I was trying to implement the VecFamily of Generalizing over Generics in Rust (Part 1) - AKA Higher Kinded Types in Rust | Rusty Yato. I got stumped however due to an "unconstrained type parameter" error. Here's the minimal example:

pub trait MyType<A> {
    type This;
}

// adding the type parameter to MyStruct produces the same error
struct MyStruct/*<A>(PhantomData<A>)*/;

impl<A> MyType<A> for MyStruct { // removing this impl
    type This = A;               // produces the same error
}                                //

trait MyTrait { }

impl<A> MyTrait for <MyStruct/*<A>*/ as MyType<A>>::This { }

In the last line it looks like there is an <A> in the self type, which should fit the 2nd inference rule of rfcs/0447-no-unused-impl-parameters.md at master · rust-lang/rfcs · GitHub. Where's the rub?

Maybe you could also post your code that’s trying to implement VecFamily instead of just a “minimal example”?

Your MyTrait implementation does have an unconstrained type parameter A. In particular, it is problematic because different This types could refer to the same type, so that you’d get conflicting trait implementations. I am however not sure, how MyTrait fits into the picture of VecFamily, hence the request to post the non-“minimized” example :wink:

I guess, in this particular “minized example” code, the definition of This is known, and it’s more of a limitation or somewhat artificial restriction of Rusts type system to not accept your code. Since <MyStruct as MyType<A>>::This pretty much A, you might as well write A directly, e.g.

impl<A> MyTrait for A { }

but I’m not sure if this “fix” translates in any reasonable form to your actual code for approaching VecFamily.

1 Like

Depending on what's going on inside the impl, you might need to add a where clause to ensure MyStruct can be used inside it:

impl<A> MyTrait for A
where
    MyStruct/*<A>*/: MyType<A, This=A>
{ }

Sure, anyways, as I was trying to implicitly say, this question screams XY Problem since the right VecFamily implementation should not run into any problems such as this in the first place.

And I’m not going to post a correct VecFamily implementation here since that would defeat the purpose of the exercise. Waiting for OP’s incorrect solution to get posted, and then hinting at where/what the mistake might be seems like the most reasonable thing to do.

Edit: Just noticing that this thread might not actually be about OP having problems with that exercise but just trying to understand the details of why Rust doesn’t just figure out that <MyStruct as MyType<A>>::This is A and accepts the code.

1 Like

Thanks for not giving away the solution, I'll start a different topic if I give up :slight_smile:. Indeed this question is about this particular error and not to ask for a solution to the exercise, sorry if that much wasn't clear.

In particular, it is problematic because different This types could refer to the same type, so that you’d get conflicting trait implementations.

Is the following a good example where such a conflict arises?

pub trait MyType<A> {
    type This;
}

struct StructA;

impl<A> MyType<A> for StructA {
    type This = A;
}

struct StructB;

impl<A> MyType<A> for StructB {
    type This = A;
}

trait MyTrait {
    fn fun();
}

impl<A> MyTrait for <StructA as MyType<A>>::This {
    fn fun() {
        println!("foo");
    }
}

impl<A> MyTrait for <StructB as MyType<A>>::This {
    fn fun() {
        println!("bar");
    }
}

Also, why exactly doesn't the 2nd inference rule of the RFC apply here?

If T appears in the impl self type,
then: T is constrained

I'm sure I can see an A in <MyStruct as MyType<A>>::This, so I guess I'm either not reading the rule correctly, or the rule is not exact.

I think the error message is misleading, but note that these two impls definitely overlap:

impl<A> MyTrait for <StructA as MyType<A>>::This {
impl<A> MyTrait for <StructB as MyType<A>>::This {

since they both implement MyTrait for all types A.

In case you’re still running into problems, try following the OptionFamily example more closely, just replacing “Option” with “Vec:wink:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.