Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggest using a temporary variable to fix borrowck errors #83174

Merged
merged 1 commit into from
Dec 11, 2021

Conversation

camelid
Copy link
Member

@camelid camelid commented Mar 15, 2021

Fixes #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.

@camelid camelid added A-borrow-checker Area: The borrow checker A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. C-enhancement Category: An issue proposing an enhancement or a PR with one. labels Mar 15, 2021
@rust-highfive
Copy link
Collaborator

r? @oli-obk

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 15, 2021
@rust-log-analyzer

This comment has been minimized.

@camelid camelid added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Mar 16, 2021
@camelid camelid removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Apr 4, 2021
@bors
Copy link
Contributor

bors commented May 2, 2021

☔ The latest upstream changes (presumably #84822) made this pull request unmergeable. Please resolve the merge conflicts.

@camelid camelid added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label May 5, 2021
@camelid
Copy link
Member Author

camelid commented Jun 12, 2021

Starting with a rebase so this doesn't get too stale.

@rust-log-analyzer

This comment has been minimized.

@inquisitivecrystal inquisitivecrystal added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Aug 24, 2021
@bors

This comment has been minimized.

@oli-obk oli-obk removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 6, 2021
@rust-log-analyzer

This comment has been minimized.

@camelid
Copy link
Member Author

camelid commented Oct 20, 2021

Status update: I've figured out, and implemented, a way to find the locations of
the outer and inner calls.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@camelid
Copy link
Member Author

camelid commented Oct 20, 2021

FYI, I just noticed this (pre-existing) test has a typo in it, but it probably shouldn't matter now that MIR borrowck is the default, right?

https://github.com/rust-lang/rust/blob/e6875793dd149345fca224f84d71814a0daa1be7/src/test/ui/borrowck/two-phase-sneaky.rs#L1

Copy link
Member Author

@camelid camelid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@oli-obk I've made some progress on this. When you get a chance, could you look at the code and the errors? There are a few issues where the wrong span is used, but the false positive rate is much lower 🎉

I left comments on all the test outputs that have issues. I would appreciate suggestions on how to improve the accuracy :)

Comment on lines 15 to 19
help: ...and then using that local as the argument to this call
--> $DIR/two-phase-nonrecv-autoref.rs:51:9
|
LL | f(f(10));
| ^
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This span's not great, but not terrible either.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it more than the one that goes to the end of the call as spans won't overlap this way

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This regressed with #83174 (comment); the suggestion is no longer reported. I think let's just leave it for now.

src/test/ui/borrowck/two-phase-sneaky.stderr Outdated Show resolved Hide resolved
src/test/ui/codemap_tests/one_line.stderr Show resolved Hide resolved
src/test/ui/issues/issue-18566.stderr Outdated Show resolved Hide resolved
src/test/ui/issues/issue-61623.stderr Outdated Show resolved Hide resolved
@bors
Copy link
Contributor

bors commented Dec 10, 2021

📌 Commit 381b275 has been approved by oli-obk

@bors
Copy link
Contributor

bors commented Dec 10, 2021

🌲 The tree is currently closed for pull requests below priority 100. This pull request will be tested once the tree is reopened.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 10, 2021
@camelid
Copy link
Member Author

camelid commented Dec 10, 2021

@oli-obk thank you so much for helping me with this PR over the past 9 months! ❤️

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Dec 10, 2021
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.
@matthiaskrgr
Copy link
Member

@bors r- rollup-
failed in a rollup:
#91756 (comment)
Can you please double check that there is no test failure? Thanks!

@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Dec 10, 2021
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.
Comment on lines +11 to +20
help: try adding a local storing this argument...
--> $DIR/suggest-local-var-imm-and-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-imm-and-mut.rs:12:13
|
LL | self.foo(self.bar());
| ^^^^^^^^^^^^^^^^^^^^
Copy link
Member Author

@camelid camelid Dec 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's intriguing that the suggestion doesn't show up in normal mode but does (correctly) show up in nll mode.

@camelid
Copy link
Member Author

camelid commented Dec 10, 2021

@bors r=oli-obk

@bors
Copy link
Contributor

bors commented Dec 10, 2021

📌 Commit e273152 has been approved by oli-obk

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Dec 10, 2021
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Dec 11, 2021
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.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Dec 11, 2021
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.
bors added a commit to rust-lang-ci/rust that referenced this pull request Dec 11, 2021
…askrgr

Rollup of 6 pull requests

Successful merges:

 - rust-lang#83174 (Suggest using a temporary variable to fix borrowck errors)
 - rust-lang#89734 (Point at capture points for non-`'static` reference crossing a `yield` point)
 - rust-lang#90270 (Make `Borrow` and `BorrowMut` impls `const`)
 - rust-lang#90741 (Const `Option::cloned`)
 - rust-lang#91548 (Add spin_loop hint for RISC-V architecture)
 - rust-lang#91721 (Minor improvements to `future::join!`'s implementation)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 433a13b into rust-lang:master Dec 11, 2021
@rustbot rustbot added this to the 1.59.0 milestone Dec 11, 2021
@camelid camelid deleted the borrow-help branch December 11, 2021 21:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-borrow-checker Area: The borrow checker A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix`. C-enhancement Category: An issue proposing an enhancement or a PR with one. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
9 participants