Lifetime and closures and continuation passing style - rust

I'm playing with Rust closures, trying to get a feeling for them, and one task I set for myself was to implement an in-order traversal with continuation-passing-style. Usually something I can do in about an hour in other languages, but here I've managed to get stuck on how to manage the lifetime of a closure I use in callback.
I've defined a binary tree like this, which is pretty straightforward:
// A node is a tuple of (left, value, right)
struct Node<T>(pub Tree<T>, pub T, pub Tree<T>);
// A tree is an optional pointer to a node
type Tree<T> = Option<Box<Node<T>>>;
and I can do a direct recursive traversal the way I would expect:
// Direct recursion.
// The <T: Copy> is needed because we copy values into
// the result vector. For other usages we might not need it
fn inorder<T: Copy>(t: &Tree<T>, res: &mut Vec<T>) {
// If t is not empty it is Some(node)
if let Some(node) = t {
// Pull out the values of the node.
// In the development branch of Rust there is
// a nicer syntax, but this is how it is now
let Node(left, val, right) = node.as_ref();
inorder(left, res);
res.push(*val);
inorder(right, res);
}
}
To do it with continuations, however, I need to define closures to manage the rest of the traversal and pass those along with a tail-recursion, and my immediate solution looked not much different from my current one:
// Ideally, we wouldn't need to pass the vector along with the closures
// but Rust won't let us hold on to a mutable reference in a closure if
// another closure also has a mutable reference, so we pass the vector
// from continuation to continuation instead.
fn cps_rec<T: Copy>(t: &Tree<T>, res: &mut Vec<T>,
k: Box<dyn FnOnce(&mut Vec<T>)>)
{
match t {
None => { k(res) },
Some(node) => {
let Node(left, val, right) = node.as_ref();
let after_left = |v: &mut Vec<T>| {
// After we have gone left, add v and go right,
// calling k when we are done
v.push(*val);
cps_rec(right, v, k);
};
cps_rec(left, res, Box::new(after_left));
}
}
}
fn cps<T: Copy>(t: &Tree<T>) -> Vec<T> {
let mut res = vec![];
cps_rec(t, &mut res, Box::new(|_| ()));
res
}
Playground
The problem is in the recursion cps_rec(left, res, after_left) where the lifetime of the closure doesn't match the constraint. (I think, I can't say I fully understand exactly what Rust is complaining about, but the problem goes away as soon as I make the closure's body empty, so it is something in the inferred lifetime there that is messing things up). I first suspected that it was the lifetime of val or right that was fighting me, but it doesn't help to put move in front of the closure after dereferencing them
fn cps_rec<T: Copy>(t: &Tree<T>, res: &mut Vec<T>,
k: Box<dyn FnOnce(&mut Vec<T>)>)
{
match t {
None => { k(res) },
Some(node) => {
let Node(left, val, right) = node.as_ref();
let val = *val;
let right = *right;
let after_left = move |v: &mut Vec<T>| {
// After we have gone left, add v and go right,
// calling k when we are done
v.push(val);
cps_rec(&right, v, k);
};
cps_rec(left, res, Box::new(after_left));
}
}
}
Playground
so I can't work out what the problem is, or how to tell Rust that this closure will survive long enough to complete the recursion...
I then tried using a generic type for the continuation, seeing if that would make Rust resolve the issue for me:
fn cps_rec<'a, T: Copy, Cont>(t: &'a Tree<T>, res: &'a mut Vec<T>, k: Cont)
where Cont: FnOnce(&'a mut Vec<T>)
{
match t {
None => { k(res) },
Some(node) => {
let Node(left, val, right) = node.as_ref();
let after_left = |v: &'a mut Vec<T>| {
// After we have gone left, add v and go right,
// calling k when we are done
v.push(*val);
cps_rec(right, v, k);
};
cps_rec(left, res, Box::new(after_left));
}
}
}
Playground
but that breaks the compilation when the type checker has to recurse on the type inference. Maybe not surprising since the type of the closure probably depends on the inferred type of the recursion.
Is there something I can do to fix this, or is the idea dead on arrival and I have to try a completely different approach if I want to make something along those lines?

The lifetime problem is becaue Box<dyn FnOnce(&mut Vec<T>)> is actually, with lifetimes explicitly specified, Box<dyn FnOnce(&mut Vec<T>) + 'static>. That is, it requires the closures to be 'static. A closure is static if everything it captures is 'static. Of course an empty closure fulfills this condition - it captures nothing, so it worked if you emptied its body.
However, your closure captures over non-'static references - val and right. I'll soon explain why copying them doesn't work.
The solution is simple: we don't really need the closure to be 'static; we can be fine even if it won't be - we don't store it or something. To express that to the compiler, we need to change Box<dyn FnOnce(&mut Vec<T>)> to Box<dyn FnOnce(&mut Vec<T>) + '_> (playground). That's it. '_ is the explicitly elided lifetime: it tells the compiler "figure the right lifetime out yourself". Usually the compiler does that automatically, but with dyn Trait he sometimes gives up and just uses 'static. The lifetime is inferred according to the lifetime elision rules; in this case, it introduces a new lifetime, like if we wrote:
fn cps_rec<'elided_lifetime, T: Copy>(
t: &Tree<T>,
res: &mut Vec<T>,
k: Box<dyn FnOnce(&mut Vec<T>) + 'elided_lifetime>,
) { ... }
What confuses here is the compiler's error message. It'd be clearer if you'd followed the compiler's suggestion and put T: 'static (playground):
error: lifetime may not live long enough
--> src/lib.rs:17:32
|
6 | fn cps_rec<T: Copy + 'static>(t: &Tree<T>, res: &mut Vec<T>, k: Box<dyn FnOnce(&mut Vec<T>)>) {
| - let's call the lifetime of this reference `'1`
...
17 | cps_rec(left, res, Box::new(after_left));
| ^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`
This is what I said. 'static is required because of the closure's implied 'static bound.
But the compiler is has something more important to tell you (or rather, yell at you). It thinks: "given that the closure requires 'static, those references are obviously 'static. This user isn't lying to me, he's a good citizen!" Only later it'll realize it was wrong, but it will never get to this "later" because it will stop compilation due to errors earlier. But as of now it thinks, "given that those references are obviously 'static, they're &'static T (for val, or &'static Option<Box<T>> for right). But for &'static T to be valid, T: 'static must hold (imagine a reference like &'long &'short i32: you'll be able to access it for 'long, but as long as 'short is over it's invalid, and you will use a dangling reference!). Can I prove that T: 'static always hold? Nope! Well, should emit an error." (You can fill a bug report at https://github.com/rust-lang/rust/issues, the Rust developers will appreciate it even though I'm not sure how much they can do to improve the situation).
Why copying them didn't help? First, the way the compiler thought about it hasn't changed, and so the same error is still emitted. Second, even if we could solve it (for example by specifying T: 'static), there is another error (playground):
error[E0507]: cannot move out of `*right` which is behind a shared reference
--> src/lib.rs:12:34
|
12 | let right: Tree<T> = *right;
| ^^^^^^ move occurs because `*right` has type `Option<Box<Node<T>>>`, which does not implement the `Copy` trait
|
help: consider borrowing the `Option`'s content
|
12 | let right: Tree<T> = *right.as_ref();
| +++++++++
help: consider borrowing here
|
12 | let right: Tree<T> = &*right;
| ~~~~~~~
Hopefully this one is self-explanatory.
About the generic version, your assumption is indeed correct: no language can do recursive CPS with monomorphization, they all use dynamic dispatch (which is equivalent to Box<dyn FnOnce()> (or some GCed version), or to &mut dyn FnMut() or something similar). We will have to instantiate it ad infinitum.

Related

Recursive async function that borrows mutable variable twice

I'm designing a connection retry function. It retries if the error was ConnectionClosed. In the full implementation it has other things that justify it being a recursion, but this is off topic. Anyways, since it's a connection, it makes sense to be async. However, async recursives force me to use BoxFuture, and we know that asyncs capture and return all the arguments.
use std::future::Future;
use futures::future::{BoxFuture, FutureExt};
struct Message;
struct Client;
enum Error {
ConnectionClosed
}
impl Client {
fn send_and_expect<'a>(
&'a mut self,
message: &'a Message
) -> BoxFuture<'a, Result<(), Error>> {
async move {
Ok(())
}.boxed()
}
//With this function I can wrap any async function f that grabs data from the internet
pub fn connection_retrier<'a, T>(
f: fn(&'a mut Self, &'a Message) -> T,
f_self: &'a mut Self,
f_m: &'a Message,
) -> BoxFuture<'a, Result<(),Error>>
where
T: Future<Output = Result<(), Error>> + 'a + Send
{
/*
By making f: fn(&'a mut Self, &'a Message) -> T, we tell the compiler that
`f` is a specific function: one that specifically requires the `Self` and `Message`
arguments to live as long as `'a`, where `'a` is the min of the lifetimes of the `f_self` and `f_m`
arguments passed to `connection_retrier`.
Thus this forces `f_self` and `f_m` to live as long as `connection_retrier`.
The call `let r = f(f_self, f_m).await` returns a `Future` that lives as long as `'a`.
I think this is the problem. The result of the first call borrows `f_self` and `f_m`
for at least the entire lifetime of `r`. This would make it impossible to use
`f_self` and `f_m` again inside `connection_retrier`. As you see, I tried making sure
that `r` destructs before we use `f_self` in `connection_retrier` again, but somehow
`r` is marked to live as long as `connection_retrier`, because `f_self` is still considered
to be borrowed.
*/
async move {
let ok: bool;
{
let r = f(f_self, f_m).await;
match r {
Ok(_) => ok = true,
Err(Error::ConnectionClosed) => {
ok = false;
}
}
}
match ok {
true => Ok(()),
false => Client::connection_retrier(f, f_self, f_m).await
}
}.boxed()
}
async fn send_with_retry<'a> (
&'a mut self,
message: &'a Message,
) -> Result<(), Error>
{
Client::connection_retrier(
Client::send_and_expect,
self,
message
).await
}
}
Error:
error[E0499]: cannot borrow `*f_self` as mutable more than once at a time
--> src/lib.rs:58:56
|
24 | f: fn(&'a mut Self, &'a Message) -> T,
| - lifetime `'1` appears in the type of `f`
...
48 | let r = f(f_self, f_m).await;
| --------------
| | |
| | first mutable borrow occurs here
| argument requires that `*f_self` is borrowed for `'1`
...
58 | false => Client::connection_retrier(f, f_self, f_m).await
| ^^^^^^ second mutable borrow occurs here
Playground
I understand why the error occurs: Client::connection_retrier(f, f_self, f_m).await, let's call it r, holds a mutable reference to f_self, so I cannot use it again while it's being held. However, after I check that this result r is Error::ConnectionClosed, I don't need it anymore, so there should be a way to discard it so I can reborrow it mutably.
The problem
As #moy2010 said, the problem is here:
pub fn connection_retrier<'a, T>(
f: fn(&'a mut Self, &'a Message) -> T,
f_self: &'a mut Self,
f_m: &'a Message,
) -> BoxFuture<'a, Result<(), Error>>
where T: Future<Output = Result<(), Error>> + 'a + Send
This signature defines f to be a function that accepts arguments with exactly the lifetime 'a, which is alive throughout the body of connection_retrier.
When you are able to temporarily pass a mutable reference to a function and then 'recover' it later, this is called a reborrow. Reborrowing from a mutable reference works by creating a new mutable reference of shorter lifetime to the data it points to, and preventing use of the original reference until this lifetime has ended. Usually a reborrow happens during a function call, in which case that lifetime is just long enough for the function call to be made.
As you can see, reborrowing always produces a reference with lifetime shorter than the original. But f needs a reference whose lifetime is exactly 'a, so the compiler correctly deduces that the call to f cannot reborrow f_self and instead, f_self is permanently moved into f. Hence the error when you attempt to use it again.
Solutions
If you can change the signature of send_and_expect so that the returned future only borrows from message (i.e. not the Client), then #moy2010 has already provided a correct solution in the comments to their answer. I will proceed on the assumption that send_and_expect must borrow from both its arguments, as indicated by the signature in the question.
Since you would like to reborrow f_self before passing it to f, what you really need is to define f to be a function that can be called for any lifetime (not just 'a). You might think that means we can just change the declaration of f to for<'b> fn(&'b mut Self, &'b Message) -> T. But wait! Your where bound specifies that T borrows from the lifetime 'a, not 'b, so this signature doesn't line up with that of send_and_expect. But also notice that we can't change the bound to say 'b instead, because 'b is not in scope outside of the declaration of f! So there is no way to express the correct bound on T here. There are, however, a few workarounds.
Use a Boxed trait object
The simplest solution is just to make the return type of f a boxed trait object instead of a generic parameter, like this:
pub fn connection_retrier<'a>(
f: for<'b> fn(&'b mut Self, &'b Message) -> BoxFuture<'b, Result<(), Error>>,
f_self: &'a mut Self,
f_m: &'a Message,
) -> BoxFuture<'a, Result<(), Error>>
Now we can specify what the return value borrows from inline, avoiding the problem that 'b isn't in scope for a where bound. Since send_and_expect already returns a BoxFuture anyway in your example, this may be the best solution for you.
Use a trait implemented on a ZST instead of a fn pointer
Resorting to boxing and dynamic dispatch to satisfy a compile-time issue might strike some as distasteful, and there is a small performance penalty. This is a trick that can be used to make this work with static dispatch, at the cost of some verbosity. We will have to define our own trait, ConnectFn:
trait ConnectFn<'a> {
type ConnectFuture: Future<Output=Result<(), Error>> + Send + 'a;
fn connect(&self, client: &'a mut Client, message: &'a Message) -> Self::ConnectFuture;
}
Then, we can make the signature of connection_retrier the following:
pub fn connection_retrier<'a, F>(
f: F,
f_self: &'a mut Self,
f_m: &'a Message,
) -> BoxFuture<'a, Result<(), Error>>
where F: for<'b> ConnectFn<'b>
And replace f(f_self, f_m) in the body with f.connect(f_self, f_m). This avoids the need for the return type of f to appear anywhere in connection_retrier's signature, circumventing the issue we had before.
We can then replace our function send_and_expect with a zero-sized type SendAndExpect which implements ConnectFn, like so:
struct SendAndExpect;
impl<'a> ConnectFn<'a> for SendAndExpect
{
type ConnectFuture = BoxFuture<'a, Result<(), Error>>;
fn connect(&self, client: &'a mut Client, message: &'a Message) -> Self::ConnectFuture {
/* the body of Client::send_and_expect goes here. `self` is ignored */
}
}
With this, we can call connection_retrier like so:
Client::connection_retrier(SendAndExpect, &mut client, &message)
Which is pretty nice. The definition of SendAndExpect itself can be made even nicer, close to that of a regular fn, using macros, but this is left as an exercise to the reader.
Sidenote: You might think that it would be possible to have a blanket implementation of ConnectFn on suitable fn pointers and avoid the need for a new type, but sadly you would be wrong. You'll either run into the same issue with impossible where clause bounds or trait solver limitations when dealing with universally quantified types.
The reason lies within these three lines:
pub fn connection_retrier<'a, T>(
f: fn(&'a mut Self, &'a Message) -> T,
f_self: &'a mut Self,
For f, you are telling the compiler that it will receive a mutable reference with a lifetime equal to that of the mutable reference that connection_retrier receives for f_self (in this case it is 'a).
When you change f's signature to f: fn(&mut Self, &Message) -> T, you are letting the compiler determine the lifetime, which it correctly does by assigning it a lifetime shorter than 'a and hence why it compiles.

Chaining a sequence of things that are either owned or referenced

I'm attempting to have a trait for things that can either simply contain other things, or create them on demand, given a thing's name. Those contained things should in turn be able to do the same, creating a hierarchy of sorts. Here's a minimal code:
use std::ops::Deref;
pub enum BoxOrRef<'a, T: ?Sized + 'a> {
Boxed(Box<T>),
Ref(&'a T),
}
impl<'a, T: ?Sized + 'a> Deref for BoxOrRef<'a, T> {
type Target = T;
fn deref(&self) -> &T {
match self {
BoxOrRef::Boxed(b) => &b,
BoxOrRef::Ref(r) => r,
}
}
}
pub trait Elem {
fn get_subelem<'a, 'b>(&'a self, name: &'b str) -> Option<BoxOrRef<'a, dyn Elem>>;
}
pub trait Table {
fn get_elem<'a, 'b>(&'a self, name: &'b str) -> Option<BoxOrRef<'a, dyn Elem>>;
}
fn resolve_name<'a, T: Table + ?Sized>(
table: &'a T,
name: &[String],
) -> Option<BoxOrRef<'a, dyn Elem>> {
let mut segments = name.iter();
if let Some(first_segment) = segments.next() {
segments.fold(table.get_elem(&first_segment), |res, next| {
res.and_then(|elem| elem.get_subelem(next))
})
} else {
None
}
}
The lifetime checker however, is not satisfied by this:
error[E0597]: `elem` does not live long enough
--> src/lib.rs:33:33
|
33 | res.and_then(|elem| elem.get_subelem(next))
| ^^^^ - borrowed value only lives until here
| |
| borrowed value does not live long enough
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 26:17...
--> src/lib.rs:26:17
|
26 | fn resolve_name<'a, T: Table + ?Sized>(
| ^^
I need to somehow extend lifetimes of the intermediate res's. I guess I could put them in a struct and tweak the return type of resolve_name to return it along with the final element, but that strikes me as rather clumsy way of doing it. Is there a better solution?
The return value of get_subelem can't outlive the &self borrow you used to call it, because the signature of get_subelem says so explicitly:
fn get_subelem<'a, 'b>(&'a self, name: &'b str) -> Option<BoxOrRef<'a, dyn Elem>>;
// ^^ ^^
In order to get a BoxOrRef<'a, _>, you have to borrow self for the lifetime 'a. In the caller, elem can't outlive the closure it belongs to, and get_subelem borrows elem, so it can't return a value that can escape that closure either.
You're trying to do something that is unsafe, and the compiler is right to stop you. In theory, table.get_elem could return a Boxed value, and elem.get_subelem could return an internal reference, and then the Box would be dropped when the closure returns, invalidating the reference.
Presumably that doesn't actually happen, so you have to tell the compiler that. One way is to decouple &self from BoxOrRef<'a, _>:
pub trait Elem<'a> {
fn get_subelem(&self, name: &str) -> Option<BoxOrRef<'a, dyn Elem<'a>>>;
}
The above change will make your example compile once you add lifetime parameters to all the Elems, but it puts you in an awkward position when implementing Elem: you can't return a reference to self, so practically everything has to be Boxed.
It's hard to make a good recommendation given the vagueness of the example, but I suggest you take a step back and think about whether BoxOrRef is the right abstraction here. Fundamentally, you can't do anything with a BoxOrRef that you couldn't do with a reference, because the BoxOrRef might be a reference. At the same time, you can't do anything with it that you couldn't do with a Box, because it might be a Box. std::borrow::Cow uses ToOwned to implement Clone and into_owned -- perhaps a similar approach could work for you. (And if you can, maybe just implement ToOwned for dyn Elem and use Cow directly.)

Explicit lifetime for Vec to slice conversation

I want a callback on changes inside a list, so I created simple example:
struct Foo;
struct FooList {
list: Vec<Foo>,
on_change_cb: Vec<Box<FnMut(& mut [Foo])>>,
}
impl FooList {
/*
pub fn register_on_change_cb2<F>(&mut self, cb: F) where F: FnMut(&mut [Foo]) {
self.on_change_cb.push(Box::new(cb));
}*/
pub fn register_on_change_cb(&mut self, cb: Box<FnMut(&mut [Foo])>) {
self.on_change_cb.push(cb);
}
pub fn push(&mut self, foo: Foo) {
self.list.push(foo);
self.on_change();
}
fn on_change(&mut self) {
for cb in &mut self.on_change_cb {
cb(&mut self.list);
}
}
}
I don't give any explicit hint to the compiler about lifetimes here: Vec<Box<FnMut(& mut [Foo])>>, so what lifetimes will the compiler use here? If I change the code like this:
struct FooList<'a> {
list: Vec<Foo>,
on_change_cb: Vec<Box<FnMut(&'a mut [Foo])>>,
}
impl<'a> FooList<'a> {
I get a compile time error:
error[E0495]: cannot infer an appropriate lifetime for borrow
expression due to conflicting requirements
How can I explicitly set the lifetimes in some way such that the lifetime of & mut [Foo] for the callback is less than, but not equal to the lifetime of the whole FooList object?
I have commented register_on_change_cb2, I want to allow calling register_on_change_cb without usage of Box::new but failed. If you uncomment register_on_change_cb2, you get the error:
error[E0310]: the parameter type F may not live long enough
How can I fix this error without the requirement of a 'static lifetime for callback? I just want to call Box::new on my side.
I'm going to try to answer your questions 1 and 3, because question 2 is either redundant or orthogonal to the others, and I can't tell what you really want to achieve by it. Perhaps it deserves a question of its own.
If you have a function that takes a reference, but it doesn't need any lifetime information about the reference, it must be able to accept a reference of any lifetime. Here's the explicit syntax for that (this is what the compiler infers from the code you wrote):
on_change_cb: Vec<Box<for<'b> FnMut(&'b mut [Foo])>>,
This is called a higher ranked trait bound or HRTB for short. They're mostly useful for the Fn traits, which is why they exist.
If the type of on_change_cb is Vec<Box<FnMut(&mut [Foo])>>, which doesn't carry any lifetime information, then it must not contain any references (except 'static references). You need to say that the type implementing FnMut may also contain (non-'static) references, as long as they outlive some lifetime 'a:
struct FooList<'a> {
list: Vec<Foo>,
on_change_cb: Vec<Box<FnMut(&mut [Foo]) + 'a>>,
}
This reads something like: "For each FooList object, there is a lifetime 'a such that every callback in the FooList contains only references that live for at least 'a." This interpretation may make it easier to write the prototype for register_on_change_cb2: it takes a callback that also contains only references that live for at least 'a.
impl<'a> FooList<'a> {
pub fn register_on_change_cb2<F>(&mut self, cb: F)
where F: FnMut(&mut [Foo]) + 'a
{
self.on_change_cb.push(Box::new(cb));
}
(I think I have the variance of 'a correct now -- a previous version of this answer had it wrong.)
The 'a lifetime lets the compiler guarantee that you never put a callback in the Box (and therefore the Vec) unless it lasts at least as long as the FooList itself. This is important because closures can capture references to values in the enclosing scope, as in the following code (playground link):
let longlived = String::from("hello");
let mut list = FooList {
list: Vec::new(),
on_change_cb: Vec::new(),
};
list.register_on_change_cb2(|_| println!("{}", longlived)); // ok
let shortlived = String::from("hello");
list.register_on_change_cb2(|_| println!("{}", shortlived)); // `shortlived` does not live long enough
list.push(Foo);
In this example, you can't insert the closure that captures shortlived because it doesn't outlive the (inferred) lifetime 'a. But you can insert the closure that captures longlived, because the compiler can infer a lifetime 'a that satisfies both constraints:
'a must outlive list, because list is of type FooList<'a>.
longlived must outlive 'a, because |_| println!("{}", longlived), which borrows longlived, is bounded by 'a in the call to register_on_change_cb2.
If you want to say that the callbacks don't borrow anything by-reference, the 'a lifetime is unnecessary, and in that case you could just add the 'static bound that the compiler suggests:
pub fn register_on_change_cb2<F>(&mut self, cb: F)
where F: FnMut(&mut [Foo]) + 'static

Confusing error in Rust with trait object lifetime

Can anyone tell what the problem is with the following code? The compiler is complaining about lifetimes, but the error message makes absolutely no sense. I've tried everything I could think of, but nothing seems to help.
use std::borrow::BorrowMut;
trait Trait<'a> {
fn accept(&mut self, &'a u8);
}
struct Impl<'a>{
myref: Option<&'a u8>,
}
impl<'a> Trait<'a> for Impl<'a> {
fn accept(&mut self, inp: &'a u8) { self.myref = Some(inp); }
}
fn new<'a>() -> Box<Trait<'a> + 'a> {
Box::new(Impl{myref: None})
}
fn user<'a>(obj: &mut Trait<'a>) {}
fn parent<'a>(x: &'a u8) {
let mut pool = new();
user(pool.borrow_mut());
}
The compiler error is
error: `pool` does not live long enough
--> src/wtf.rs:22:10
|
22 | user(pool.borrow_mut());
| ^^^^ does not live long enough
23 | }
| - borrowed value dropped before borrower
|
= note: values in a scope are dropped in the opposite order they are created
Which makes absolutely no sense. How is the borrower outliving anything? I'm not even using the borrowed value!
Ok, this does make sense, but it's hard to see due to lifetime elision. So, here's your code with all the lifetimes written out explicitly, and with irrelevant details culled:
use std::borrow::BorrowMut;
trait Trait<'a> {}
struct Impl<'a> {
myref: Option<&'a u8>,
}
impl<'a> Trait<'a> for Impl<'a> {}
fn new<'a>() -> Box<Trait<'a> + 'a> {
Box::new(Impl { myref: None })
}
fn user<'a, 'b>(obj: &'b mut (Trait<'a> + 'b)) {}
fn parent() {
/* 'i: */ let mut pool/*: Box<Trait<'x> + 'x>*/ = new();
/* 'j: */ let pool_ref/*: &'i mut Box<Trait<'x> + 'x>*/ = &mut pool;
/* BorrowMut<T>::borrow_mut<'d>(&'d mut Self) -> &'d mut T */
/* 'k: */ let pool_borrow/*: &'i mut (Trait<'x> + 'x)*/ = Box::borrow_mut(pool_ref);
user(pool_borrow);
}
Now, from the perspective of the last line of parent, we can work out the following equivalences by just reading the definition of user and substituting the lifetimes we have in parent:
'a = 'x
'b = 'i
'b = 'x
Furthermore, this lets us conclude that:
'x = 'i
This is the problem. Because of the way you've defined user, you've put yourself in a situation where the lifetime of the pool_ref borrow (which is equal to the lifetime of the pool storage location you're borrowing from) must be the same as the lifetime 'x being used in the thing being stored in pool.
It's a bit like the Box being able to have a pointer to itself before it exists, which doesn't make any sense.
Either way, the fix is simple. Change user to actually have the correct type:
fn user<'a, 'b>(obj: &'b mut (Trait<'a> + 'a)) {}
This matches the type produced by new. Alternately, just don't use borrow_mut:
user(&mut *pool)
This works because it is "re-borrowing". Calling borrow_mut translates the lifetimes more or less directly, but re-borrowing allows the compiler to narrow the borrows to shorter lifetimes. To put it another way, explicitly calling borrow_mut doesn't allow the compiler enough freedom to "fudge" the lifetimes to make them all line up, re-borrowing does.
As a quick aside:
I'm not even using the borrowed value!
Irrelevant. Rust does type- and lifetime-checking entirely locally. It never looks at the body of another function to see what it's doing; it goes on the interface alone. The compiler neither checks, nor cares, what you're doing inside a different function.
Note that there's more to the error message:
error: `pool` does not live long enough
--> src/main.rs:25:10
|>
25 |> user(pool.borrow_mut());
|> ^^^^
note: reference must be valid for the block at 23:25...
--> src/main.rs:23:26
|>
23 |> fn parent<'a>(x: &'a u8) {
|> ^
note: ...but borrowed value is only valid for the block suffix following statement 0 at 24:25
--> src/main.rs:24:26
|>
24 |> let mut pool = new();
|> ^
Let's look at user:
fn user<'a>(obj: &mut Trait<'a>) {}
This says that it will accept a mutable reference (with an unnamed lifetime) to a trait object parameterized with the lifetime 'a.
Turning to new, I'd say the method is highly suspicious:
fn new<'a>() -> Box<Trait<'a> + 'a> {
Box::new(Impl { myref: None })
}
This says that it will return a boxed trait object with whatever lifetime the caller specifies. That basically never makes sense.
All that said, I'm not clear why the code chooses to use borrow_mut. I would have written that more directly:
user(&mut *pool);
This dereferences the Box<Trait> to get a Trait, then takes a mutable reference, yielding &mut Trait, which compiles.
I cannot currently explain why BorrowMut differs in behavior.
I'm not sure why this error happens, but I can give solutions!
First, it seems that using borrow_mut unnecessarily restricts the lifetime of the returned reference. Using operators to create the reference solves the error.
fn parent() {
let mut pool = new();
user(&mut *pool);
}
However, if we don't do that, we can solve the error by adding a lifetime bound to the Trait object in user's obj argument.
fn user<'a>(obj: &mut (Trait<'a> + 'a)) {}

Unable to infer lifetime for borrow expression when using a trait with an explicit lifetime

use std::io::BufReader;
struct Foo {
buf: [u8, ..10]
}
trait Bar<'a> {
fn test(&self, arg: BufReader<'a>) {}
}
impl<'a, T: Bar<'a>> Foo {
fn bar(&'a mut self, t: T) {
t.test(BufReader::new(&self.buf));
let b = &mut self.buf;
}
fn baz(&self, t: T) {
t.test(BufReader::new(&self.buf));
}
}
fn main() {}
The code above fails to compile, with the error message:
lifetimes.rs:17:31: 17:40 error: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
lifetimes.rs:17 t.test(BufReader::new(&self.buf));
^~~~~~~~~
lifetimes.rs:16:5: 18:6 help: consider using an explicit lifetime parameter as shown: fn baz(&'a self, t: T)
lifetimes.rs:16 fn baz(&self, t: T) {
lifetimes.rs:17 t.test(BufReader::new(&self.buf));
lifetimes.rs:18 }
error: aborting due to previous error
However, if I add the named lifetime parameter, I cannot mutable borrow the buf field after calling test, as seen in fn bar. Commenting out the fn baz and trying to compile results in:
lifetimes.rs:13:22: 13:30 error: cannot borrow `self.buf` as mutable because it is also borrowed as immutable
lifetimes.rs:13 let b = &mut self.buf;
^~~~~~~~
lifetimes.rs:12:32: 12:40 note: previous borrow of `self.buf` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `self.buf` until the borrow ends
lifetimes.rs:12 t.test(BufReader::new(&self.buf));
^~~~~~~~
lifetimes.rs:14:6: 14:6 note: previous borrow ends here
lifetimes.rs:11 fn bar(&'a mut self, t: T) {
lifetimes.rs:12 t.test(BufReader::new(&self.buf));
lifetimes.rs:13 let b = &mut self.buf;
lifetimes.rs:14 }
^
error: aborting due to previous error
My understanding of this is that by adding the named lifetime 'a to the &'a mut self parameter, the reference taken by BufReader has a lifetime as long as the self reference is valid, which is until the end of the function. This conflicts with the mutable borrow of self.buf on the line after.
However, I am not sure why I need the named lifetime parameter on the self. It seems to me that the BufReader reference should be able to only exist for the lifetime of the t.test method call. Is the compiler complaining because the self.buf borrow must be ensured to live only as long as the &self borrow? How would I go about doing that while still only borrowing it for the lifetime of the method call?
Any help in going about fixing this problem and understanding more about the semantics here would be much appreciated!
Update
So I am still looking into this problem, and I have found this test case and this issue that show basically what I am trying to do. I would very much like to understand why the error pointed to by the test case link is an error.
I can see in the issue rustc output that attempts to point out what the error is, but I am having trouble understanding what exactly it is trying to say.
Removing all explicit lifetimes also works. I've found that I only add lifetimes when I'm sure I need them (i.e. to specifiy that two lifetimes should intersect at a given point which can't be known to the compiler).
I'm not sure exactly what you're going for, but this compiles (on rustc 0.13.0-nightly (cc19e3380 2014-12-20 20:00:36 +0000)).
use std::io::BufReader;
struct Foo {
buf: [u8, ..10]
}
trait Bar {
fn test(&self, arg: BufReader) {}
}
impl<T: Bar> Foo {
fn bar(&mut self, t: T) {
t.test(BufReader::new(&self.buf));
let b = &mut self.buf;
}
fn baz(&self, t: T) {
t.test(BufReader::new(&self.buf));
}
}
Edit
I'm going to copy-edit my comment here:
I originally thought that adding a lifetime or generic parameter to the trait / struct / enum was a shorthand for putting it on every method in the trait, but I was wrong. My current understanding is that you add a lifetime to the trait / struct / enum when that item needs to participate in the lifetime, likely because it is storing a reference with that lifetime.
struct Keeper<'a> {
counts: Vec<&'a i32>,
}
impl<'a> Keeper<'a> {
fn add_one(&mut self, count: &'a i32) {
if *count > 5 {
self.counts.push(count);
}
}
fn add_two<'b>(&mut self, count: &'b i32) -> i32 {
*count + 1
}
}
fn main() {
let mut cnt1 = 1;
let mut cnt2 = 2;
let mut k = Keeper { counts: Vec::new() };
k.add_one(&cnt1);
k.add_two(&cnt2);
// cnt1 += 1; // Errors: cannot assign to `cnt1` because it is borrowed
cnt2 += 1; // Just fine
println!("{}, {}", cnt1, cnt2)
}
Here, we've added a lifetime to Keeper because it might store the reference it is given. The borrow checker must assume that the reference is stored for good when we call add_one, so once we call that method, we can no longer mutate the value.
add_two, on the other hand, creates a fresh lifetime that can only be applied to that function invocation, so the borrow checker knows that once the function returns, it is the One True Owner.
The upshot is, if you need to store a reference, then there's nothing you can do at this level. Rust can't make sure you are safe, and that's something it takes seriously.
However, I bet you don't need to store the reference. Move the <'a, T: Bar<'a>> from the impl to the fn and you'll be good to go.
Said another way: I bet you should never have impl<A> if your trait or struct don't require it. Put the generics on the methods instead.
Original
This compiles, but I'm not 100% sure it does what you intended:
impl Foo {
fn baz<'a, T: Bar<'a>>(&'a self, t: T) {
t.test(BufReader::new(&self.buf));
}
}
I fell into this trap myself, so I'll paste what I was told:
Everything in the impl block is parameterized. I've actually never
seen type parameters added to impl blocks themselves that aren't part
of the trait or type definition. It's far more common to parameterize
the individual methods that need it.
Perhaps other comments / answers can help explain in further detail.

Resources