Decouple trait object lifetimes in generic function

Viewed 72

Given:

pub trait SomeTrait {}

pub fn foo<T: ?Sized>(arg1: &mut T, arg2: Box<T>) -> Box<T> {
    arg2
}

struct S {
    b: Box<dyn SomeTrait>
}

pub fn bar(a0: &mut S, a1: &mut dyn SomeTrait, a2: Box<dyn SomeTrait>) {
    a0.b = foo(a1, a2);
}

I have a generic function foo. When it's used in bar it seems as though T gets a type of dyn SomeTrait + 'static which seems to force arg1 to have lifetime of `'static' and gives the following error:

error[E0759]: `a1` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
  --> <source>:12:12
   |
11 | pub fn bar(a0: &mut S, a1: &mut dyn SomeTrait, a2: Box<dyn SomeTrait>) {
   |                            ------------------ this data with an anonymous lifetime `'_`...
12 |     a0.b = foo(a1, a2);
   |            ^^^^--^^^^^
   |                |
   |                ...is used and required to live as long as `'static` here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0759`.
Compiler returned: 1

Is there a way force arg1 to have an independent lifetime? i.e. decouple it from the 'static so that the code compiles?

1 Answers

Is there a way force arg1 to have an independent lifetime? i.e. decouple it from the 'static so that the code compiles?

No. There's a single type parameter T, and in the case of a trait object type, there's a lifetime bound embedded in the type, and so the lifetime bound will be the same every time T is used.

What we can do is relax the 'static requirement instead...


The 'static requirement comes from the assignment to a0.b. The type of a0.b is Box<dyn SomeTrait + 'static>: 'static is inferred here, because lifetime parameters must always be explicit on structs. However, the &mut dyn SomeTrait and Box<dyn SomeTrait> parameters on bar have anonymous lifetimes instead, hence the error.

The solution is to introduce a lifetime parameter on S and use it in the trait object, and then adjust bar's signature to make the lifetimes agree.

pub trait SomeTrait {}

pub fn foo<T: ?Sized>(arg1: &mut T, arg2: Box<T>) -> Box<T> {
    arg2
}

pub struct S<'a> {
    b: Box<dyn SomeTrait + 'a>,
}

pub fn bar<'a>(a0: &mut S<'a>, a1: &mut (dyn SomeTrait + 'a), a2: Box<dyn SomeTrait + 'a>) {
    a0.b = foo(a1, a2);
}
Related