Infinite borrowing when passing borrowed value to Box<dyn Trait>

This top part is mainly useful if you like solving lifetime puzzles. Something potentially useful is at the bottom.

The low-level cause (which does prevent this high-level unsoundness) is invariance. Namely, trait parameters are invariant. So in the case of a trait object, the method signature takes

&dyn MyTrait<Chars<'c>>, Chars<'c>
//           ^^^^^^^^^

Because the underlined part is invariant, the lifetime has to be the entirety of the borrow 'c. This is what ties the borrow of s to the type of dyn_trait:

Box<dyn MyTrait<Chars<'c>> + '_>

and the final piece of the puzzle is that trait objects always have a non-trivial drop, so from a low-level borrow checking perspective, there's a use of the borrow of s when dyn_trait goes out of scope.

More generally, if the following three ingredients are a recipe for borrow entanglement:

  1. A method taking different parameters with the same lifetime
  2. Something causing the lifetime to be invariant
  3. A non-trivial drop

The invariance of trait parameters means that a dyn MyTrait<Chars<'c>> is saying, "I can only work with Chars<'a> if 'a is exactly 'c". Contravariance would be "'c or longer", etc.

There is a way to be more general without changing the trait: you can have a higher-ranked bound that says "I can work with Chars<'a> for any 'a". That would be this change:

-    let dyn_trait: Box<dyn MyTrait<_>> = Box::new(X {});
+    let dyn_trait: Box<dyn for<'a> MyTrait<Chars<'a>>> = Box::new(X {});

Now the lifetimes in the method call don't have to be the same.

Whether the implementors you want can meet that bound or not is a different question, so this may or may not be a viable alternative.

In terms of @2e71828 solution, you will end up with the same borrowing situation as the OP if the iterator Item type is something borrowed. The higher-ranked trait object type (commented in the playground) again may or may not be a viable workaround, depending on the MyTrait implemention of the base type.

2 Likes