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

NLL: Suggest ref mut and &mut self #52242

Merged
merged 16 commits into from
Jul 13, 2018
Merged

Conversation

ashtneoi
Copy link
Contributor

@ashtneoi ashtneoi commented Jul 11, 2018

Fixes #51244. Supersedes #51249, I think.

Under the old lexical lifetimes, the compiler provided helpful suggestions about adding mut when you tried to mutate a variable bound as &self or (explicit) ref. NLL doesn't have those suggestions yet. This pull request adds them.

I didn't bother making the help text exactly the same as without NLL, but I can if that's important.

(Originally this was supposed to be part of #51612, but I got bogged down trying to fit everything in one PR.)

@rust-highfive
Copy link
Collaborator

r? @nikomatsakis

(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 Jul 11, 2018

Some(ClearCrossCrate::Clear) => bug!("saw cleared local state"),

None => bug!(),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not really sure what the most idiomatic way to do this is. I could add .as_ref().unwrap() on line 1844, but that felt kinda ugly.

) -> (Span, String) {
// This implementation attempts to emulate AST-borrowck prioritization
// by trying (3.), then (2.) and finally falling back on (1.).
let locations = mir.find_assignments(local);
if locations.len() > 0 {
let assignment_rhs_span = mir.source_info(locations[0]).span;
let snippet = tcx.sess.codemap().span_to_snippet(assignment_rhs_span);
if let Ok(src) = snippet {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not clear to me how span_to_snippet could fail, but I left the fallthrough alone just in case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

(instead of unwrapping the result)

@ashtneoi
Copy link
Contributor Author

cc @pnkfelix if you're interested

@csmoe
Copy link
Member

csmoe commented Jul 12, 2018

@ashtneoi wow, you moved further than me #51249 when addressing the issue about old suggestion #51244 , it's well covered by your suggest_ref_mut method, would you mind fixing that here?

@ashtneoi
Copy link
Contributor Author

@csmoe Does this look right? I rebased your branch onto mine and updated the tests.

@ashtneoi
Copy link
Contributor Author

Or did you want me to factor out the ref -> ref mut code?

@csmoe
Copy link
Member

csmoe commented Jul 12, 2018

@ashtneoi yep, I wanna introduce your suggest_ref_mut(or likely) there since the old and my replacement solution is untidy.

@ashtneoi
Copy link
Contributor Author

@csmoe Ok, I think I did it. Also fixed that "use a mutable reference instead: x" help message.

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-5.0 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
/usr/local/lib/python2.7/dist-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py:122: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.io/en/latest/security.html#insecureplatformwarning.
  InsecurePlatformWarning
/usr/local/lib/python2.7/dist-packages/pip/_vendor/requests/packages/urllib3/util/ssl_.py:122: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. You can upgrade to a newer version of Python to solve this. For more information, see https://urllib3.readthedocs.io/en/latest/security.html#insecureplatformwarning.
  InsecurePlatformWarning
  Downloading https://files.pythonhosted.org/packages/f7/fc/4e5fde613a2c680621c500ca1b1f4f2b53bd1d02ea4b5a91663f58e7a320/awscli-1.15.58-py2.py3-none-any.whl (1.3MB)
    0% |▎                               | 10kB 12.5MB/s eta 0:00:01
    1% |▌                               | 20kB 1.8MB/s eta 0:00:01
    2% |▊                               | 30kB 2.2MB/s eta 0:00:01
    3% |█                               | 40kB 2.0MB/s eta 0:00:01
---
[00:47:19] ......................................i.............................................................
[00:47:22] ............................i.......................................................................
[00:47:25] ....................................................................................................
[00:47:28] ....................................................................................................
[00:47:32] ............................................F................................i......................
  ^^^^^^^^^^^ cannot borrow as mutable
[00:47:34] +    |     ^^^^^^^^^^^ `my_ref` is a `&` reference, so the data it refers to cannot be written
[00:47:34] 9 error: aborting due to previous error
[00:47:34] 10 
[00:47:34] 
[00:47:34] 
[00:47:34] 
[00:47:34] The actual stderr differed from the expected stderr.
[00:47:34] Actual stderr saved to /checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/suggestions/issue-51244.nll/issue-51244.nll.stderr
[00:47:34] To update references, rerun the tests and pass the `--bless` flag
[00:47:34] To only update this specific test, also pass `--test-args suggestions/issue-51244.rs`
[00:47:34] error: 1 errors occurred comparing output.
[00:47:34] status: exit code: 101
[00:47:34] status: exit code: 101
[00:47:34] command: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/src/test/ui/suggestions/issue-51244.rs" "--target=x86_64-unknown-linux-gnu" "--error-format" "json" "-Zui-testing" "-C" "prefer-dynamic" "-o" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/suggestions/issue-51244.nll/a" "-Zborrowck=mir" "-Ztwo-phase-borrows" "-Crpath" "-O" "-Zunstable-options" "-Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "-L" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/suggestions/issue-51244.nll/auxiliary" "-A" "unused"
[00:47:34] ------------------------------------------
[00:47:34] 
[00:47:34] ------------------------------------------
[00:47:34] stderr:
[00:47:34] stderr:
[00:47:34] ------------------------------------------
[00:47:34] {"message":"cannot assign to `*my_ref` which is behind a `&` reference","code":{"code":"E0594""rendered":"error: aborting due to previous error\n\n"}
[00:47:34] {"message":"For more information about this error, try `rustc --explain E0594`.","code":null,"level":"","spans":[],"children":[],"rendered":"For more information about this error, try `rustc --explain E0594`.\n"}
[00:47:34] ------------------------------------------
[00:47:34] 
[00:47:34] thread '[ui (nll)] ui/suggestions/issue-51244.rs' panicked at 'explicit panic', tools/compiletest/src/runtest.rs:3139:9
[00:47:34] note: Run with `RUST_BACKTRACE=1` for a backtrace.
---
[00:47:34] test result: FAILED. 1557 passed; 1 failed; 5 ignored; 0 measured; 0 filtered out
[00:47:34] 
[00:47:34] 
[00:47:34] 
[00:47:34] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/compiletest" "--compile-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib" "--run-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-gnu/lib" "--rustc-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "--src-base" "/checkout/src/test/ui" "--build-base" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui" "--stage-id" "stage2-x86_64-unknown-linux-gnu" "--mode" "ui" "--target" "x86_64-unknown-linux-gnu" "--host" "x86_64-unknown-linux-gnu" "--llvm-filecheck" "/usr/lib/llvm-5.0/bin/FileCheck" "--host-rustcflags" "-Crpath -O -Zunstable-options " "--target-rustcflags" "-Crpath -O -Zunstable-options  -Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--docck-python" "/usr/bin/python2.7" "--lldb-python" "/usr/bin/python2.7" "--gdb" "/usr/bin/gdb" "--quiet" "--llvm-version" "5.0.0\n" "--system-llvm" "--cc" "" "--cxx" "" "--cflags" "" "--llvm-components" "" "--llvm-cxxflags" "" "--adb-path" "adb" "--adb-test-dir" "/data/tmp/work" "--android-cross-path" "" "--color" "always" "--compare-mode" "nll"
[00:47:34] 
[00:47:34] 
[00:47:34] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test
[00:47:34] Build completed unsuccessfully in 0:02:14
[00:47:34] Build completed unsuccessfully in 0:02:14
[00:47:34] Makefile:58: recipe for target 'check' failed
[00:47:34] make: *** [check] Error 1
2350756 ./obj
2350724 ./obj/build
1757848 ./obj/build/x86_64-unknown-linux-gnu
782440 ./src
---
143628 ./obj/build/x86_64-unknown-linux-gnu/stage1-std
133584 ./obj/build/x86_64-unknown-linux-gnu/stage1-rustc/x86_64-unknown-linux-gnu
133580 ./obj/build/x86_64-unknown-linux-gnu/stage1-rustc/x86_64-unknown-linux-gnu/release
130360 ./obj/build/bootstrap/debug/incremental/bootstrap-2evv84e4ca5z
130356 ./obj/build/bootstrap/debug/incremental/bootstrap-2evv84e4ca5z/s-f2ujtb4zxl-1hqhos6-3b6w870is5kd0
129456 ./obj/build/x86_64-unknown-linux-gnu/stage0-bootstrap-tools/x86_64-unknown-linux-gnu/release
122720 ./obj/build/x86_64-unknown-linux-gnu/stage1-rustc/x86_64-unknown-linux-gnu/release/deps
122452 ./obj/build/x86_64-unknown-linux-gnu/stage0-bootstrap-tools/x86_64-unknown-linux-gnu/release/deps
107620 ./src/llvm/test/CodeGen

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@pnkfelix
Copy link
Member

pnkfelix commented Jul 13, 2018

Weird, I had tried something similar to your changes here, but I kept hitting a problem where it was making erroneous suggestions for mutations of references in arm guards.

In particular for the test issue-27282-reborrow-ref-mut-in-guard.rs, my version of this code would try to suggest changing the ref mut r (to e.g. ref mut mut r; I'm not 100% sure of that, but it was along those lines).

But there is (by design) actually no way for the user to change r in any way that would make *r mutable within the guard.

So I had been spending time putting in some infrastructure to be able to filter this case.

But it seems like your PR here does not run into that problem.

I have not managed to figure out how you have managed to avoid it. heh.

  • Update: Ah, I think the thing I missed is how you are inspecting the mir::BindingForm carried in the is_user_variable

@pnkfelix
Copy link
Member

So, the approach I was planning to use wasn't going to have the local_decl.is_user_variable.is_some() guard; it was going to do something different which would have allowed it to suggest ref mut for bindings that are bound at deeper levels within a pattern.

In particular, if you look at my versions of tests like rfc-2005-default-binding-mode/enum.nll.stderr and rfc-2005-default-binding-mode/explicit-mut.nll.stderr, I have managed to provide suggestions for bindings like Some(n), even though those are not tagged with is_user_variable.

Having said that, there is something buggy in my own approach (which is why I have not put up a PR for it yet) and your approach is clearly fixing the bug in question and helping us bring NLL closer to parity with AST-borrowck in diagnostic quality.

So I am going to r+ your PR which will let me put my own branch on the back-burner.

@pnkfelix
Copy link
Member

@bors r+

@bors
Copy link
Contributor

bors commented Jul 13, 2018

📌 Commit 1ed8619 has been approved by pnkfelix

@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 Jul 13, 2018
@pnkfelix pnkfelix self-assigned this Jul 13, 2018
Mark-Simulacrum added a commit to Mark-Simulacrum/rust that referenced this pull request Jul 13, 2018
NLL: Suggest `ref mut` and `&mut self`

Fixes rust-lang#51244. Supersedes rust-lang#51249, I think.

Under the old lexical lifetimes, the compiler provided helpful suggestions about adding `mut` when you tried to mutate a variable bound as `&self` or (explicit) `ref`. NLL doesn't have those suggestions yet. This pull request adds them.

I didn't bother making the help text exactly the same as without NLL, but I can if that's important.

(Originally this was supposed to be part of rust-lang#51612, but I got bogged down trying to fit everything in one PR.)
bors added a commit that referenced this pull request Jul 13, 2018
Rollup of 16 pull requests

Successful merges:

 - #51962 (Provide llvm-strip in llvm-tools component)
 - #52003 (Implement `Option::replace` in the core library)
 - #52156 (Update std::ascii::ASCIIExt deprecation notes)
 - #52242 (NLL: Suggest `ref mut` and `&mut self`)
 - #52244 (Don't display default generic parameters in diagnostics that compare types)
 - #52290 (Deny bare trait objects in src/librustc_save_analysis)
 - #52293 (Deny bare trait objects in librustc_typeck)
 - #52299 (Deny bare trait objects in src/libserialize)
 - #52300 (Deny bare trait objects in librustc_target and libtest)
 - #52302 (Deny bare trait objects in the rest of rust)
 - #52310 (Backport 1.27.1 release notes to master)
 - #52314 (Fix ICE when using a pointer cast as array size)
 - #52315 (Resolve FIXME(#27942))
 - #52316 (task: remove wrong comments about non-existent LocalWake trait)
 - #52322 (Update llvm-rebuild-trigger in light of LLVM 7 upgrade)
 - #52332 (dead-code lint: say "constructed", "called" for structs, functions)

Failed merges:

r? @ghost
@bors
Copy link
Contributor

bors commented Jul 13, 2018

⌛ Testing commit 1ed8619 with merge fe29a4c...

bors added a commit that referenced this pull request Jul 13, 2018
NLL: Suggest `ref mut` and `&mut self`

Fixes #51244. Supersedes #51249, I think.

Under the old lexical lifetimes, the compiler provided helpful suggestions about adding `mut` when you tried to mutate a variable bound as `&self` or (explicit) `ref`. NLL doesn't have those suggestions yet. This pull request adds them.

I didn't bother making the help text exactly the same as without NLL, but I can if that's important.

(Originally this was supposed to be part of #51612, but I got bogged down trying to fit everything in one PR.)
@bors
Copy link
Contributor

bors commented Jul 13, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: pnkfelix
Pushing fe29a4c to master...

@bors bors merged commit 1ed8619 into rust-lang:master Jul 13, 2018
@ashtneoi
Copy link
Contributor Author

@pnkfelix As I understand it, the check for src.starts_with("ref") (plus whitespace) in suggest_ref_mut is what keeps implicit ref bindings like Some(n) from triggering the ref mut suggestion. I was able to get messages like this...

+	LL |         Some(n) => {
+	   |              - help: consider changing this to be a mutable reference: `<make this mutable> n`
16	LL |             *n += 1; //~ ERROR cannot assign to immutable

...by just returning Some instead of None from suggest_ref_mut when the binding doesn't start with ref. Should I submit a PR for that (with better wording, of course)?

@ashtneoi ashtneoi deleted the suggest-ref-mut branch July 13, 2018 20:24
@pnkfelix
Copy link
Member

pnkfelix commented Jul 17, 2018

Hmm I had thought, beyond the problem you describe, that there was also an issue involving is_user_variable (and I had thought there was some reason to try to leverage the internal variable for some purpose here...).

But its possible my memory is faulty.

Update: Yes my memory was just faulty. The cases I was thinking needed to be addressed are actually handled here.


We certainly could consider trying to also do something with implicit ref bindings, but I don't think we need to worry about that case right now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants