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

Point to immutable arg/fields when trying to use as &mut #39139

Merged
merged 1 commit into from
Jan 27, 2017

Conversation

estebank
Copy link
Contributor

@estebank estebank commented Jan 17, 2017

Present the following output when trying to access an immutable borrow's
field as mutable:

error[E0389]: cannot borrow data mutably in a `&` reference
  --> $DIR/issue-38147-1.rs:27:9
   |
26 | fn f(&self) {
   |      -----  use `&mut self` here to make mutable
27 |     f.s.push('x');
   |     ^^^ assignment into an immutable reference

And the following when trying to access an immutable struct field as mutable:

error: cannot borrow immutable borrowed content `*self.s` as mutable
  --> $DIR/issue-38147-3.rs:17:9
   |
12 |     s: &'a String
   |     ------------- use `&'a mut String` here to make mutable
...|
16 |     fn f(&self) {
   |          -----  use `&mut self` here to make mutable
17 |         self.s.push('x');
   |         ^^^^^^ cannot borrow as mutable

Fixes #38147.

@rust-highfive
Copy link
Collaborator

r? @nrc

(rust_highfive has picked a reviewer for you, use r? to override)

@estebank
Copy link
Contributor Author

@@ -177,7 +177,7 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
debug!("check_aliasability aliasability={:?} req_kind={:?}",
aliasability, req_kind);

match (aliasability, req_kind) {
match (aliasability.clone(), req_kind.clone()) {
Copy link
Member

Choose a reason for hiding this comment

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

Why suddenly cloning them?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Leftover from previous exploration.

@GuillaumeGomez
Copy link
Member

This is great! 👍

@nrc
Copy link
Member

nrc commented Jan 18, 2017

r? @nikomatsakis (I'm not familiar enough with these bits of the compiler any more).

I would prefer less assertive language in the error messages - rather than "X should be Y", I prefer, "if you want X, then you can change X to Y" or something similar. Also, could these be suggestions rather than labels? One day I would like to be able to auto-apply suggestions like this and it makes it easier if they are declared as such.

@rust-highfive rust-highfive assigned nikomatsakis and unassigned nrc Jan 18, 2017
@estebank
Copy link
Contributor Author

Introduced an error in two tests (removed two hints). Will try to fix it tonight.

@estebank
Copy link
Contributor Author

I would prefer less assertive language in the error messages - rather than "X should be Y", I prefer, "if you want X, then you can change X to Y" or something similar.

@nrc, I'm ok with doing so. For now, I copied the message already being used for the same kind of suggestion:

error: cannot borrow immutable borrowed content `*self.s` as mutable
  --> $DIR/issue-38147-3.rs:17:9
   |
12 |     s: &'a String
   |     ------------- this field should be `&mut`
...|
16 |     fn f(&self) {
   |          -----  use `&mut self` here to make mutable
17 |         self.s.push('x');
   |         ^^^^^^

Also, could these be suggestions rather than labels? One day I would like to be able to auto-apply suggestions like this and it makes it easier if they are declared as such.

The only things that makes me uneasy about using suggestions are that the actual output turns out to be slightly longer, and because of the out of order and lack of line number, less comprehensible:

error: cannot borrow immutable borrowed content `*self.s` as mutable
  --> $DIR/issue-38147-3.rs:17:9
   |
12 |     s: &'a String
   |     ------------- this field should be `&mut`
...
17 |         self.s.push('x');
   |         ^^^^^^
   |
help: try making this a mutable borrow
   |     fn f(&mut self) {

I just filed #39152 so it can be improved going forward, but as it is now I really prefer the span_label presentation.

@sophiajt
Copy link
Contributor

I'm definitely liking this revision. One question, is this part missing something?

17 |         self.s.push('x');
   |         ^^^^^^

Seems like it needs a label there

@estebank
Copy link
Contributor Author

@jonathandturner the current output doesn't set a label. To add one, I could definitely use some help with the wording. Something along the lines of:

error: cannot borrow immutable borrowed content `*self.s` as mutable
  --> $DIR/issue-38147-3.rs:17:9
17 |         self.s.push('x');
   |         ^^^^^^ cannot borrow as mutable

or

error: cannot borrow immutable borrowed content `*self.s` as mutable
  --> $DIR/issue-38147-3.rs:17:9
17 |         self.s.push('x');
   |         ^^^^^^ cannot borrow immutable borrowed content as mutable

seems reasonable.

@sophiajt
Copy link
Contributor

@estebank choice #1 sounds good :)

@estebank estebank force-pushed the issue-38147 branch 3 times, most recently from 0df4676 to a9a0f48 Compare January 19, 2017 05:50
@estebank
Copy link
Contributor Author

@jonathandturner done.

@nikomatsakis
Copy link
Contributor

👍 to shorter wording on the "primary label". In fact, though I think this is a separate thing, I have long wanted to aggressively shorten the borrowck messages, e.g. removing the phrase "borrowed as mutable" and just say "write" or "mutate", and definitely not talking about distracting but complex things like "immutable borrowed content".

Also 👍 to this general pull request. =)

@estebank
Copy link
Contributor Author

@nikomatsakis is there anything else that should be part of this PR?

Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

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

Looks like it's close but not quite there. We should make some tests targeting this specific case (the existing tests seem to have caught this overenthusiastic error message "by accident", no?)

fn immutable_argument_should_be_mut(&self, nid: ast::NodeId, db: &mut DiagnosticBuilder) {
let parent = self.tcx.map.get_parent_node(nid);

if let Some(fn_like) = FnLikeNode::from_node(self.tcx.map.get(parent)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

So...this fn is pretty hard to read. =) Maybe we can use some temporaries or something? I just find it hard to follow, but maybe it's ok, if there was at least a comment. Basically when I read it I just see "walk a bunch of data structures to pull out data", but my eyes slide over the details...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is moved code from bellow so that I could use it twice without copying code around :)

I will see how I can make it easier to follow.

--> $DIR/issue-38147-2.rs:17:9
|
12 | s: &'a String
| ------------- this field should be `&mut`
Copy link
Contributor

Choose a reason for hiding this comment

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

nice :)

| ------------- this field should be `&mut`
...
16 | fn f(&self) {
| ----- use `&mut self` here to make mutable
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe we can adjust the wording to make it clearer that BOTH parts need to be &mut self? That's a bit tricky, particularly since we don't control the relative order of things here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could look at the span's line number to identify order and change this to something like

error: cannot borrow immutable borrowed content `*self.s` as mutable
  --> $DIR/issue-38147-3.rs:17:9
   |
12 |     s: &'a String
   |     ------------- this field should be `&mut`...
...
16 |     fn f(&self) {
   |          ----- ...and use `&mut self` here to make mutable
17 |         self.s.push('x');
   |         ^^^^^^ cannot borrow as mutable

But I don't think it's unreasonable to show both labels, and if the developer only changes one of them, to still get the same error with the remaining label.


error: cannot borrow immutable `Box` content `*f.f` as mutable
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:44:5
|
18 | f: Box<FnMut() + 'a>
| -------------------- this field should be `&mut`
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, this seems wrong, no?

Copy link
Contributor

Choose a reason for hiding this comment

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

Certainly there is nothing that would easily be converted to &mut here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What should be the appropriate message for this case? Nothing if the type is not a ref?


let mut db = self.struct_span_err(span, msg);
if let Some(span) = field_span {
db.span_label(span, &"this field should be `&mut`");
Copy link
Contributor

Choose a reason for hiding this comment

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

seems like we have to check here that the type of the field is some sort of reference, right? (hence the "over fire" case in the ui tests below)

Copy link
Contributor Author

@estebank estebank left a comment

Choose a reason for hiding this comment

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

We should make some tests targeting this specific case

issue-38147-1, issue-38147-2, issue-38147-3 & issue-38147-4 are new tests targeting this case.


error: cannot borrow immutable `Box` content `*f.f` as mutable
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:44:5
|
18 | f: Box<FnMut() + 'a>
| -------------------- this field should be `&mut`
Copy link
Contributor Author

Choose a reason for hiding this comment

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

What should be the appropriate message for this case? Nothing if the type is not a ref?

fn immutable_argument_should_be_mut(&self, nid: ast::NodeId, db: &mut DiagnosticBuilder) {
let parent = self.tcx.map.get_parent_node(nid);

if let Some(fn_like) = FnLikeNode::from_node(self.tcx.map.get(parent)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is moved code from bellow so that I could use it twice without copying code around :)

I will see how I can make it easier to follow.

| ------------- this field should be `&mut`
...
16 | fn f(&self) {
| ----- use `&mut self` here to make mutable
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could look at the span's line number to identify order and change this to something like

error: cannot borrow immutable borrowed content `*self.s` as mutable
  --> $DIR/issue-38147-3.rs:17:9
   |
12 |     s: &'a String
   |     ------------- this field should be `&mut`...
...
16 |     fn f(&self) {
   |          ----- ...and use `&mut self` here to make mutable
17 |         self.s.push('x');
   |         ^^^^^^ cannot borrow as mutable

But I don't think it's unreasonable to show both labels, and if the developer only changes one of them, to still get the same error with the remaining label.

@nikomatsakis
Copy link
Contributor

@estebank

What should be the appropriate message for this case? Nothing if the type is not a ref?

Yeah, no change is needed in this case.

@nikomatsakis
Copy link
Contributor

@estebank

Travis is failing because a UI test needs to be updated:

error: cannot borrow immutable borrowed content `*self.s` as mutable
  --> /checkout/src/test/ui/did_you_mean/issue-38147-3.rs:17:9
   |
12 |     s: &'a String
   |     ------------- use `&'a mut String` here to make mutable
...
16 |     fn f(&self) {
   |          ----- use `&mut self` here to make mutable
17 |         self.s.push('x');
   |         ^^^^^^ cannot borrow as mutable

error: aborting due to previous error

@nikomatsakis
Copy link
Contributor

but the new output looks correct =)

@estebank
Copy link
Contributor Author

@nikomatsakis tests are fixed. Can you check wether the method immutable_argument_should_be_mut is now more readable (along with the new method suggest_mut_for_immutable )?

Also, please verify that using bug! for a case that shouldn't ever happen is correct. If it is not, it can be changed to return a generic comment use '&mut' to make mutable.

@bors
Copy link
Contributor

bors commented Jan 26, 2017

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

Point to immutable borrow arguments and fields when trying to use them as
mutable borrows. Add label to primary span on "cannot borrow as mutable"
errors.

Present the following output when trying to access an immutable borrow's
field as mutable:

```
error[E0389]: cannot borrow data mutably in a `&` reference
  --> $DIR/issue-38147-1.rs:27:9
   |
26 | fn f(&self) {
   |      -----  use `&mut self` here to make mutable
27 |     f.s.push('x');
   |     ^^^ assignment into an immutable reference
```

And the following when trying to access an immutable struct field as mutable:

```
error: cannot borrow immutable borrowed content `*self.s` as mutable
  --> $DIR/issue-38147-3.rs:17:9
   |
12 |     s: &'a String
   |     ------------- use `&'a mut String` here to make mutable
...|
16 |     fn f(&self) {
   |          -----  use `&mut self` here to make mutable
17 |         self.s.push('x');
   |         ^^^^^^ cannot borrow as mutable
```
@nikomatsakis
Copy link
Contributor

@estebank

Can you check wether the method immutable_argument_should_be_mut is now more readable (along with the new method suggest_mut_for_immutable)?

Yes; it's a wonder what some comments will do! :) Thanks.

Also, please verify that using bug! for a case that shouldn't ever happen is correct. If it is not, it can be changed to return a generic comment use '&mut' to make mutable.

Yes that is correct.

@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Contributor

bors commented Jan 26, 2017

📌 Commit e1280d8 has been approved by nikomatsakis

@bors
Copy link
Contributor

bors commented Jan 26, 2017

⌛ Testing commit e1280d8 with merge f453929...

@bors
Copy link
Contributor

bors commented Jan 26, 2017

💔 Test failed - status-travis

@alexcrichton
Copy link
Member

alexcrichton commented Jan 26, 2017 via email

@bors
Copy link
Contributor

bors commented Jan 26, 2017

⌛ Testing commit e1280d8 with merge 4805ad6...

@bors bors mentioned this pull request Jan 27, 2017
@bors
Copy link
Contributor

bors commented Jan 27, 2017

💔 Test failed - status-travis

@alexcrichton
Copy link
Member

alexcrichton commented Jan 27, 2017 via email

@bors
Copy link
Contributor

bors commented Jan 27, 2017

⌛ Testing commit e1280d8 with merge 9876cb0...

@bors
Copy link
Contributor

bors commented Jan 27, 2017

💔 Test failed - status-travis

@alexcrichton
Copy link
Member

alexcrichton commented Jan 27, 2017 via email

@bors
Copy link
Contributor

bors commented Jan 27, 2017

⌛ Testing commit e1280d8 with merge 025fb7d...

bors added a commit that referenced this pull request Jan 27, 2017
Point to immutable arg/fields when trying to use as &mut

Present the following output when trying to access an immutable borrow's
field as mutable:

```
error[E0389]: cannot borrow data mutably in a `&` reference
  --> $DIR/issue-38147-1.rs:27:9
   |
26 | fn f(&self) {
   |      -----  use `&mut self` here to make mutable
27 |     f.s.push('x');
   |     ^^^ assignment into an immutable reference
```

And the following when trying to access an immutable struct field as mutable:

```
error: cannot borrow immutable borrowed content `*self.s` as mutable
  --> $DIR/issue-38147-3.rs:17:9
   |
12 |     s: &'a String
   |     ------------- use `&'a mut String` here to make mutable
...|
16 |     fn f(&self) {
   |          -----  use `&mut self` here to make mutable
17 |         self.s.push('x');
   |         ^^^^^^ cannot borrow as mutable
```

Fixes #38147.
@bors
Copy link
Contributor

bors commented Jan 27, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing 025fb7d to master...

@arielb1
Copy link
Contributor

arielb1 commented Feb 6, 2017

This causes the ICE #39544.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants