Associated type inference

Minimal Example:

pub trait RemoveT<TargetL, List> {
    type AfterRemove;

    fn remove_label(&self) -> Self::AfterRemove;}

impl<TargetL, List, T> RemoveT<TargetL, List> for T {
    type AfterRemove = Nil;

    fn remove_label(&self) -> Self::AfterRemove {

// ================================================================================ test

pub struct Foo;
pub struct Nil;

fn main () {
    let x = Vec::<i32>::new();

    let y = (x as RemoveT<Foo, Vec<i32>>).remove_label();


   Compiling playground v0.0.1 (/playground)
warning: trait objects without an explicit `dyn` are deprecated
  --> src/
20 |     let y = (x as RemoveT<Foo, Vec<i32>>).remove_label();
   |                   ^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn RemoveT<Foo, Vec<i32>>`
   = note: `#[warn(bare_trait_objects)]` on by default

error[E0191]: the value of the associated type `AfterRemove` (from trait `RemoveT`) must be specified
  --> src/
2  |     type AfterRemove;
   |     ----------------- `AfterRemove` defined here
20 |     let y = (x as RemoveT<Foo, Vec<i32>>).remove_label();
   |                   ^^^^^^^^^^^^^^^^^^^^^^ help: specify the associated type: `RemoveT<Foo, Vec<i32>, AfterRemove = Type>`

error[E0620]: cast to unsized type: `Vec<i32>` as `dyn RemoveT<Foo, Vec<i32>>`
  --> src/
20 |     let y = (x as RemoveT<Foo, Vec<i32>>).remove_label();
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider using a box or reference as appropriate
  --> src/
20 |     let y = (x as RemoveT<Foo, Vec<i32>>).remove_label();
   |              ^

error: aborting due to 2 previous errors; 1 warning emitted

Some errors have detailed explanations: E0191, E0620.
For more information about an error, try `rustc --explain E0191`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

Question: Why does this error? It is "clear" to me that we should have AfterRemove = Nil

If you callt like this, the type inference works properly:

fn main () {
    let x = Vec::<i32>::new();

    let y = RemoveT::<Foo, Vec<i32>>::remove_label(&x);

Trait objects always have to list associated types explicitly: The identity of the underlying type is lost when the trait object is generated, so it’s no longer possible to look up the associated types from the impl block.

  1. Repeated application of this apparently solved my problem.

  2. I have no idea why this worked. Can you please explain how, from a type inference perspective,

works, while what I wrote fails ?

To me, these two lines after some AST simplification, are identical.

Yet the compiler accepts yours and rejects mine. What is going on inside the compiler ?

as RemoveT<Foo, Vec<i32>> is a cast, and the RemoveT<Foo, Vec<i32>> is interpreted as a type, not a trait. The only way to interpret that as a type is as a trait object, and that's why the compiler is complaining it's missing the dyn keyword and that it is unsized. Calling a method that involves an associated type on a trait object also requires that the associated type is specified. It can't be inferred because it would change the type since dyn RemoveT<Foo, Vec<i32>> is not the same as dyn RemoveT<Foo, Vec<i32>, AfterRemove=Nil>.

Edit: To be clear, in expr as RemoveT<Foo, Vec<i32>> the as means a cast but when you do something like <Vec<i32> as RemoveT<Foo, Vec<i32>>>::remove_label(&x) then RemoveT<Foo, Vec<i32>> is interpreted as a trait and used to disambiguate the method call.


How should I read this statement?

It says "I want to call the remove_label function from the impl RemoveT<Foo, Vec<i32>> for Vec<i32> block with &x as its only argument".

Thanks for your detailed response. I think what really threw me off is:

  1. in most of my code, I rarely write <value as T>... ; instead I write use T; value. ...

  2. Due to reading lots of trait programming code, I have been reading/writing <Type as T>::... all over the place.

  3. As a result, I got confused and wrote <x as RemoveT<...>>... which I normally would not write.

Thanks again for detailed explainations!