Default a generic parameter to `impl Trait`?

Is there a way to default a generic parameter to an impl Trait using either a hacky version of default generic type parameter syntax or the type alias keyword?

I'm trying to write a construct that can replace a keyword MyStruct2 with MyStruct<impl ATrait>. I know I could write a clippy lint with --fix, but is there another way to do this?

Consider the following code (note that allowing impl Trait in a type alias is an unstable feature locked behind the type_alias_impl_trait flag):

#![feature(type_alias_impl_trait)]

struct MyStruct<State: ATrait>
{
    state: State
}

impl MyStruct<A>
{
    fn new() -> Self
    {
        MyStruct {
            state: A {}
        }
    }
}

// define traits
trait ATrait
{}

struct A
{}

impl ATrait for A
{}

mod my_struct
{
    use super::*;
    
    pub type MyStruct2 = MyStruct<impl ATrait>;
}

use my_struct::MyStruct2;
fn main() 
{
    let a_test = MyStruct::<A>::new();
    wah(a_test);
}

fn wah(_s: MyStruct2)
{}

which gives the error:

error: unconstrained opaque type
  --> src/main.rs:32:35
   |
32 |     pub type MyStruct2 = MyStruct<impl ATrait>;
   |                                   ^^^^^^^^^^^
   |
   = note: `MyStruct2` must be used in combination with a concrete type within the same module

error[E0308]: mismatched types
  --> src/main.rs:39:9
   |
32 |     pub type MyStruct2 = MyStruct<impl ATrait>;
   |                                   ----------- the expected opaque type
...
39 |     wah(a_test);
   |     --- ^^^^^^ expected `MyStruct<MyStruct2::{opaque#0}>`, found `MyStruct<A>`
   |     |
   |     arguments to this function are incorrect
   |
   = note: expected struct `MyStruct<MyStruct2::{opaque#0}>`
              found struct `MyStruct<A>`
note: this item must have the opaque type in its signature in order to be able to register hidden types
  --> src/main.rs:36:4
   |
36 | fn main() 
   |    ^^^^
note: function defined here
  --> src/main.rs:42:4
   |
42 | fn wah(_s: MyStruct2)
   |    ^^^ -------------

For more information about this error, try `rustc --explain E0308`.
error: could not compile `opaque-test` (bin "opaque-test") due to 2 previous errors

I've experimented with both, but haven't met with success with either. A simple struct MyStruct<State: ATrait = impl ATrait> is disallowed by the compiler with the error:

error[E0562]: `impl Trait` is not allowed in generic parameter defaults
 --> src/main.rs:7:37
  |
7 | struct MyString<State: TaintedTrait=impl TaintedTrait>
  |                                     ^^^^^^^^^^^^^^^^^
  |
  = note: `impl Trait` is only allowed in arguments and return types of functions and methods

I'm pretty sure this isn't possible the way I want it to be, but wanted to check my understanding. Thanks!

impl Trait isn't an actual type, and it means different things in different contexts. Sometimes it adds a hidden type parameter, and sometimes it adds an opaque concrete type (RPIT / TAIT). Defaulting a parameter to impl Trait would have to be given a specific meaning, and it doesn’t have one right now.

Can you describe what behavior you are trying to achieve, without mentioning impl Trait syntax? For example, in what way is this not what you want?

mod my_struct {
    pub type MyStruct2 = MyStruct<super::A>;
}
2 Likes

If I have:

struct B {}

impl ATrait for B
{}

fn foo(s: MyStruct2)

I want to be able to pass either a MyStruct<B> or a MyStruct<A> variable to foo()

No; you are asking for foo() to be a generic function, and there is no syntax to make a function invisibly generic (except for lifetimes), and there probably never will be because it would be confusing. You must write one of these:

fn foo<T: ATrait>(s: MyStruct<T>) {}
fn foo(s: MyStruct<impl ATrait>) {}
4 Likes

That makes sense. Thank you!