forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rollup merge of rust-lang#83174 - camelid:borrow-help, r=oli-obk
Suggest using a temporary variable to fix borrowck errors Fixes rust-lang#77834. In Rust, nesting method calls with both require `&mut` access to `self` produces a borrow-check error: error[E0499]: cannot borrow `*self` as mutable more than once at a time --> src/lib.rs:7:14 | 7 | self.foo(self.bar()); | ---------^^^^^^^^^^- | | | | | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here That's because Rust has a left-to-right evaluation order, and the method receiver is passed first. Thus, the argument to the method cannot then mutate `self`. There's an easy solution to this error: just extract a local variable for the inner argument: let tmp = self.bar(); self.foo(tmp); However, the error doesn't give any suggestion of how to solve the problem. As a result, new users may assume that it's impossible to express their code correctly and get stuck. This commit adds a (non-structured) suggestion to extract a local variable for the inner argument to solve the error. The suggestion uses heuristics that eliminate most false positives, though there are a few false negatives (cases where the suggestion should be emitted but is not). Those other cases can be implemented in a future change.
- Loading branch information
Showing
10 changed files
with
276 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
use std::collections::BTreeSet; | ||
|
||
use rustc_middle::mir::visit::{PlaceContext, Visitor}; | ||
use rustc_middle::mir::{Body, Local, Location}; | ||
|
||
/// Find all uses of (including assignments to) a [`Local`]. | ||
/// | ||
/// Uses `BTreeSet` so output is deterministic. | ||
pub(super) fn find<'tcx>(body: &Body<'tcx>, local: Local) -> BTreeSet<Location> { | ||
let mut visitor = AllLocalUsesVisitor { for_local: local, uses: BTreeSet::default() }; | ||
visitor.visit_body(body); | ||
visitor.uses | ||
} | ||
|
||
struct AllLocalUsesVisitor { | ||
for_local: Local, | ||
uses: BTreeSet<Location>, | ||
} | ||
|
||
impl<'tcx> Visitor<'tcx> for AllLocalUsesVisitor { | ||
fn visit_local(&mut self, local: &Local, _context: PlaceContext, location: Location) { | ||
if *local == self.for_local { | ||
self.uses.insert(location); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// See issue #77834. | ||
|
||
#![crate_type = "lib"] | ||
|
||
mod method_syntax { | ||
struct Foo; | ||
|
||
impl Foo { | ||
fn foo(&mut self, _: f32) -> i32 { todo!() } | ||
fn bar(&mut self) -> f32 { todo!() } | ||
fn baz(&mut self) { | ||
self.foo(self.bar()); //~ ERROR | ||
} | ||
} | ||
} | ||
|
||
mod fully_qualified_syntax { | ||
struct Foo; | ||
|
||
impl Foo { | ||
fn foo(&mut self, _: f32) -> i32 { todo!() } | ||
fn bar(&mut self) -> f32 { todo!() } | ||
fn baz(&mut self) { | ||
Self::foo(self, Self::bar(self)); //~ ERROR | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
error[E0499]: cannot borrow `*self` as mutable more than once at a time | ||
--> $DIR/suggest-local-var-double-mut.rs:12:22 | ||
| | ||
LL | self.foo(self.bar()); | ||
| ---------^^^^^^^^^^- | ||
| | | | | ||
| | | second mutable borrow occurs here | ||
| | first borrow later used by call | ||
| first mutable borrow occurs here | ||
| | ||
help: try adding a local storing this argument... | ||
--> $DIR/suggest-local-var-double-mut.rs:12:22 | ||
| | ||
LL | self.foo(self.bar()); | ||
| ^^^^^^^^^^ | ||
help: ...and then using that local as the argument to this call | ||
--> $DIR/suggest-local-var-double-mut.rs:12:13 | ||
| | ||
LL | self.foo(self.bar()); | ||
| ^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error[E0499]: cannot borrow `*self` as mutable more than once at a time | ||
--> $DIR/suggest-local-var-double-mut.rs:24:39 | ||
| | ||
LL | Self::foo(self, Self::bar(self)); | ||
| --------- ---- ^^^^ second mutable borrow occurs here | ||
| | | | ||
| | first mutable borrow occurs here | ||
| first borrow later used by call | ||
| | ||
help: try adding a local storing this argument... | ||
--> $DIR/suggest-local-var-double-mut.rs:24:29 | ||
| | ||
LL | Self::foo(self, Self::bar(self)); | ||
| ^^^^^^^^^^^^^^^ | ||
help: ...and then using that local as the argument to this call | ||
--> $DIR/suggest-local-var-double-mut.rs:24:13 | ||
| | ||
LL | Self::foo(self, Self::bar(self)); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
error: aborting due to 2 previous errors | ||
|
||
For more information about this error, try `rustc --explain E0499`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// See issue #77834. | ||
|
||
#![crate_type = "lib"] | ||
|
||
mod method_syntax { | ||
struct Foo; | ||
|
||
impl Foo { | ||
fn foo(&self, _: f32) -> i32 { todo!() } | ||
fn bar(&mut self) -> f32 { todo!() } | ||
fn baz(&mut self) { | ||
self.foo(self.bar()); //~ ERROR | ||
} | ||
} | ||
} | ||
|
||
mod fully_qualified_syntax { | ||
struct Foo; | ||
|
||
impl Foo { | ||
fn foo(&self, _: f32) -> i32 { todo!() } | ||
fn bar(&mut self) -> f32 { todo!() } | ||
fn baz(&mut self) { | ||
Self::foo(self, Self::bar(self)); //~ ERROR | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable | ||
--> $DIR/suggest-local-var-imm-and-mut.rs:12:22 | ||
| | ||
LL | self.foo(self.bar()); | ||
| ---------^^^^^^^^^^- | ||
| | | | | ||
| | | mutable borrow occurs here | ||
| | immutable borrow later used by call | ||
| immutable borrow occurs here | ||
|
||
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable | ||
--> $DIR/suggest-local-var-imm-and-mut.rs:24:29 | ||
| | ||
LL | Self::foo(self, Self::bar(self)); | ||
| --------- ---- ^^^^^^^^^^^^^^^ mutable borrow occurs here | ||
| | | | ||
| | immutable borrow occurs here | ||
| immutable borrow later used by call | ||
|
||
error: aborting due to 2 previous errors | ||
|
||
For more information about this error, try `rustc --explain E0502`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters