edit2: Ok, so there's a lot of subtle things colliding here.
Box<dyn Test> actually means Box<dyn Test + 'static>. It gets this implicit lifetime bound by default.
&mut dyn Test does not get an implicit 'static bound. It's &'tmp dyn Test + 'tmp.
&mut lifetimes are invariant, meaning they have to match exactly, and can't be made shorter. If you have &'long you can't use it where &'short is required.
Except where reborrowing and coercions can create a new &'short mut loan borrowed from a &'long mut one. Reborrowing is "shallow", and will change only the outer lifetime, but coercions are more powerful and can alter dyn Trait.
So I think it looks like this:
trait Test {}
fn test(mut s: Option<&mut Box<dyn Test + 'static>>) {
consume(s.map(|x| x.as_mut()));
}
fn consume<'a>(s: Option<&'a mut (dyn Test + 'a)>) {}
It works if you change it to:
fn consume<'a>(s: Option<&'a mut (dyn Test + '_)>) {}
or
fn consume<'a>(s: Option<&'a mut (dyn Test + 'static)>) {}
Every trait object type has a lifetime bound on its contents, and that lifetime is inferred when not written. The inference rules specify that:
Box<dyn Test> is equal to Box<dyn Test + 'static>
&'a mut dyn Test is equal to &'a mut (dyn Test + 'a)
Thus, you get a type mismatch. The straightforward fix is to specify &'a mut (dyn Test + 'static) explicitly in the signature of consume.
This is not actually the whole story; &mut dyn Test + 'static actually will coerce to&mut dyn Test + 'a. However, coercions don’t happen to types inside arbitrary generic types; you can't coerce an Option containing the dyn Test type.[1] But you can fix that by annotating the map closure’s return type, to make the coercion happen at a point where the value (x) is not wrapped in Option:
Compared to the previous solution, this preserves more flexibility of consume() — you can pass it values that contain borrows whose lifetimes are at least 'a but less than 'static. But, if you have no use for that — if everydyn Test must meet a 'static bound for other reasons — then you might as well restrict it for clarity.
A more common example of this lack of coercion is that if you want to make an Option<Box<dyn Test>>, then you have to make sure that you coerce Box<SomeImplementor> to Box<dyn Test> before putting it in the Option, rather than after. ↩︎
This would make sense based on the rest of Rust, but it’s not actually true for trait object lifetime bounds. They can be coerced shorter; you can coerce &mut dyn Trait + 'long to &mut dyn Trait + 'short. @user1984’s problem is just that the coercion didn’t happen. (This coercion is sound, in case you’re wondering, because since the concrete type of a dyn is specified by its vtable pointer, you can’t ever write a new too-short dynvalue through the &mut because that wouldn’t update the vtables of other pointers to the value, so the unsound operation already has to be prohibited for more fundamental reasons.)