-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Open
Labels
A-async-awaitArea: Async & AwaitArea: Async & AwaitA-borrow-checkerArea: The borrow checkerArea: The borrow checkerAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.Async-await issues that have been triaged during a working group meeting.C-bugCategory: This is a bug.Category: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
Description
I've tried to simplify this example to the best of my abilities so here it goes. For some reason borrow checker doesn't treat match as taking ownership / consuming the argument:
async fn job(value: &mut usize) -> usize {
*value
}
let mut value1 = 42;
let mut value2 = 42;
let mut future1 = Box::pin(job(&mut value1));
let mut future2 = Box::pin(job(&mut value2));
loop {
let result = select(future1, future2).await;
match result {
Either::Left(e) => println!("{}", e.0),
Either::Right(e) => println!("{}", e.0),
}
future1 = Box::pin(job(&mut value1)); // ERROR: cannot borrow `value1` as mutable more than once at a time [E0499]
future2 = Box::pin(job(&mut value2)); // ERROR: cannot borrow `value1` as mutable more than once at a time [E0499]
}
The most weird thing I found is that this issue can be worked around with a very simple trick:
async fn job(value: &mut usize) -> usize {
*value
}
fn noop<T>(value: T) -> T {
value
}
let mut value1 = 42;
let mut value2 = 42;
let mut future1 = Box::pin(job(&mut value1));
let mut future2 = Box::pin(job(&mut value2));
loop {
let result = select(future1, future2).await;
match noop(result) { // explicitly consuming and returning result fixes borrowing errors
Either::Left(e) => println!("{}", e.0),
Either::Right(e) => println!("{}", e.0),
}
future1 = Box::pin(job(&mut value1)); // NO ERROR
future2 = Box::pin(job(&mut value2)); // NO ERROR
}
I expected to see this happen:
Match must consume all &mut references and allow me to create new &mut references after it.
Instead, this happened:
It seams that borrow checker doesn't think that match consumed &mut references.
Meta
Bug reproduces on both stable and nightly versions.
rustc --version --verbose
:
rustc 1.71.0 (8ede3aae2 2023-07-12)
binary: rustc
commit-hash: 8ede3aae28fe6e4d52b38157d7bfe0d3bceef225
commit-date: 2023-07-12
host: aarch64-apple-darwin
release: 1.71.0
LLVM version: 16.0.5
Backtrace
Blocking waiting for file lock on build directory
Compiling futures-sink v0.3.28
Compiling pin-project-lite v0.2.10
Compiling pin-utils v0.1.0
Compiling futures-core v0.3.28
Compiling memchr v2.5.0
Compiling futures-task v0.3.28
Compiling futures-io v0.3.28
Compiling slab v0.4.8
Compiling futures-channel v0.3.28
Compiling futures-util v0.3.28
Compiling futures-executor v0.3.28
Compiling futures v0.3.28
Compiling rust-test v0.1.0 (/Users/matrixdev/Projects/rust-test)
error[E0499]: cannot borrow `value1` as mutable more than once at a time
--> src/main.rs:20:32
|
10 | let mut future1 = Box::pin(job(&mut value1));
| ----------- first mutable borrow occurs here
...
20 | future1 = Box::pin(job(&mut value1));
| ^^^^^^^^^^^ second mutable borrow occurs here
21 | future2 = Box::pin(job(&mut value2));
22 | }
| - first borrow might be used here, when `result` is dropped and runs the destructor for type `Either<(usize, Pin<Box<impl futures::Future<Output = usize>>>), (usize, Pin<Box<impl futures::Future<Output = usize>>>)>`
error[E0499]: cannot borrow `value2` as mutable more than once at a time
--> src/main.rs:21:32
|
11 | let mut future2 = Box::pin(job(&mut value2));
| ----------- first mutable borrow occurs here
...
21 | future2 = Box::pin(job(&mut value2));
| ^^^^^^^^^^^ second mutable borrow occurs here
22 | }
| - first borrow might be used here, when `result` is dropped and runs the destructor for type `Either<(usize, Pin<Box<impl futures::Future<Output = usize>>>), (usize, Pin<Box<impl futures::Future<Output = usize>>>)>`
For more information about this error, try `rustc --explain E0499`.
error: could not compile `rust-test` (bin "rust-test") due to 2 previous errors
Metadata
Metadata
Assignees
Labels
A-async-awaitArea: Async & AwaitArea: Async & AwaitA-borrow-checkerArea: The borrow checkerArea: The borrow checkerAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.Async-await issues that have been triaged during a working group meeting.C-bugCategory: This is a bug.Category: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.