Why does the directly assignment for self-reference is permitted?

Consider this example:

struct SelfR<'a>{
   a:String,
   b:Option<&'a String>
}
fn foo0(){
  let mut c = SelfR{a:"abc".to_string(),b:None};
  c.b = Some(&c.a); // OK
  println!("{}",c.b);
}
fn foo1(){
  let mut c = SelfR{a:"abc".to_string(),b:None};
  let d = Some(&c.a);
  c.b = d; // OK
  println!("{}",c.b);
}
fn foo2(){
  let mut c = SelfR{a:"abc".to_string(),b:None};
  let mrf = & mut c;
  mrf.b = &mrf.a; // OK
  println!("{}",mrf.b);
}
fn foo3(){
  let mut c = SelfR{a:"abc".to_string(),b:None};
  let mrf = & mut c;
  (& mut *mrf).b = Some(&mrf.a); // Error
  println!("{}",mrf.b);
}
fn foo4(){
  let mut c = SelfR{a:"abc".to_string(),b:None};
  (& mut c).b = Some(&c.a); // Error
 println!("{}",c.b);
}

Why are foo0, foo1, and foo2 permitted to produce self-reference, I expect they would have the same diagnosis as that of foo3 and foo4. Is there a special rule that applies to the former three?

There's nothing really wrong with 3 and 4, they're just obfuscated from the compiler being able to tell that they're okay. The parts in parentheses are borrowing the whole c, so you aren't allowed to then borrow a part of c in the same expression.

This doesn't really have anything to do with self-references. This would apply when calling a method like c.b.m(&c.a) vs (&mut c).b.m(&c.a).

The other ones work because Rust deals with borrows per-member when such information is available. It knows &mut c.b and &c.a don't overlap.

Ok, Is my understanding wrong for c.b = Some(&c.a), I thought its desugar is (& mut c).b = Some(&c.a).

I don't think this desugars. Usually it's sufficient to think of each member as its own variable. Like this:

let mut c = SelfR {
    a: "abc".to_string(),
    b: None,
};

// c.b = Some(&c.a);
let &mut SelfR {
    ref a,
    ref mut b,
} = &mut c;
*b = Some(a);

println!("{:?}", b);

If there were any desugaring, the correct equivalent would be *&mut c.b = Some(&c.a). Fields can be borrowed separately.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.