1

The following code is fully type annotated:

fn enter<'a, F, R>(x: &'a i32, func: F) -> R
where
    F: for<'b> FnOnce(&'b i32) -> R,
{
    func(x)
}

fn identity<'a>(x: &'a i32) -> &'a i32 {
    x
}

fn main() {
    let x = &42;
    enter(x, identity);
}

The compiler reports an error when compiling it:

error[E0308]: mismatched types
  --> src/main.rs:14:5
   |
14 |     enter(x, identity);
   |     ^^^^^^^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected trait `for<'b> FnOnce<(&'b i32,)>`
              found trait `for<'a> FnOnce<(&'a i32,)>`
note: the lifetime requirement is introduced here
  --> src/main.rs:3:35
   |
3  |     F: for<'b> FnOnce(&'b i32) -> R,
   |                                   ^

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

My understanding is that the trait bound for<'b> FnOnce(&'b i32) -> R is more general than identity's signature for<'a> fn(&'a i32) -> &'a i32, so it should pass.

However, the generic -> R seems to be the culprit that stops the compilation but I don't know why.

I noticed there are similar questions, but they experienced the error because their types were not fully annotated and the compiler incorrectly inferred the type.

Related:

Zhiyao
  • 4,152
  • 2
  • 12
  • 21

1 Answers1

3

My understanding is that the trait bound for<'b> FnOnce(&'b i32) -> R is more general than identity's signature for<'a> fn(&'a i32) -> &'a i32, so it should pass.

No it is not. When R is declared, 'b is not in the context, so it cannot depend on it (this is one way to view that, there are others).

This is necessary for APIs like std::thread::LocalKey::with() to be sound: if R was allowed to contain the lifetime (implicit in the case of with()), references to the thread local could escape the closure and with(), and then used on different threads, causing UB.

As far as I know, there is no way to have a generic return type and allow it to reference the parameters.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77