Closed
Description
Looks like a bug in the borrow checker:
use std::cell::RefCell;
fn main() {
let c = Caller::new();
let mut y = 1; // NOT in RefCell.
c.pusher().push(|| { y = y * 2u; });
c.pusher().push(|| { y = y * 3u; }); // Second mutable borrow of y?!
c.call();
println!("{}", y); // Prints 6.
}
// Collects multiple closures then call all of them.
struct Caller<'c> {
funs: RefCell<Vec<||:'c -> ()>>,
} impl<'c> Caller<'c> {
fn new() -> Caller<'c> {
Caller { funs: RefCell::new(Vec::new()) }
}
fn pusher(&'c self) -> Pusher<'c> {
Pusher { caller: self }
}
fn call(&self) {
let ref mut funs = self.funs.borrow_mut();
loop {
match funs.pop() {
Some(f) => f(),
_ => break,
}
}
}
}
// Pushes closures into a caller.
trait Push<'c> {
fn push<'f: 'c>(self, push: ||:'f -> ());
}
struct Pusher<'c> {
caller: &'c Caller<'c>
}
// /*
impl<'c> Push<'c> for Pusher<'c> {
fn push<'f: 'c>(self, fun: ||:'f -> ()) {
self.caller.funs.borrow_mut().push(fun)
}
}
// Using the following impl (without trait) makes compilation fail correctly: */
/*
impl<'c> Pusher<'c> {
fn push<'f: 'c>(self, fun: ||:'f -> ()) {
self.caller.funs.borrow_mut().push(fun)
}
}
*/
This compiles and runs fine. It also compiles when using unboxed closures instead (using type param F: FnOnce<(), ()>+'c and F members). Using the non-trait impl, however, causes compilation to fail correctly:
<anon>:7:21: 7:39 error: cannot borrow `y` as mutable more than once at a time
<anon>:7 c.pusher().push(|| { y = y * 3u; }); // Second mutable borrow of y?!
^~~~~~~~~~~~~~~~~~
<anon>:7:30: 7:31 note: borrow occurs due to use of `y` in closure
<anon>:7 c.pusher().push(|| { y = y * 3u; }); // Second mutable borrow of y?!
^
<anon>:6:21: 6:39 note: previous borrow of `y` occurs here due to use in closure; the mutable borrow prevents subsequent moves, borrows, or modification of `y` until the borrow ends
<anon>:6 c.pusher().push(|| { y = y * 2u; });
^~~~~~~~~~~~~~~~~~
<anon>:10:2: 10:2 note: previous borrow ends here
<anon>:3 fn main() {
...
<anon>:10 }
^
<anon>:9:20: 9:21 error: cannot borrow `y` as immutable because it is also borrowed as mutable
<anon>:9 println!("{}", y); // Prints 6.
^
note: in expansion of format_args!
<std macros>:2:23: 2:77 note: expansion site
<std macros>:1:1: 3:2 note: in expansion of println!
<anon>:9:5: 9:23 note: expansion site
<anon>:6:21: 6:39 note: previous borrow of `y` occurs here due to use in closure; the mutable borrow prevents subsequent moves, borrows, or modification of `y` until the borrow ends
<anon>:6 c.pusher().push(|| { y = y * 2u; });
^~~~~~~~~~~~~~~~~~
<anon>:10:2: 10:2 note: previous borrow ends here
<anon>:3 fn main() {
...
<anon>:10 }
^
<anon>:9:20: 9:21 error: cannot borrow `y` as immutable because it is also borrowed as mutable
<anon>:9 println!("{}", y); // Prints 6.
^
note: in expansion of format_args!
<std macros>:2:23: 2:77 note: expansion site
<std macros>:1:1: 3:2 note: in expansion of println!
<anon>:9:5: 9:23 note: expansion site
<anon>:7:21: 7:39 note: previous borrow of `y` occurs here due to use in closure; the mutable borrow prevents subsequent moves, borrows, or modification of `y` until the borrow ends
<anon>:7 c.pusher().push(|| { y = y * 3u; }); // Second mutable borrow of y?!
^~~~~~~~~~~~~~~~~~
<anon>:10:2: 10:2 note: previous borrow ends here
<anon>:3 fn main() {
...
<anon>:10 }
^
error: aborting due to 3 previous errors
playpen: application terminated with error code 101
Program ended.