Open safinaskar opened 1 year ago
That doesn't seem to be correct
@tadaHrd , what you mean? Algorithm for vector merging is wrong? Or my code violates some Rust invariants?
I don't think this is a bug.
Your code: (with comments removed)
let mut left = vec![0, 1, 2];
let right = vec![1, 2, 3];
let duplicate_part = &mut left[n..];
left.extend_from_slice(right.strip_prefix(duplicate_part).unwrap());
Due to argument evaluation order, I believe the last line expands to something like:
{
let extend_receiver = &mut left; // (*)
let arg = right.strip_prefix(duplicate_part).unwrap();
extend_receiver.extend_from_slice(arg);
}
Now the lifetime error should be obvious, as duplicate_part
and extend_receiver
have overlapping lifetimes, and one is exclusive. Your compiling version effectively switches those two lines, solving the issue.
(*) More precisely, the method receiver is taken as a two-phase borrow, which is why the code would compile if duplicate_part
was a shared borrow instead.
@quaternic Is there a reason why two-phase doesn't allow exclusive borrows in the arguments?
For example in this code, if the lifetime of the borrow in the argument outlives the method call it would be wrong for shared borrows as well as exclusive borrows, but only the exclusive borrow is a compiler error.
struct Foo;
impl Foo {
fn bar(&mut self, _: ()) {}
}
fn main() {
let mut foo = Foo;
foo.bar(drop(&foo)); // OK
foo.bar(drop(&mut foo)); // ERROR
}
The two-phase functions like a shared borrow until its activation point (when the call is actually made), and exclusive from then on. See the link for details (bottom of the page).
URLO would be a much better medium for asking questions about the language. The issue tracker really isn't the place.
@safinaskar, I think you need to implement it yourself if you need special functionality. Rust is a Turing complete programming language to my knowledge so you should be able to.
@quaternic
Due to argument evaluation order
The line let extend_receiver = &mut left
doesn't have any side effects, so I think the compiler should move it down despite evaluation order guarantees.
In other words, I think the compiler should try all possible evaluation order strategies, which are equivalent to order specified in the reference (from side-effects point of view), until the compiler finds evaluation order, which satisfies borrow checker.
@tadaHrd
I think you need to implement it yourself if you need special functionality
You mean writing patch for rustc? I simply want this bug to stay opened for a long time. Until someone will eventually (possibly after several years) fix it. I. e. similarly to how bug https://github.com/rust-lang/rust/issues/47680#issuecomment-363131420 (and similar bugs) eventually led to creation of Polonius.
I don't even ask to fix this bug. Just keep this report opened
Here is simplified version of my code from actual production code base: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=99a751acd113949b2a77fa251e33f955 (rustc 1.68.2)
The code doesn't compile, but the code is correct, and it should compile. Yes, I can do the same task easier, but the code is still correct.
-Zpolonius
doesn't change anything, i. e. this bug is not fixed by Polonius.@rustbot label +A-lifetimes +T-compiler +A-borrow-checker +NLL-polonius +A-NLL