"temporary value dropped while borrowed" with capturing closure - rust

Please consider the following example (playground):
struct Animal<'a> {
format: &'a dyn Fn() -> (),
}
impl <'a>Animal<'a> {
pub fn set_formatter(&mut self, _fmt: &'a dyn Fn() -> ()) -> () {} // Getting rid of 'a here satisfies the compiler
pub fn bark(&self) {}
}
fn main() {
let mut dog: Animal = Animal { format: &|| {()} };
let x = 0;
dog.set_formatter(&|| {
println!("{}", x); // Commenting this out gets rid of the error. Why?
});
dog.bark(); // Commenting this out gets rid of the error. Why?
}
This gives the following compilation error:
Compiling playground v0.0.1 (/playground)
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:13:24
|
13 | dog.set_formatter(&|| {
| ________________________^
14 | | println!("{}", x); // Commenting this out gets rid of the error. Why?
15 | | });
| | ^ - temporary value is freed at the end of this statement
| |_____|
| creates a temporary which is freed while still in use
16 | dog.bark(); // Commenting this out gets rid of the error. Why?
| --- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
error: aborting due to previous error
For more information about this error, try `rustc --explain E0716`.
error: could not compile `playground`
To learn more, run the command again with --verbose.
This kind of makes sense as the closure that I'm passing to dog.set_formatter(...) is indeed a temporary which (I guess) is freed when execution proceeds to dog.bark();.
I know that getting rid of the explicit lifetime annotation in the implementation of set_formatter seems to satisfy the compiler (note the missing 'a before dyn):
pub fn set_formatter(&mut self, _fmt: & dyn Fn() -> ()) -> () {}
However, I don't understand the following:
Why does the problem go away when I comment out println!("{}", x); inside the closure? I'm still passing a temporary which I expect the compiler to complain about, but it doesn't.
Why does the problem go away when I comment out dog.bark(); at the end? Again, I'm still passing a temporary closure which is freed but now the compiler is happy. Why?

The first thing to understand is that &|| () has a 'static lifetime:
fn main() {
let closure: &'static dyn Fn() = &|| (); // compiles
}
Another thing worth mentioning is that a closure's lifetime cannot exceed the lifetime of any of the variables it captures from its environment, which is why if we try to pass a non-static variable to our static closure it would fail to compile:
fn main() {
let x = 0; // non-static temporary variable
let closure: &'static dyn Fn() = &|| {
println!("{}", x); // x reference captured by closure
}; // error: trying to capture non-static variable in static closure
}
We'll come back to that. Anyway, so if I have a struct which is generic over references, and I pass it a 'static reference, I'll have a 'static instance of that struct:
struct Dog<'a> {
format: &'a dyn Fn(),
}
fn main() {
let dog: Dog<'static> = Dog { format: &|| () }; // compiles
}
The second thing to understand is once you instantiate a type you cannot change it. This includes any of its generic parameters, including lifetimes. Once you have a Dog<'static> it will always be a Dog<'static>, you cannot convert it into a Dog<'1> for some anonymous lifetime '1 that is shorter than 'static.
This has some strong implications, one of which is that your set_formatter method probably doesn't behave how you think it behaves. Once you have a Dog<'static> you can only pass 'static formatters to set_formatter. The method looks like this:
impl<'a> Dog<'a> {
fn set_formatter(&mut self, _fmt: &'a dyn Fn()) {}
}
But since we know we're working with a Dog<'static> we can substitute out the generic lifetime parameter 'a with 'static to see what we're really working with:
// what the impl would be for Dog<'static>
impl Dog {
fn set_formatter(&mut self, _fmt: &'static dyn Fn()) {}
}
So now that we've gotten all of that context out of the way let's get to your actual questions.
Why does the problem go away when I comment out println!("{}", x); inside the closure? I'm still passing a temporary which I expect the compiler to complain about, but it doesn't.
Why it fails, with comments:
struct Dog<'a> {
format: &'a dyn Fn(),
}
impl<'a> Dog<'a> {
fn set_formatter(&mut self, _fmt: &'a dyn Fn()) {}
}
fn main() {
let mut dog: Dog<'static> = Dog { format: &|| () };
// x is a temporary value on the stack with a non-'static lifetime
let x = 0;
// this closure captures x by reference which ALSO gives it a non-'static lifetime
// and you CANNOT pass a non-'static closure to a Dog<'static>
dog.set_formatter(&|| {
println!("{}", x);
});
}
The reason this error is "fixed" by commenting out the line println!("{}", x); is because it gives the closure a 'static lifetime again since it no longer borrows the non-'static variable x.
Why does the problem go away when I comment out dog.bark(); at the end? Again, I'm still passing a temporary closure which is freed but now the compiler is happy. Why?
This weird edge case only seems to happen when we don't explicitly type-annotate the dog variable with Dog<'static>. When a variable doesn't have an explicit type annotation the compiler attempts to infer its type, but it does so lazily, and tries to be as flexible as possible, giving the benefit of the doubt to the programmer, in order to make the code compile. It really should throw a compile error even without the dog.bark() but it doesn't for whatever mysterious reasons. The point is it's not the dog.bark() line that is making the code fail to compile, it should be failing to compile at the set_formatter line regardless, but for whatever reason the compiler doesn't bother to throw an error until you try to use dog again after that offending line. Even just dropping dog will trigger the error:
struct Dog<'a> {
format: &'a dyn Fn(),
}
impl<'a> Dog<'a> {
fn set_formatter(&mut self, _fmt: &'a dyn Fn()) {}
}
fn main() {
let mut dog = Dog { format: &|| () };
let x = 0;
dog.set_formatter(&|| {
println!("{}", x);
});
drop(dog); // triggers "temp freed" error above
}
And since we've come this far, let's answer your unofficial third question, paraphrased by me:
Why does getting rid of the 'a in the set_formatter method satisfy the compiler?
Because it changes what is effectively this for Dog<'static>:
// what the impl would be for Dog<'static>
impl Dog {
fn set_formatter(&mut self, _fmt: &'static dyn Fn()) {}
}
Into this:
// what the impl would now be for Dog<'static>
impl Dog {
fn set_formatter(&mut self, _fmt: &dyn Fn()) {}
}
So now you can pass non-'static closures to a Dog<'static> although it's pointless since the method doesn't actually do anything, and the compiler will complain again the moment you actually try to set the closure in the Dog<'static> struct.

Related

Using FnMut() closures in a static function

Background: I'm trying to avoid the use of Mutex/RefCell/Option dance in an interrupt handler for an embedded system. I do not want to use the heap (and I don't think it should be necessary -- but feel free to show me wrong). I can't use std. I've looked at cortex-m-rtfm and it's neat, but pretty invasive. And anyway, this is a bit of a learning exercise. If it works out, I would prefer to use closures to handle interrupts since it feels closer to bare Rust. I am a total Rust newbie -- I've been working with it for about a week. I have tried a lot of different variants of this as I've read through documentation, re-read the Rust book, blog posts, etc.,. I cannot figure what I'm doing wrong here.
Here's the sample code. Questions to follow:
use core::cell::UnsafeCell;
pub struct Handler<'a> {
h: UnsafeCell<&'a dyn FnMut()>,
}
impl<'a> Handler<'a> {
pub fn new<T: FnMut()>(closure: &'a dyn FnMut()) -> Self {
Handler {
h: UnsafeCell::new(closure),
}
}
pub fn call(&self) {
unsafe {
// NOTE: type returned by `self.h.get()` is
// `*mut &'a (dyn std::ops::FnMut() + 'a)`
let h: *mut FnMut() = self.h.get();
h();
}
}
}
unsafe impl<'a> Sync for Handler<'a> {}
fn default_handler() {}
static HANDLER: Handler = Handler {
h: UnsafeCell::new(&default_handler),
};
#[test]
fn call_handler() {
let mut a: u32 = 0;
let foo = move || a += 1;
let mut handler = Handler::new(&foo);
handler.call();
a += 2; // Shouldn't this cause compilation failure because `a`
// was moved into the closure above?
assert_eq!(a, 1);
}
Error
error[E0618]: expected function, found `*mut dyn std::ops::FnMut()`
--> src/lib.rs:19:13
|
18 | let h: *mut FnMut() = self.h.get();
| - `*mut dyn std::ops::FnMut()` defined here
19 | h();
| ^--
| |
| call expression requires function
error[E0277]: expected a `std::ops::Fn<()>` closure, found `(dyn std::ops::FnMut() + 'a)`
--> src/lib.rs:18:35
|
18 | let h: *mut FnMut() = self.h.get();
| ^^^^^^^^^^^^ expected an `Fn<()>` closure, found `(dyn std::ops::FnMut() + 'a)`
|
= help: the trait `std::ops::Fn<()>` is not implemented for `(dyn std::ops::FnMut() + 'a)`
= note: wrap the `(dyn std::ops::FnMut() + 'a)` in a closure with no arguments: `|| { /* code */ }
= note: required because of the requirements on the impl of `std::ops::FnMut<()>` for `&'a (dyn std::ops::FnMut() + 'a)`
= note: required for the cast to the object type `dyn std::ops::FnMut()`
Explanation: Hopefully, my intentions are obvious: I'll set up the closure for HANDLER in main, before going into a busy-loop that never exits. The closure will mutably borrow the stuff the interrupt handler needs for its operation, preventing its use in other contexts. Since main never exits, stack-allocated variables within it are effectively 'static, so there shouldn't be a problem with referencing them at any point after the closure is set. The interrupt handler itself (not shown) will simply call the closure to do its work. To work around the storage of a closure (which is not Sized) in a static, I need to store a reference to the closure. UnsafeCell isn't necessarily required, but since I'm using FnMut() its referents need to be mutable, which runs into statics require immutable values when trying to set up default_handler during the creation of a static mut HANDLER.
Questions:
As posted, this code doesn't compile. For some reason, the
assignment let h: *mut FnMut() = self.h.get() tells me that it
expected an Fn<()> closure, found (dyn std::ops::FnMut() + 'a). Well, I know why it found that type. But why is it expecting Fn<()>?
In the call_handler test, why is this compiling at all? The foo closure moves its captured variable a. How is it possible to mutate it after the closure definition? When I've tried this code with a type that doesn't implement Copy, it fails as expected, but I'm frankly surprised that trait matters. Isn't the point that foo owns a now?
I realize there are potential issues with changing HANDLER.h at arbitrary points in the code, but I will worry about solving those later, after there's a viable proof-of-concept.
I have found a way to do what I want. It is grossly unsafe for general use, and appropriate mechanisms to hide its lack of safety have to be investigated, and may not even be possible. The main trick is to convert the mutable trait object into a dynamic one using an as cast, and using core::mem::transmute to change its lifetime to static. Here's the code:
use core::cell::UnsafeCell;
use core::mem::transmute;
struct Handler {
h: UnsafeCell<*const dyn FnMut()>,
}
impl Handler {
unsafe fn replace(&self, f: &dyn FnMut()) {
let f_static: &'static dyn FnMut() = transmute(f);
*self.h.get() = f_static;
}
unsafe fn call(&self) {
let f: &mut dyn FnMut() = &mut *(*self.h.get() as *mut dyn FnMut());
f();
}
}
unsafe impl Sync for Handler {}
fn default_handler() {}
static HANDLER: Handler = Handler {
h: UnsafeCell::new(&default_handler),
};
fn main() {
let mut x: u32 = 0;
let closure = || x += 2;
unsafe {
HANDLER.replace(&closure);
HANDLER.call();
};
println!("x: {}", x); // Prints 2
}
The closure wrapped by Handler.h is inside an UnsafeCell to facilitate its replacement at runtime (inside, and only inside, the main loop).

Lifetime error using associated type of trait with lifetime parameter

I'm getting a lifetime error with Rust 1.14 due to using an associated type, demonstrated by the following two similar programs, the first which compiles without error and the second which has the lifetime error.
Program #1 — compiles without error
trait Trait<'a> {
type T;
}
struct Impl;
impl<'a> Trait<'a> for Impl {
type T = std::marker::PhantomData<&'a ()>;
}
struct Alpha<'a, T: Trait<'a>> {
_dummy: std::marker::PhantomData<(&'a (), T)>,
}
fn use_alpha<'a>(_: &'a Alpha<'a, Impl>) {}
fn main() {
for x in Vec::<Alpha<Impl>>::new().into_iter() {
use_alpha(&x); // <-- ok
}
}
Program #2 — has the lifetime error
trait Trait<'a> {
type T;
}
struct Impl;
impl<'a> Trait<'a> for Impl {
type T = std::marker::PhantomData<&'a ()>;
}
struct Alpha<'a, T: Trait<'a>> {
_dummy: std::marker::PhantomData<(&'a (), T::T)>,
}
fn use_alpha<'a>(_: &'a Alpha<'a, Impl>) {}
fn main() {
for x in Vec::<Alpha<Impl>>::new().into_iter() {
use_alpha(&x); // <-- !error!
}
}
Here's the compile-time error for the second program:
error: `x` does not live long enough
--> src/main.rs:20:5
|
19 | use_alpha(&x); // <-- !error!
| - borrow occurs here
20 | }
| ^ `x` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
Here's the diff for the two programs:
#[derive(Clone)]
struct Alpha<'a, T: Trait<'a>> {
- _dummy: std::marker::PhantomData<(&'a (), T)>,
+ _dummy: std::marker::PhantomData<(&'a (), T::T)>,
}
The only difference is that by changing the first program to use an associated type instead of the type parameter in the struct definition, a lifetime error occurs. I have no idea why this happens. As far as I can tell, the associated type should not incur any additional lifetime restrictions—it's all just 'a, but clearly the Rust compiler disagrees.
If I replace iteration in the second program's main function with simple instantiation, then the lifetime error goes away. That is:
fn main() {
let x = Alpha::<Impl> { _dummy: std::marker::PhantomData };
use_alpha(&x); // <-- ok in both programs
}
I don't understand why iteration is any different than direct instantiation.
In use_alpha, you have used the same lifetime for the reference to Alpha and its lifetime parameter. Its lifetime parameter then becomes the lifetime of Impl's Trait::T. The note gives a hint about the order that values are dropped: Impl::T gets dropped before Impl because it's part of Impl's definition, but that means that some parts of Alpha have already been dropped while it is still around.
You can fix this by using two lifetimes parameters in use_alpha:
fn use_alpha<'a, 'b>(_: &'a Alpha<'b, Impl>) {}
This will allow the compiler to infer different lifetimes for each of the types.

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)) {}

Borrow checker failing when using traits as type parameter

I have a problem with the borrow checker when using traits as type parameter in a structure:
trait Trait {}
struct FooBar;
impl Trait for FooBar{}
struct Observer<Arg> {
action: Box<Fn(Arg) + Send>,
// Other fields
}
impl <Arg> Observer<Arg> {
fn new(action: Box<Fn(Arg) + Send>) -> Observer<Arg> {
Observer{action: action}
}
fn execute(&self, arg: Arg) {
(*self.action)(arg);
}
}
fn test() {
let mut foobar = FooBar;
{
let mut observer = Observer::new(Box::new(|&: param: &mut Trait| {
// do something with param here
}));
observer.execute(&mut foobar); // First borrow passes ...
observer.execute(&mut foobar); // This fails as "foobar" is already borrowed
} // The previous borrow ends here (lifetime of "observer")
}
The output is:
error: cannot borrow `foobar` as mutable more than once at a time
observer.execute(&mut foobar); // This fails as "foobar" is already borrowed
^~~~~~
note: previous borrow of `foobar` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `foobar` until the borrow ends
observer.execute(&mut foobar); // First borrow passes ...
^~~~~~
note: previous borrow ends here
{
...
} // The previous borrow ends here (lifetime of "observer")
^
Yet the following example works:
trait Trait {}
struct FooBar;
impl Trait for FooBar{}
struct Observer {
action: Box<Fn(&mut Trait) + Send>,
// Other fields
}
impl Observer {
fn new(action: Box<Fn(&mut Trait) + Send>) -> Observer {
Observer{action: action}
}
fn execute(&self, arg: &mut Trait) {
(*self.action)(arg);
}
}
fn test() {
let mut foobar = FooBar;
{
let mut observer = Observer::new(Box::new(|&: param: &mut Trait| {
// do something with param here
}));
observer.execute(&mut foobar);
observer.execute(&mut foobar);
}
}
This looks really weird to me, as the second example is just an instantiation of the first example, and I could probably (painfully) implement the same thing with macros.
I guess this is quite tricky, as I need to know the type of the parameter taken by the closure, but I don't need to store this reference ...
Is this a bug in the borrow checker? Or am I doing something wrong?
rustc 1.0.0-nightly (44a287e6e 2015-01-08 17:03:40 -0800)
EDIT 1: Precised the use case
EDIT 2: As explained in the answer below, the issue is that the borrow checker forces the lifetime of Observer<&mut Type> to be the same as the &mut Type, so in fact the issue is not related to the fact that we use a trait as a type parameter (it does the same with an actual structure).
So in my case, I can have a workaround by defining Observer<Arg> like this:
struct Observer<Arg> {
action: Box<Fn(&mut Arg) + Send>,
}
so the type parameter Arg itself is not a reference, but this makes the code less generic. Anybody has a better solution?
The problem here is that the borrow checker is forcing the lifetime of the &mut Trait reference to be the same as the whole GenericStruct. I believe this is because the reference is a type parameter of the struct itself.
Since your struct has no fields that store the reference (if you need to do this in your original code, please update your question), then you can move the type parameter to the method itself, instead of the struct:
trait Trait{}
struct FooBar;
impl Trait for FooBar{}
struct GenericStruct;
impl GenericStruct {
fn bar<T>(&self, _: T) {}
}
fn main() {
let mut foobar = FooBar;
{
let foo = GenericStruct;
foo.bar(&mut foobar);
foo.bar(&mut foobar);
}
}
This will make the borrow last only as long as the call to foo.bar().

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