Generics for traits?

I am playing around with trait objects and tried to write the function below.
As expected, it does not work as intended, since generics always represent types, not traits.
Just out of curiosity: Is it possible in current Rust, to implement such a generic function as below?

use std::fmt::Debug;

fn as_dyn<T, U>(input: T) -> Box<dyn U>
where
    T: U,
{
    Box::new(input) as Box<dyn U>
}

#[derive(Debug)]
struct Foo;

fn main() {
    let d = as_dyn::<_, Debug>(Foo);
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0404]: expected trait, found type parameter `U`
 --> src/main.rs:5:8
  |
3 | fn as_dyn<T, U>(input: T) -> Box<dyn U>
  |              - found this type parameter
4 | where
5 |     T: U,
  |        ^ not a trait

error[E0404]: expected trait, found type parameter `U`
 --> src/main.rs:3:38
  |
3 | fn as_dyn<T, U>(input: T) -> Box<dyn U>
  |              -                       ^ not a trait
  |              |
  |              found this type parameter

error[E0404]: expected trait, found type parameter `U`
 --> src/main.rs:7:32
  |
3 | fn as_dyn<T, U>(input: T) -> Box<dyn U>
  |              - found this type parameter
...
7 |     Box::new(input) as Box<dyn U>
  |                                ^ not a trait

For more information about this error, try `rustc --explain E0404`.
error: could not compile `playground` (bin "playground") due to 3 previous errors

No, as you explained yourself, being generic over traits is not possible.

As for the conversion at hand, with unstable APIs from std you can generalize further (using a generic to stand for dyn Trait, not Trait) and express this specific function with the Unsize trait, (though it also covers a few more kinds of coercions than just T: Trait to dyn Trait).

All implementations of Unsize are provided automatically by the compiler. Those implementations are:

  • Arrays [T; N] implement Unsize<[T]>.
  • A type implements Unsize<dyn Trait + 'a> if all of these conditions are met:
    • The type implements Trait.
    • Trait is object safe.
    • The type is sized.
    • The type outlives 'a.
  • Structs Foo<..., T1, ..., Tn, ...> implement Unsize<Foo<..., U1, ..., Un, ...>> where any number > of (type and const) parameters may be changed if all of these conditions are met:
    • Only the last field of Foo has a type involving the parameters T1, …, Tn.
    • All other parameters of the struct are equal.
    • Field<T1, ..., Tn>: Unsize<Field<U1, ..., Un>>, where Field<...> stands for the actual type of the struct’s last field.
#![feature(unsize)]
use std::fmt::Debug;
use std::marker::Unsize;

fn as_dyn<T, U: ?Sized>(input: T) -> Box<U>
where
    T: Unsize<U>,
{
    Box::new(input) as Box<U>
}

#[derive(Debug)]
struct Foo;

fn main() {
    let d = as_dyn::<_, dyn Debug>(Foo);
}

Rust Playground

4 Likes