Why is "one type more general than the other" here?

fn foo<T: ?Sized>(_: &T) {}

fn main() {
    let _: fn(&dyn Send) = foo::<dyn Send>;
}

(Playground)

Gives error:

error[E0308]: mismatched types
 --> src/main.rs:4:28
  |
4 |     let _: fn(&dyn Send) = foo::<dyn Send>;
  |                            ^^^^^^^^^^^^^^^ one type is more general than the other
  |
  = note: expected fn pointer `for<'r> fn(&'r (dyn Send + 'r))`
                found fn item `for<'r> fn(&'r dyn Send) {foo::<dyn Send>}`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error

Why? Shouldn't &'r (dyn Send + 'r) be the same thing as &'r dyn Send?

dyn Trait implicitly has a + 'static lifetime unless something else is specified. You have to accord the lifetimes somehow, so both of these compile:

fn arbitrary<'a>() {
    let _: fn(&'a dyn Send) = foo::<dyn Send + 'a>;
}

fn main() {
    let _: fn(&'static dyn Send) = foo::<dyn Send>;
}

Hmm, thinking about it, there might be another issue, too: fn(&T) is implicitly a HRTB, it really means for<'arg>(&'arg T). However, foo::<dyn Send> is a concrete function with a generic lifetime argument, and has type fn(&'a T) for some lifetime 'a. Hence, it's not a HRTB. And while these two can practically be used interchangeably, they are not the same type.

3 Likes

&dyn Trait has a bound on the trait object from the lifetime on the reference, and dyn Trait has a bound of 'static. So you have to change one of them so they agree.

You can make the one behind the reference static

fn foo<T: ?Sized>(_: &T) {}

fn main() {
    let _: fn(&(dyn Send + 'static)) = foo::<dyn Send>;
}
3 Likes

It is higher-ranked in the lifetime as the (anonymous) lifetime has no bounds. But this is a problem if the lifetime has bounds (even if they are trivial).

2 Likes