Assignment to a borrowed in RefCell - rust

The following code gives me the "Assignment to borrowed a" error. Hows the compiler able to know that? Is the compiler special casing RefCell or is there something in the language that allows it to tell the compiler you have a borrowed value?
use std::cell::RefCell;
fn main() {
let mut a = RefCell::new(A{a:5});
let mut b = a.borrow_mut();
a = RefCell::new(A{a:6});
}
Also, why does this code work which seems to be doing the exact same thing?
use std::cell::RefCell;
fn main() {
let mut a = Box::new(A{a:5});
let mut b = &mut a;
a = Box::new(A{a:6});
}

The compiler is not special casing RefCell. But borrow_mut() has the following signature:
pub fn borrow_mut(&self) -> RefMut<'_, T>
So it returns a RefMut that keeps the RefCell borrowed while it is alive (because of the '_, that according to the lifetime elision rules borrows from self). So while it is alive, you cannot assign to the RefCell because it is borrowed.
The reason the second case with a mutable reference works is that since mutable references don't implement Drop (a more precise term is that they don't have a drop glue, that is, neither they implement Drop nor any of their fields (which is none for mutable references) has a drop glue, recursively), the compiler shortens the borrow and drop the reference early. But it cannot do that with the RefMut from the RefCell because it implements Drop, and thus early-dropping it would change program behavior.

Related

Rust: when does function reborrow / move its argument? e.g., fn foo<T>(x: &mut T) vs. fn foo<T>(x: T) [duplicate]

fn main() {
let mut name = String::from("Charlie");
let x = &mut name;
let y = x; // x has been moved
say_hello(y);
say_hello(y); // but y has not been moved, it is still usable
change_string(y);
change_string(y);
}
fn say_hello(s: &str) {
println!("Hello {}", s);
}
fn change_string(s: &mut String) {
s.push_str(" Brown");
}
When I assign x to y x has been moved. However, I would expect something with move semantics to be moved when I use it in a function. However, I can still use the reference after subsequent calls. Maybe this has to do with say_hello() taking a immutable reference but change_string() takes a mutable reference but the reference is still not moved.
You are completely right with both your reasoning and your observations. It definitely looks like things should be happening the way you describe it. However, the compiler applies some convenience magic here.
Move semantics generally apply in Rust for all types that do not implement the Copy trait. Shared references are Copy, so they are simply copied when assigned or passed to a function. Mutable references are not Copy, so they should be moved.
That's where the magic starts. Whenever a mutable reference is assigned to a name with a type already known to be a mutable reference by the compiler, the original reference is implicitly reborrowed instead of being moved. So the function called
change_string(y);
is transformed by the compiler to mean
change_string(&mut *y);
The original reference is derefenced, and a new mutable borrow is created. This new borrow is moved into the function, and the original borrow gets released once the function returns.
Note that this isn't a difference between function calls and assignments. Implicit reborrows happen whenever the target type is already known to be a mutable reference by the compiler, e.g. because the pattern has an explicit type annotation. So this line also creates an implicit reborrow, since we explicitly annotated it as a mutable reference type:
let y: &mut _ = x;
This function call on the other hand moves (and thus consumes) the mutable reference y:
fn foo<T>(_: T) {}
[...]
foo(y);
The generic type T here isn't explicitly a mutable reference type, so no implicit reborrow occurs, even though the compiler infers that the type is a mutable reference – just as in the case of your assignment let y = x;.
In some cases, the compiler can infer a generic type is a mutable reference even in the absence of an explicit type annotation:
fn bar<T>(_a: T, _b: T) {}
fn main() {
let mut i = 42;
let mut j = 43;
let x = &mut i;
let y = &mut j;
bar(x, y); // Moves x, but reborrows y.
let _z = x; // error[E0382]: use of moved value: `x`
let _t = y; // Works fine.
}
When inferring the type of the first parameter, the compiler doesn't know yet it's a mutable reference, so no implicit reborrow occurs and x is moved into the function. However, when reaching the second parameter, the compiler has already inferred that T is a mutable reference, so y is implicitly reborrowed. (This example is a good illustration why adding compiler magic to make things "just work" generally is a bad idea. Explicit is better than implicit.)
Unfortunately, this behaviour currently isn't documented in the Rust reference.
See also:
Stuff the Identity Function Does (in Rust)
Discussion of the topic on the Rust users forum
Why is the mutable reference not moved here?

Immutable object changing to mutable depending on function signature

Checkout the Rust code below. It compiles
fn main() {
let vec0 = Vec::new();
let mut vec1 = fill_vec(vec0);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}
fn fill_vec(mut vec: Vec<i32>) -> Vec<i32> {
vec.push(22);
vec.push(44);
vec.push(66);
vec
}
Here I am declaring vec0 as immutable but fill_vec takes in a mutable vector. Depending on the function signature it seems Rust is changing the nature of the argument being passed.
My question is, this obviously seems like a "shot yourself in the foot" instant. Why does Rust allow this? Or, is this actually safe and I am missing something?
There are different things at play here that can all explain why this behavior make sense:
First of, mut doesn't really mean "mutable". There are such things as interior mutability, Cells, Mutexes, etc., which allow you to modify state without needing a single mut. Rather, mut means that you can get mutually exclusive references.
Second, mutability is a property of a binding. vec0 in main and vec in fill_vec are different bindings, so they can have different mutability.
See also:
What does 'let x = x' do in Rust?
Finally ownership: fill_vec takes full ownership of its parameter, which effectively doesn't exist anymore in main. Why should the function not be allowed to do whatever it wants with its owned parameters? Had the function taken the parameter as a mutable reference, you would have needed to declare the original binding as mut:
fn main() {
let mut vec0 = Vec::new();
// ^^^ now _needs_ a mutable binding
fill_vec(&mut vec0);
// ^^^^ needs an explicit `&mut` reference
}
fn fill_vec(vec: &mut Vec<i32>) {
// ^^^^ borrows rather than take ownership
// …
}
You're making the argument vec of fill_vec mutable. You are still passing the vec by value.
If you wanted a mutable reference you would have vec: &mut Vec<i32>.

Can I coerce a lifetime parameter to a shorter lifetime (soundly) even in the presence of `&mut T`?

I'm trying to make a tree with parent pointers in Rust. A method on the node struct is giving me lifetime issues. Here's a minimal example, with lifetimes written explicitly so that I can understand them:
use core::mem::transmute;
pub struct LogNode<'n>(Option<&'n mut LogNode<'n>>);
impl<'n> LogNode<'n> {
pub fn child<'a>(self: &'a mut LogNode<'n>) -> LogNode<'a> {
LogNode(Some(self))
}
pub fn transmuted_child<'a>(self: &'a mut LogNode<'n>) -> LogNode<'a> {
unsafe {
LogNode(Some(
transmute::<&'a mut LogNode<'n>, &'a mut LogNode<'a>>(self)
))
}
}
}
(Playground link)
Rust complains about child...
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'n due to conflicting requirements
...but it's fine with transmuted_child.
I think I understand why child won't compile: the self parameter's type is &'a mut LogNode<'n> but the child node contains an &'a mut LogNode<'a>, and Rust doesn't want to coerce LogNode<'n> to LogNode<'a>. If I change the mutable references to shared references, it compiles fine, so it sounds like the mutable references are a problem specifically because &mut T is invariant over T (whereas &T is covariant). I guess the mutable reference in LogNode bubbles up to make LogNode itself invariant over its lifetime parameter.
But I don't understand why that's true—intuitively it feels like it's perfectly sound to take LogNode<'n> and shorten its contents' lifetimes by turning it into a LogNode<'a>. Since no lifetime is made longer, no value can be accessed past its lifetime, and I can't think of any other unsound behavior that could happen.
transmuted_child avoids the lifetime issue because it sidesteps the borrow checker, but I don't know if the use of unsafe Rust is sound, and even if it is, I'd prefer to use safe Rust if possible. Can I?
I can think of three possible answers to this question:
child can be implemented entirely in safe Rust, and here's how.
child cannot be implemented entirely in safe Rust, but transmuted_child is sound.
child cannot be implemented entirely in safe Rust, and transmuted_child is unsound.
Edit 1: Fixed a claim that &mut T is invariant over the lifetime of the reference. (Wasn't reading the nomicon right.)
Edit 2: Fixed my first edit summary.
The answer is #3: child cannot be implemented in safe Rust, and transmuted_child is unsound¹. Here's a program that uses transmuted_child (and no other unsafe code) to cause a segfault:
fn oops(arg: &mut LogNode<'static>) {
let mut short = LogNode(None);
let mut child = arg.transmuted_child();
if let Some(ref mut arg) = child.0 {
arg.0 = Some(&mut short);
}
}
fn main() {
let mut node = LogNode(None);
oops(&mut node);
println!("{:?}", node);
}
short is a short-lived local variable, but since you can use transmuted_child to shorten the lifetime parameter of the LogNode, you can stuff a reference to short inside a LogNode that should be 'static. When oops returns, the reference is no longer valid, and trying to access it causes undefined behavior (segfaulting, for me).
¹ There is some subtlety to this. It is true that transmuted_child itself does not have undefined behavior, but because it makes other code such as oops possible, calling or exposing it may make your interface unsound. To expose this function as part of a safe API, you must take great care to not expose other functionality that would let a user write something like oops. If you cannot do that, and you cannot avoid writing transmuted_child, it should be made an unsafe fn.
To understand why the immutable version works and the mutable version is unsound (as written), we have to discuss subtyping and variance.
Rust mostly doesn't have subtyping. Values typically have a unique type. One place where Rust does have subtyping, however, is with lifetimes. If 'a: 'b (read 'a is longer than 'b), then, for example, &'a T is a subtype of &'b T, intuitively because longer lifetimes can be treated as if they were shorter.
Variance is how subtyping propagates. If A is a subtype of B, and we have a generic type Foo<T>, Foo<A> might be a subtype of Foo<B>, vice versa, or neither. In the first case, where the direction of subtyping stays the same, Foo<T> is said to be covariant with respect to T. In the second case, where the direction reverses, it's said to be contravariant, and in the third case, it's said to be invariant.
For this case, the relevant types are &'a T and &'a mut T. Both are covariant in 'a (so references with longer lifetimes can be coerced to references with shorter lifetimes). &'a T is covariant in T, but &'a mut T is invariant in T.
The reason for this is explained in the Nomicon (linked above), so I'll just show you the (somewhat simplified) example given there. Trentcl's code is a working example of what goes wrong if &'a mut T is covariant in T.
fn evil_feeder(pet: &mut Animal) {
let spike: Dog = ...;
// `pet` is an Animal, and Dog is a subtype of Animal,
// so this should be fine, right..?
*pet = spike;
}
fn main() {
let mut mr_snuggles: Cat = ...;
evil_feeder(&mut mr_snuggles); // Replaces mr_snuggles with a Dog
mr_snuggles.meow(); // OH NO, MEOWING DOG!
}
So why does the immutable version of child work, but not the mutable version? In the immutable version, LogNode contains an immutable reference to a LogNode, so by covariance in both the lifetime and the type parameter, LogNode is covariant in its lifetime parameter. If 'a: 'b, then LogNode<'a> is a subtype of LogNode<'b>.
We have self: &'a LogNode<'n>, which implies 'n: 'a (otherwise this borrow would outlast the data in LogNode<'n>). Thus, since LogNode is covariant, LogNode<'n> is a subtype of LogNode<'a>. Furthermore, covariance in immutable references again allows &'a LogNode<'n> to be a subtype of &'a LogNode<'a>. Thus, self: &'a LogNode<'n> can be coerced to &'a LogNode<'a> as needed for the return type in child.
For the mutable version, LogNode<'n> isn't covariant in 'n. The variance here comes down to the variance of &'n mut LogNode<'n>. But since there's a lifetime in the "T" part of the mutable reference here, the invariance of mutable references (in T) implies that this must also be invariant.
This all combines to show that self: &'a mut LogNode<'n> can't be coerced to &'a mut LogNode<'a>. So the function doesn't compile.
One solution to this is to add the lifetime bound 'a: 'n, though as noted above, we already have 'n: 'a, so this forces the two lifetimes to be equal. That may or may not work with the rest of your code, so take it with a grain of salt.

Compiler continues to count the borrow as mutable when it is actually immutable [duplicate]

This code fails the dreaded borrow checker (playground):
struct Data {
a: i32,
b: i32,
c: i32,
}
impl Data {
fn reference_to_a(&mut self) -> &i32 {
self.c = 1;
&self.a
}
fn get_b(&self) -> i32 {
self.b
}
}
fn main() {
let mut dat = Data{ a: 1, b: 2, c: 3 };
let aref = dat.reference_to_a();
println!("{}", dat.get_b());
}
Since non-lexical lifetimes were implemented, this is required to trigger the error:
fn main() {
let mut dat = Data { a: 1, b: 2, c: 3 };
let aref = dat.reference_to_a();
let b = dat.get_b();
println!("{:?}, {}", aref, b);
}
Error:
error[E0502]: cannot borrow `dat` as immutable because it is also borrowed as mutable
--> <anon>:19:20
|
18 | let aref = dat.reference_to_a();
| --- mutable borrow occurs here
19 | println!("{}", dat.get_b());
| ^^^ immutable borrow occurs here
20 | }
| - mutable borrow ends here
Why is this? I would have thought that the mutable borrow of dat is converted into an immutable one when reference_to_a() returns, because that function only returns an immutable reference. Is the borrow checker just not clever enough yet? Is this planned? Is there a way around it?
Lifetimes are separate from whether a reference is mutable or not. Working through the code:
fn reference_to_a(&mut self) -> &i32
Although the lifetimes have been elided, this is equivalent to:
fn reference_to_a<'a>(&'a mut self) -> &'a i32
i.e. the input and output lifetimes are the same. That's the only way to assign lifetimes to a function like this (unless it returned an &'static reference to global data), since you can't make up the output lifetime from nothing.
That means that if you keep the return value alive by saving it in a variable, you're keeping the &mut self alive too.
Another way of thinking about it is that the &i32 is a sub-borrow of &mut self, so is only valid until that expires.
As #aSpex points out, this is covered in the nomicon.
Why is this an error: While a more precise explanation was already given by #Chris some 2.5 years ago, you can read fn reference_to_a(&mut self) -> &i32 as a declaration that:
“I want to exclusively borrow self, then return a shared/immutable reference which lives as long as the original exclusive borrow” (source)
Apparently it can even prevent me from shooting myself in the foot.
Is the borrow checker just not clever enough yet? Is this planned?
There's still no way to express "I want to exclusively borrow self for the duration of the call, and return a shared reference with a separate lifetime". It is mentioned in the nomicon as #aSpex pointed out, and is listed among the Things Rust doesn’t let you do as of late 2018.
I couldn't find specific plans to tackle this, as previously other borrow checker improvements were deemed higher priority. The idea about allowing separate read/write "lifetime roles" (Ref2<'r, 'w>) was mentioned in the NLL RFC, but no-one has made it into an RFC of its own, as far as I can see.
Is there a way around it? Not really, but depending on the reason you needed this in the first place, other ways of structuring the code may be appropriate:
You can return a copy/clone instead of the reference
Sometimes you can split a fn(&mut self) -> &T into two, one taking &mut self and another returning &T, as suggested by #Chris here
As is often the case in Rust, rearranging your structs to be "data-oriented" rather than "object-oriented" can help
You can return a shared reference from the method: fn(&mut self) -> (&Self, &T) (from this answer)
You can make the fn take a shared &self reference and use interior mutability (i.e. define the parts of Self that need to be mutated as Cell<T> or RefCell<T>). This may feel like cheating, but it's actually appropriate, e.g. when the reason you need mutability as an implementation detail of a logically-immutable method. After all we're making a method take a &mut self not because it mutates parts of self, but to make it known to the caller so that it's possible to reason about which values can change in a complex program.

Difference between &mut and ref mut for trait objects

First of all, I'm not asking what's the difference between &mut and ref mut per se.
I'm asking because I thought:
let ref mut a = MyStruct
is the same as
let a = &mut MyStruct
Consider returning a trait object from a function. You can return a Box<Trait> or a &Trait. If you want to have mutable access to its methods, is it possible to return &mut Trait?
Given this example:
trait Hello {
fn hello(&mut self);
}
struct English;
struct Spanish;
impl Hello for English {
fn hello(&mut self) {
println!("Hello!");
}
}
impl Hello for Spanish {
fn hello(&mut self) {
println!("Hola!");
}
}
The method receives a mutable reference for demonstration purposes.
This won't compile:
fn make_hello<'a>() -> &'a mut Hello {
&mut English
}
nor this:
fn make_hello<'a>() -> &'a mut Hello {
let b = &mut English;
b
}
But this will compile and work:
fn make_hello<'a>() -> &'a mut Hello {
let ref mut b = English;
b
}
My theory
This example will work out of the box with immutable references (not necessary to assign it to a variable, just return &English) but not with mutable references. I think this is due to the rule that there can be only one mutable reference or as many immutable as you want.
In the case of immutable references, you are creating an object and borrowing it as a return expression; its reference won't die because it's being borrowed.
In the case of mutable references, if you try to create an object and borrow it mutably as a return expression you have two mutable references (the created object and its mutable reference). Since you cannot have two mutable references to the same object it won't perform the second, hence the variable won't live long enough. I think that when you write let mut ref b = English and return b you are moving the mutable reference because it was captured by a pattern.
All of the above is a poor attempt to explain to myself why it works, but I don't have the fundamentals to prove it.
Why does this happen?
I've also cross-posted this question to Reddit.
This is a bug. My original analysis below completely ignored the fact that it was returning a mutable reference. The bits about promotion only make sense in the context of immutable values.
This is allowable due to a nuance of the rules governing temporaries (emphasis mine):
When using an rvalue in most lvalue contexts, a temporary unnamed lvalue is created and used instead, if not promoted to 'static.
The reference continues:
Promotion of an rvalue expression to a 'static slot occurs when the expression could be written in a constant, borrowed, and dereferencing that borrow where the expression was the originally written, without changing the runtime behavior. That is, the promoted expression can be evaluated at compile-time and the resulting value does not contain interior mutability or destructors (these properties are determined based on the value where possible, e.g. &None always has the type &'static Option<_>, as it contains nothing disallowed).
Your third case can be rewritten as this to "prove" that the 'static promotion is occurring:
fn make_hello_3<'a>() -> &'a mut Hello {
let ref mut b = English;
let c: &'static mut Hello = b;
c
}
As for why ref mut allows this and &mut doesn't, my best guess is that the 'static promotion is on a best-effort basis and &mut just isn't caught by whatever checks are present. You could probably look for or file an issue describing the situation.

Resources