[specialization] expected associated type but found unit type

I'm using the specialization feature and got an error like this:

#![feature(specialization)]
#![feature(min_specialization)]

trait Foo {
    type Ty;
    fn foo() -> Self::Ty;
}

impl Foo for i32 {
    type Ty = f32;

    fn foo() -> Self::Ty {
        1.0
    }
}

impl<T> Foo for T {
    default type Ty = ();

    default fn foo() -> Self::Ty {
        ()
    }
}

And the error message is:

error[E0308]: mismatched types
  --> src/main.rs:21:9
   |
18 |     default type Ty = ();
   |     --------------------- expected this associated type
19 |
20 |     default fn foo() -> Self::Ty {
   |                         -------- expected `<T as Foo>::Ty` because of return type
21 |         ()
   |         ^^ expected associated type, found `()`
   |
   = note: expected associated type `<T as Foo>::Ty`
                    found unit type `()`

It seems that the compiler didn't recognize that <T as Foo>::Ty is ().

Did I do anything wrong?

An impl could change the associated type without changing the default method. The default method would obviously not make sense anymore in that case

I don't understand :rofl:, why an impl could affect the default function? It looks to me the default impl is like the last choice, if no other impl matches...

Do you suggest that the default foo function can't actually "see" what the Ty is, even I write default type Ty = ();?

A default item is explicitly opting in to potentially not being the last choice.

The generic impl still has to be valid in that case, even though your code currently doesn't have any impls that are only overriding one of the trait items

Your generic impl requires the following impl to be allowed

impl Foo for String {
    type Ty = String;
}

Since default items can be specialized separately. This impl doesn't make sense with the default fn your generic impl provides. That's why the generic impl is being rejected.

2 Likes

Sorry for asking more, I'm still not very clear to your answers, may I ask, if I write like this:

trait Foo {
    type Ty: Default;
    fn test() -> Self::Ty;
}

impl Foo for i32 {
    type Ty = f32;

    fn test() -> Self::Ty {
        1.0
    }
}



impl<T> Foo for T {
    default type Ty = ();

    default fn test() -> Self::Ty {
        Self::Ty::default()
    }
}

This code will compile, and in this case, what's the point to write default type Ty = ()? It is unused at all.

It would be used, if impl Foo for i32 contained only fn test, but not type Ty - playground.

1 Like

I never know I can partially implement a trait in specialization feature :rofl:, and it looks that my guessing that the default foo function can't actually "see" what the Ty is right, they are totally unrelated?

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.