Skip to content

Mir Borrowck: Parity with Ast for E0384 (Cannot assign twice to immutable) #46022

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

Merged
merged 3 commits into from
Nov 27, 2017

Conversation

matthewjasper
Copy link
Contributor

@matthewjasper matthewjasper commented Nov 15, 2017

  • Closes MIR-borrowck: ICE during diagnostic search for assignment (unwrap of None) #45199
  • Don't allow assigning to dropped immutable variables
  • Show the "first assignment" note on the first assignment that can actually come before the second assignment.
  • Make "first assignment" notes point to function parameters if needed.
  • Don't show a "first assignment" note if the first and second assignment have the same span (in a loop). This matches ast borrowck for now, but maybe this we should add "in previous loop iteration" as with some other borrowck errors. (Commit 2)
  • Use revisions to check mir borrowck for the existing tests for this error. (Commit 3)

Still working on a less ad-hoc way to get 'first assignment' notes to show on the correct assignment. Also need to check mutating function arguments. Now using a new dataflow pass.

@kennytm kennytm added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Nov 16, 2017
@nikomatsakis
Copy link
Contributor

r? @pnkfelix

@arielb1
Copy link
Contributor

arielb1 commented Nov 16, 2017

@matthewjasper

I don't think StorageDead kills move-out status, so I think this will break situations such as:

loop {
    let x = String::new();
    drop(x);
}

You probably want to create a separate dataflow for "propagating initializations" (basically the opposite of the MoveOut analysis, that is killed by a StorageDead, but not by moves) and use that instead of using a combination of moveout + maybe-uninitialized.

@arielb1
Copy link
Contributor

arielb1 commented Nov 19, 2017

@matthewjasper

Nice PR. However, I think we are getting quite a bit of separate move-in implementation sprawl - there are already 2, and now we're getting another one. I think we can merge them - that would imply changing the
code so that MovingOutStatements and drop_flag_effects_for_location use the init_loc_map.

For that, you'll need to have some sort of flag on the init_loc_map so that you won't initialize the return value of calls on the panic path, because that will cause bugs. I think adding a non_panic_path_only flag to Init and checking it where needed would be enough.

@@ -337,6 +369,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
}
if let Some((ref destination, _bb)) = *destination {
self.create_move_path(destination);
Copy link
Contributor

Choose a reason for hiding this comment

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

This only initializes the destination on the non-panic-path, so you'll probably want some label on the Init you create to indicate that.

Copy link
Contributor

Choose a reason for hiding this comment

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

fixed.

self.mir,
move_data,
move_data.rev_lookup.find(dest_lval),
|mpi| for ii in &init_path_map[mpi] {
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks wrong - you don't want to "christmas tree" every initialization for this lvalue, you want just the initialization for the call.

e.g. in a code like

let x;
if true {
    x = 2;
} else {
    x = get();
    x = 3;
}

You want to highlight just the get, not the other assignment to x.

If you want to do this correctly, you could just do

let call_loc = Location { // why doesn't MIR have a terminator_loc method?
    block: call_bb,       // feel free to add one
    statement_index: self.mir[call_bb].statements.len()
};
for init_index in &init_loc_map[call_loc] {
    zero_to_one(sets.gen_set.words_mut(), *init_index);
}

@arielb1
Copy link
Contributor

arielb1 commented Nov 19, 2017

r=me with the initialization sprawl bought under control.

@shepmaster
Copy link
Member

@matthewjasper the title of this PR still says "[WIP]", but it looks like your review is close to finished. Please make sure to remove that if you feel this PR should be merged.

@arielb1
Copy link
Contributor

arielb1 commented Nov 25, 2017

@matthewjasper

How are you doing with this PR? Could you address the nits so we can move forward?

@matthewjasper matthewjasper force-pushed the cannot-assign-twice-error branch from 8347043 to d895346 Compare November 26, 2017 00:35
@matthewjasper
Copy link
Contributor Author

Comments addressed.

@matthewjasper matthewjasper changed the title [WIP] Mir Borrowck: Parity with Ast for E0384 (Cannot assign twice to immutable) Mir Borrowck: Parity with Ast for E0384 (Cannot assign twice to immutable) Nov 26, 2017
self.report_illegal_reassignment(
context, (lvalue, span), assignment_stmt.source_info.span);
for ii in &move_data.init_path_map[mpi] {
if flow_state.ever_inits.curr_state.contains(ii)
Copy link
Contributor

Choose a reason for hiding this comment

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

style: opening brace for ifs is in the same line as the if:

                if flow_state.ever_inits.curr_state.contains(ii) {

}
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

style: no newline at end of file

let bits_per_block = self.bits_per_block();
for init_index in &init_loc_map[location] {
assert!(init_index.index() < bits_per_block);
zero_to_one(sets.gen_set.words_mut(), *init_index);
Copy link
Contributor

@arielb1 arielb1 Nov 26, 2017

Choose a reason for hiding this comment

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

I would prefer to use a in_out.add rather than a zero_to_one here - I'm not sure of a good reason for this to always be for an uninitialized variable (it could be that right now we only assign to temporaries, but that might not remain so in the future).

Copy link
Contributor

@arielb1 arielb1 Nov 26, 2017

Choose a reason for hiding this comment

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

Also, even if it doesn't matter for borrow-check (because you can't have assignments in the panic path) you should not mark call destinations as uninitialized if the call unwinds (i.e. if the init loc map entry is a NonPanicPathOnly).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean as initialized?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yea my bad

let path = self.data.rev_lookup.locals[arg];
let span = self.mir.local_decls[arg].source_info.span;

let init = self.data.inits.push(Init {
Copy link
Contributor

@arielb1 arielb1 Nov 26, 2017

Choose a reason for hiding this comment

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

You want to have arguments assigned before the first statement, to avoid edge cases such as my wrong.

@arielb1
Copy link
Contributor

arielb1 commented Nov 26, 2017

This is cool.

r=me modulo nits

@matthewjasper matthewjasper force-pushed the cannot-assign-twice-error branch 2 times, most recently from 356316b to 88776fd Compare November 26, 2017 23:02
@matthewjasper
Copy link
Contributor Author

Nits addressed

* Used for new dataflow to track if a variable has every been initialized
* Used for other dataflows that need to be updated for initializations
Matches current ast-borrowck behavior.
@matthewjasper matthewjasper force-pushed the cannot-assign-twice-error branch from 88776fd to d64a318 Compare November 27, 2017 08:08
@arielb1
Copy link
Contributor

arielb1 commented Nov 27, 2017

@bors r+

@bors
Copy link
Collaborator

bors commented Nov 27, 2017

📌 Commit d64a318 has been approved by arielb1

arielb1 pushed a commit to arielb1/rust that referenced this pull request Nov 27, 2017
…rror, r=arielb1

Mir Borrowck: Parity with Ast for E0384 (Cannot assign twice to immutable)

- Closes rust-lang#45199
- Don't allow assigning to dropped immutable variables
- Show the "first assignment" note on the first assignment that can actually come before the second assignment.
- Make "first assignment" notes point to function parameters if needed.
- Don't show a "first assignment" note if the first and second assignment have the same span (in a loop). This matches ast borrowck for now, but maybe this we should add "in previous loop iteration" as with some other borrowck errors. (Commit 2)
- Use revisions to check mir borrowck for the existing tests for this error. (Commit 3)

~~Still working on a less ad-hoc way to get 'first assignment' notes to show on the correct assignment. Also need to check mutating function arguments.~~ Now using a new dataflow pass.
@bors
Copy link
Collaborator

bors commented Nov 27, 2017

⌛ Testing commit d64a318 with merge 560a5da...

bors added a commit that referenced this pull request Nov 27, 2017
…elb1

Mir Borrowck: Parity with Ast for E0384 (Cannot assign twice to immutable)

- Closes #45199
- Don't allow assigning to dropped immutable variables
- Show the "first assignment" note on the first assignment that can actually come before the second assignment.
- Make "first assignment" notes point to function parameters if needed.
- Don't show a "first assignment" note if the first and second assignment have the same span (in a loop). This matches ast borrowck for now, but maybe this we should add "in previous loop iteration" as with some other borrowck errors. (Commit 2)
- Use revisions to check mir borrowck for the existing tests for this error. (Commit 3)

~~Still working on a less ad-hoc way to get 'first assignment' notes to show on the correct assignment. Also need to check mutating function arguments.~~ Now using a new dataflow pass.
@bors
Copy link
Collaborator

bors commented Nov 27, 2017

☀️ Test successful - status-appveyor, status-travis
Approved by: arielb1
Pushing 560a5da to master...

@bors bors merged commit d64a318 into rust-lang:master Nov 27, 2017
@matthewjasper matthewjasper deleted the cannot-assign-twice-error branch May 11, 2018 21:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants