Michael Paddon
Michael Paddon

Reputation: 343

Rust: lifetime checking of a borrow inside a refernce to a MaybeOwned

I'm having trouble with the follwoing code...

use std::collections::BTreeSet;
use maybe_owned::MaybeOwned;

struct Thing<'a, T> {
    set: BTreeSet<MaybeOwned<'a, T>>
}

impl<'a, T: Ord> Thing<'a, T> {
    fn take(&mut self, x: T){
        let y = self.set.take(&MaybeOwned::Borrowed(&x));
    }
}

gives the compiler error

error[E0597]: `x` does not live long enough
  --> src/main.rs:10:53
   |
8  | impl<'a, T: Ord> Thing<'a, T> {
   |      -- lifetime `'a` defined here
9  |     fn take(&mut self, x: T){
10 |         let y = self.set.take(&MaybeOwned::Borrowed(&x));
   |                 ------------------------------------^^--
   |                 |                                   |
   |                 |                                   borrowed value does not live long enough
   |                 argument requires that `x` is borrowed for `'a`
11 |     }
   |     - `x` dropped here while still borrowed

However x is clearly not borrowed at that point because the MaybeOwned has fallen out of scope and therefore the enclosed borrow has fallen out of scope.

How can I tell the rust compiler that this is fine?

Upvotes: 3

Views: 72

Answers (1)

cdhowie
cdhowie

Reputation: 168958

The problem is that, while the temporary MaybeOwned doesn't live that long, it doesn't matter because it's implicitly MaybeOwned<'a, T>. This means x must live at least as long as 'a but it doesn't. The fact that the temporary MaybeOwned won't live that long isn't relevant to the borrow checker.

BTreeSet::take()'s second argument is a &Q, where the set's own T implements Borrow<Q>. MaybeOwned<'a, T> doesn't implement Borrow<MaybeOwned<'b, T>> where 'b: 'a, but all T and &T implement Borrow<T> thanks to a blanket implementation, so given an argument typed &MaybeOwned<'_, T>, the only lifetime that satisfies the T: Borrow<Q> constraint is &MaybeOwned<'a, T> -- thus, the lifetime parameter of the temporary MaybeOwned is inferred to be 'a. That's the only way the trait bounds can be satisfied.

Thankfully, none of this matters, because MaybeOwned<'_, T> implements Borrow<T>, which means you can just supply a &T:

let y = self.set.take(&x);

Upvotes: 2

Related Questions