let mut a = vec![0, 1]; a += a;
What special knowledge exists to allow this? I would have thought that this would result in a "cannot borrow ... as immutable because it is also borrowed as mutable" error. And replacing the number with a newtype does result in that error. This makes me think there's some built-in implementation for
i32 or some combination.
I'm pretty sure you're not getting two &mut references there?
based on the MIR it looks like that desugars into roughly speaking:
let mut a = vec![0, 1]; let mut p0 = &mut a; let p1 = a; *p0 += p1;
and that works because of 2 phase borrows letting the
&mut kick in "late"
I had a feeling 2pb would be involved, so maybe the question is why doesn't 2pb kick in for the newtype version?
hm, is your newtype Copy?
Seems weird as
Vec is not a lang item...
here's a theory: the add no longer happens "in the compiler"
I was also wondering if
AddAssign is a compiler builtin or something
Vec decays to a slice
here's a diff of the mir https://gist.github.com/Mark-Simulacrum/93386e15a03cd562bdaf9c95dff900b0
still inspecting it
So between that, we end up completely in language space, not in library space.
hm actually it almost looks like the indexing order switched?
mut happens first?
so there is this https://github.com/rust-lang/rust/pull/47489/files#diff-b3d7798e2a3c43eca68203216e36de65R544 but not sure if it's still the case
In practice, this covers the following cases:
- binary assignment operators (+=, -=, *=, etc.) Note this does /not/ include IndexMut operations at this time
but yeah the MIR for the newtype has IndexMut happening first, which activates the 2 phase borrow (if you can even call it that since there's not really 2 phases)
You wanna write that up as an answer?
nah that would require more time than I have :)
What flags did you use to get the MIR before the borrow checker said "stop doing that"?
Ah, I see you commented