Default type parameters and generic trait impls

We have a weird inconsistency with default type parameters and generic trait impls. Let's consider this example:

pub struct Foo<T = u32> { val: T }

impl<T: Default> Default for Foo<T> {
    fn default() -> Self {
        Self { val: Default::default() }
    }
}

fn main() {
    let foo = Foo::default();
}

It fails to compile with the following message:

error[E0283]: type annotations needed for `Foo<_>`
  --> src/main.rs:10:9
   |
10 |     let foo = Foo::default();
   |         ^^^   --- type must be known at this point
   |
   = note: cannot satisfy `_: Default`
note: required for `Foo<_>` to implement `Default`
  --> src/main.rs:3:18
   |
3  | impl<T: Default> Default for Foo<T> {
   |         -------  ^^^^^^^     ^^^^^^
   |         |
   |         unsatisfied trait bound introduced here
help: consider giving `foo` an explicit type, where the type for type parameter `T` is specified
   |
10 |     let foo: Foo<T> = Foo::default();
   |            ++++++++

Amusingly, <Foo>::default() and let foo: Foo = Foo::default() work as expected, so it does not look like some fundamental issue. The same applies to const generics with default value as well (e.g. Foo<const N: u32 = 42>).

Why exactly compiler can't use the default type parameter to infer T? Are there any plans to fix it?

Defaults don't affect inference, and "complete elision" in an expression outside of a type context[1] means "infer these all elided things for me", and not "fill in all the elided things with defaults".

Foo::default() is short for Foo::<_>::default(), is short for <Foo<_>>::default() -- which all mean "infer the _ for me". And defaults do not affect the inference.

With <Foo>::Default, the Foo is in a type context, and it's short for <Foo<u32>>::default(), in the same way let _: Foo = ... is short for let _: Foo<u32> = .... There is no inference in these cases, it always uses the default.

I've written more details about it here, and this is a good article about it too.

I'm not aware of any active plans. I think this is currently the issue about it.


  1. in a position where you would have to use Ty::<_> instead of just Ty<_> â†Šī¸Ž

2 Likes