From f8eb9a685cb58aeea3b25cecf7a510f6ba5c92d5 Mon Sep 17 00:00:00 2001 From: ashtneoi Date: Tue, 10 Jul 2018 21:31:07 -0700 Subject: [PATCH 01/16] Add `ref mut` suggestion test --- src/test/ui/suggestions/suggest-ref-mut.rs | 31 +++++++++++++++++++ .../ui/suggestions/suggest-ref-mut.stderr | 21 +++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/test/ui/suggestions/suggest-ref-mut.rs create mode 100644 src/test/ui/suggestions/suggest-ref-mut.stderr diff --git a/src/test/ui/suggestions/suggest-ref-mut.rs b/src/test/ui/suggestions/suggest-ref-mut.rs new file mode 100644 index 0000000000000..1f5c5b033286c --- /dev/null +++ b/src/test/ui/suggestions/suggest-ref-mut.rs @@ -0,0 +1,31 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(nll)] + +fn main() { + let ref foo = 16; + //~^ HELP + //~| SUGGESTION ref mut foo + *foo = 32; + //~^ ERROR + if let Some(ref bar) = Some(16) { + //~^ HELP + //~| SUGGESTION ref mut bar + *bar = 32; + //~^ ERROR + } + match 16 { + ref quo => { *quo = 32; }, + //~^ ERROR + //~| HELP + //~| SUGGESTION ref mut quo + } +} diff --git a/src/test/ui/suggestions/suggest-ref-mut.stderr b/src/test/ui/suggestions/suggest-ref-mut.stderr new file mode 100644 index 0000000000000..6e151a995b826 --- /dev/null +++ b/src/test/ui/suggestions/suggest-ref-mut.stderr @@ -0,0 +1,21 @@ +error[E0594]: cannot assign to `*foo` which is behind a `&` reference + --> $DIR/suggest-ref-mut.rs:17:5 + | +LL | *foo = 32; + | ^^^^^^^^^ cannot assign + +error[E0594]: cannot assign to `*bar` which is behind a `&` reference + --> $DIR/suggest-ref-mut.rs:22:9 + | +LL | *bar = 32; + | ^^^^^^^^^ cannot assign + +error[E0594]: cannot assign to `*quo` which is behind a `&` reference + --> $DIR/suggest-ref-mut.rs:26:22 + | +LL | ref quo => { *quo = 32; }, + | ^^^^^^^^^ cannot assign + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0594`. From 52d6ae854d0f4c33aa65ad1c151bf7e1700de476 Mon Sep 17 00:00:00 2001 From: ashtneoi Date: Tue, 10 Jul 2018 22:58:43 -0700 Subject: [PATCH 02/16] Reimplement some "add `mut`" suggestions under NLL Specifically, `&self` -> `&mut self` and explicit `ref` -> `ref mut`. Implicit `ref` isn't handled yet and causes an ICE. --- src/librustc_mir/borrow_check/mod.rs | 99 +++++++++++++------ src/librustc_mir/lib.rs | 2 + .../ui/did_you_mean/issue-38147-1.nll.stderr | 2 +- .../ui/did_you_mean/issue-39544.nll.stderr | 6 +- .../ui/suggestions/suggest-ref-mut.stderr | 14 ++- 5 files changed, 88 insertions(+), 35 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 1a66a2d2cb902..243f378377f9a 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -29,6 +29,8 @@ use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::small_vec::SmallVec; +use core::unicode::property::Pattern_White_Space; + use std::rc::Rc; use syntax_pos::Span; @@ -1837,17 +1839,45 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Place::Projection(box Projection { base: Place::Local(local), elem: ProjectionElem::Deref, - }) if self.mir.local_decls[*local].is_nonref_binding() => - { - let (err_help_span, suggested_code) = - find_place_to_suggest_ampmut(self.tcx, self.mir, *local); + }) if self.mir.local_decls[*local].is_user_variable.is_some() => { + let local_decl = &self.mir.local_decls[*local]; + let (err_help_span, suggested_code) = match local_decl.is_user_variable { + Some(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf)) => { + suggest_ampmut_self(local_decl) + }, + + Some(ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(_), + opt_ty_info, + .. + }))) => { + if let Some(x) = try_suggest_ampmut_rhs( + self.tcx, self.mir, *local, + ) { + x + } else { + suggest_ampmut_type(local_decl, opt_ty_info) + } + }, + + Some(ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByReference(_), + .. + }))) => { + suggest_ref_mut(self.tcx, local_decl) + }, + + Some(ClearCrossCrate::Clear) => bug!("saw cleared local state"), + + None => bug!(), + }; + err.span_suggestion( err_help_span, "consider changing this to be a mutable reference", suggested_code, ); - let local_decl = &self.mir.local_decls[*local]; if let Some(name) = local_decl.name { err.span_label( span, @@ -1874,13 +1904,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { err.emit(); return true; - // Returns the span to highlight and the associated text to - // present when suggesting that the user use an `&mut`. - // + fn suggest_ampmut_self<'cx, 'gcx, 'tcx>( + local_decl: &mir::LocalDecl<'tcx>, + ) -> (Span, String) { + (local_decl.source_info.span, "&mut self".to_string()) + } + // When we want to suggest a user change a local variable to be a `&mut`, there // are three potential "obvious" things to highlight: // - // let ident [: Type] [= RightHandSideExresssion]; + // let ident [: Type] [= RightHandSideExpression]; // ^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ // (1.) (2.) (3.) // @@ -1889,48 +1922,58 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // for example, if the RHS is present and the Type is not, then the type is going to // be inferred *from* the RHS, which means we should highlight that (and suggest // that they borrow the RHS mutably). - fn find_place_to_suggest_ampmut<'cx, 'gcx, 'tcx>( + // + // This implementation attempts to emulate AST-borrowck prioritization + // by trying (3.), then (2.) and finally falling back on (1.). + + fn try_suggest_ampmut_rhs<'cx, 'gcx, 'tcx>( tcx: TyCtxt<'cx, 'gcx, 'tcx>, mir: &Mir<'tcx>, local: Local, - ) -> (Span, String) { - // This implementation attempts to emulate AST-borrowck prioritization - // by trying (3.), then (2.) and finally falling back on (1.). + ) -> Option<(Span, String)> { 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 { - // pnkfelix inherited code; believes intention is - // highlighted text will always be `&` and - // thus can transform to `&mut` by slicing off - // first ASCII character and prepending "&mut ". if src.starts_with('&') { let borrowed_expr = src[1..].to_string(); - return (assignment_rhs_span, format!("&mut {}", borrowed_expr)); + return Some((assignment_rhs_span, format!("&mut {}", borrowed_expr))); } } } + None + } - let local_decl = &mir.local_decls[local]; - let highlight_span = match local_decl.is_user_variable { + fn suggest_ampmut_type<'tcx>( + local_decl: &mir::LocalDecl<'tcx>, + opt_ty_info: Option, + ) -> (Span, String) { + let highlight_span = match opt_ty_info { // if this is a variable binding with an explicit type, // try to highlight that for the suggestion. - Some(ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { - opt_ty_info: Some(ty_span), - .. - }))) => ty_span, - - Some(ClearCrossCrate::Clear) => bug!("saw cleared local state"), + Some(ty_span) => ty_span, // otherwise, just highlight the span associated with // the (MIR) LocalDecl. - _ => local_decl.source_info.span, + None => local_decl.source_info.span, }; let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); assert_eq!(ty_mut.mutbl, hir::MutImmutable); - return (highlight_span, format!("&mut {}", ty_mut.ty)); + (highlight_span, format!("&mut {}", ty_mut.ty)) + } + + fn suggest_ref_mut<'cx, 'gcx, 'tcx>( + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + local_decl: &mir::LocalDecl<'tcx>, + ) -> (Span, String) { + let hi_span = local_decl.source_info.span; + let hi_src = tcx.sess.codemap().span_to_snippet(hi_span).unwrap(); + assert!(hi_src.starts_with("ref")); + assert!(hi_src["ref".len()..].starts_with(Pattern_White_Space)); + let suggestion = format!("ref mut{}", &hi_src["ref".len()..]); + (hi_span, suggestion) } } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index dc0d0b244633f..92c0a2b475c20 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -33,6 +33,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(never_type)] #![feature(specialization)] #![feature(try_trait)] +#![feature(unicode_internals)] #![recursion_limit="256"] @@ -56,6 +57,7 @@ extern crate rustc_target; extern crate log_settings; extern crate rustc_apfloat; extern crate byteorder; +extern crate core; mod diagnostics; diff --git a/src/test/ui/did_you_mean/issue-38147-1.nll.stderr b/src/test/ui/did_you_mean/issue-38147-1.nll.stderr index 76b8c8ebf6029..d156d64b9d693 100644 --- a/src/test/ui/did_you_mean/issue-38147-1.nll.stderr +++ b/src/test/ui/did_you_mean/issue-38147-1.nll.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow immutable item `*self.s` as mutable --> $DIR/issue-38147-1.rs:27:9 | LL | fn f(&self) { - | ----- help: consider changing this to be a mutable reference: `&mut Foo<'_>` + | ----- help: consider changing this to be a mutable reference: `&mut self` LL | self.s.push('x'); //~ ERROR cannot borrow data mutably | ^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable diff --git a/src/test/ui/did_you_mean/issue-39544.nll.stderr b/src/test/ui/did_you_mean/issue-39544.nll.stderr index 02c1debca69b2..e2d2fcd63db12 100644 --- a/src/test/ui/did_you_mean/issue-39544.nll.stderr +++ b/src/test/ui/did_you_mean/issue-39544.nll.stderr @@ -10,7 +10,7 @@ error[E0596]: cannot borrow immutable item `self.x` as mutable --> $DIR/issue-39544.rs:26:17 | LL | fn foo<'z>(&'z self) { - | -------- help: consider changing this to be a mutable reference: `&mut Z` + | -------- help: consider changing this to be a mutable reference: `&mut self` LL | let _ = &mut self.x; //~ ERROR cannot borrow | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -18,7 +18,7 @@ error[E0596]: cannot borrow immutable item `self.x` as mutable --> $DIR/issue-39544.rs:30:17 | LL | fn foo1(&self, other: &Z) { - | ----- help: consider changing this to be a mutable reference: `&mut Z` + | ----- help: consider changing this to be a mutable reference: `&mut self` LL | let _ = &mut self.x; //~ ERROR cannot borrow | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable @@ -35,7 +35,7 @@ error[E0596]: cannot borrow immutable item `self.x` as mutable --> $DIR/issue-39544.rs:35:17 | LL | fn foo2<'a>(&'a self, other: &Z) { - | -------- help: consider changing this to be a mutable reference: `&mut Z` + | -------- help: consider changing this to be a mutable reference: `&mut self` LL | let _ = &mut self.x; //~ ERROR cannot borrow | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable diff --git a/src/test/ui/suggestions/suggest-ref-mut.stderr b/src/test/ui/suggestions/suggest-ref-mut.stderr index 6e151a995b826..d1590b3934e0b 100644 --- a/src/test/ui/suggestions/suggest-ref-mut.stderr +++ b/src/test/ui/suggestions/suggest-ref-mut.stderr @@ -1,20 +1,28 @@ error[E0594]: cannot assign to `*foo` which is behind a `&` reference --> $DIR/suggest-ref-mut.rs:17:5 | +LL | let ref foo = 16; + | ------- help: consider changing this to be a mutable reference: `ref mut foo` +... LL | *foo = 32; - | ^^^^^^^^^ cannot assign + | ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*bar` which is behind a `&` reference --> $DIR/suggest-ref-mut.rs:22:9 | +LL | if let Some(ref bar) = Some(16) { + | ------- help: consider changing this to be a mutable reference: `ref mut bar` +... LL | *bar = 32; - | ^^^^^^^^^ cannot assign + | ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*quo` which is behind a `&` reference --> $DIR/suggest-ref-mut.rs:26:22 | LL | ref quo => { *quo = 32; }, - | ^^^^^^^^^ cannot assign + | ------- ^^^^^^^^^ `quo` is a `&` reference, so the data it refers to cannot be written + | | + | help: consider changing this to be a mutable reference: `ref mut quo` error: aborting due to 3 previous errors From 6fd1a9fff79d906ecadcc9eab3962d84d38c7061 Mon Sep 17 00:00:00 2001 From: ashtneoi Date: Tue, 10 Jul 2018 23:14:12 -0700 Subject: [PATCH 03/16] Don't try to suggest `ref mut` for implicit `ref` --- src/librustc_mir/borrow_check/mod.rs | 34 +++++++++++-------- .../enum.nll.stderr | 6 ++-- .../explicit-mut.nll.stderr | 6 ++-- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 243f378377f9a..95601f1337139 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1841,9 +1841,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { elem: ProjectionElem::Deref, }) if self.mir.local_decls[*local].is_user_variable.is_some() => { let local_decl = &self.mir.local_decls[*local]; - let (err_help_span, suggested_code) = match local_decl.is_user_variable { + let suggestion = match local_decl.is_user_variable { Some(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf)) => { - suggest_ampmut_self(local_decl) + Some(suggest_ampmut_self(local_decl)) }, Some(ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { @@ -1854,9 +1854,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if let Some(x) = try_suggest_ampmut_rhs( self.tcx, self.mir, *local, ) { - x + Some(x) } else { - suggest_ampmut_type(local_decl, opt_ty_info) + Some(suggest_ampmut_type(local_decl, opt_ty_info)) } }, @@ -1872,11 +1872,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { None => bug!(), }; - err.span_suggestion( - err_help_span, - "consider changing this to be a mutable reference", - suggested_code, - ); + if let Some((err_help_span, suggested_code)) = suggestion { + err.span_suggestion( + err_help_span, + "consider changing this to be a mutable reference", + suggested_code, + ); + } if let Some(name) = local_decl.name { err.span_label( @@ -1967,13 +1969,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { fn suggest_ref_mut<'cx, 'gcx, 'tcx>( tcx: TyCtxt<'cx, 'gcx, 'tcx>, local_decl: &mir::LocalDecl<'tcx>, - ) -> (Span, String) { + ) -> Option<(Span, String)> { let hi_span = local_decl.source_info.span; let hi_src = tcx.sess.codemap().span_to_snippet(hi_span).unwrap(); - assert!(hi_src.starts_with("ref")); - assert!(hi_src["ref".len()..].starts_with(Pattern_White_Space)); - let suggestion = format!("ref mut{}", &hi_src["ref".len()..]); - (hi_span, suggestion) + if hi_src.starts_with("ref") + && hi_src["ref".len()..].starts_with(Pattern_White_Space) + { + let suggestion = format!("ref mut{}", &hi_src["ref".len()..]); + Some((hi_span, suggestion)) + } else { + None + } } } diff --git a/src/test/ui/rfc-2005-default-binding-mode/enum.nll.stderr b/src/test/ui/rfc-2005-default-binding-mode/enum.nll.stderr index 8aa7e8a417c2b..a9b2bca434cba 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/enum.nll.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/enum.nll.stderr @@ -2,19 +2,19 @@ error[E0594]: cannot assign to `*x` which is behind a `&` reference --> $DIR/enum.rs:19:5 | LL | *x += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot assign + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*x` which is behind a `&` reference --> $DIR/enum.rs:23:9 | LL | *x += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot assign + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*x` which is behind a `&` reference --> $DIR/enum.rs:29:9 | LL | *x += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot assign + | ^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be written error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.nll.stderr b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.nll.stderr index 4e00dec761621..4c6149a8b7b30 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.nll.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.nll.stderr @@ -2,19 +2,19 @@ error[E0594]: cannot assign to `*n` which is behind a `&` reference --> $DIR/explicit-mut.rs:17:13 | LL | *n += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot assign + | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*n` which is behind a `&` reference --> $DIR/explicit-mut.rs:25:13 | LL | *n += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot assign + | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*n` which is behind a `&` reference --> $DIR/explicit-mut.rs:33:13 | LL | *n += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot assign + | ^^^^^^^ `n` is a `&` reference, so the data it refers to cannot be written error: aborting due to 3 previous errors From b8b04f6385ce9909a165ff47c5ebf49ded1fc6db Mon Sep 17 00:00:00 2001 From: ashtneoi Date: Tue, 10 Jul 2018 23:23:13 -0700 Subject: [PATCH 04/16] Put the two halves of suggest_ampmut back together --- src/librustc_mir/borrow_check/mod.rs | 38 ++++++++++++---------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 95601f1337139..039f43cd213f7 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1850,22 +1850,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { binding_mode: ty::BindingMode::BindByValue(_), opt_ty_info, .. - }))) => { - if let Some(x) = try_suggest_ampmut_rhs( - self.tcx, self.mir, *local, - ) { - Some(x) - } else { - Some(suggest_ampmut_type(local_decl, opt_ty_info)) - } - }, + }))) => Some(suggest_ampmut( + self.tcx, + self.mir, + *local, + local_decl, + opt_ty_info, + )), Some(ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { binding_mode: ty::BindingMode::BindByReference(_), .. - }))) => { - suggest_ref_mut(self.tcx, local_decl) - }, + }))) => suggest_ref_mut(self.tcx, local_decl), Some(ClearCrossCrate::Clear) => bug!("saw cleared local state"), @@ -1927,12 +1923,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // // This implementation attempts to emulate AST-borrowck prioritization // by trying (3.), then (2.) and finally falling back on (1.). - - fn try_suggest_ampmut_rhs<'cx, 'gcx, 'tcx>( + fn suggest_ampmut<'cx, 'gcx, 'tcx>( tcx: TyCtxt<'cx, 'gcx, 'tcx>, mir: &Mir<'tcx>, local: Local, - ) -> Option<(Span, String)> { + local_decl: &mir::LocalDecl<'tcx>, + opt_ty_info: Option, + ) -> (Span, String) { let locations = mir.find_assignments(local); if locations.len() > 0 { let assignment_rhs_span = mir.source_info(locations[0]).span; @@ -1940,17 +1937,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if let Ok(src) = snippet { if src.starts_with('&') { let borrowed_expr = src[1..].to_string(); - return Some((assignment_rhs_span, format!("&mut {}", borrowed_expr))); + return ( + assignment_rhs_span, + format!("&mut {}", borrowed_expr), + ); } } } - None - } - fn suggest_ampmut_type<'tcx>( - local_decl: &mir::LocalDecl<'tcx>, - opt_ty_info: Option, - ) -> (Span, String) { let highlight_span = match opt_ty_info { // if this is a variable binding with an explicit type, // try to highlight that for the suggestion. From 73a979ad63ea20821996809aaccb82767ac84658 Mon Sep 17 00:00:00 2001 From: ashtneoi Date: Wed, 11 Jul 2018 00:44:55 -0700 Subject: [PATCH 05/16] Simplify match expression --- src/librustc_mir/borrow_check/mod.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 039f43cd213f7..b754fde9069a5 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1841,31 +1841,29 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { elem: ProjectionElem::Deref, }) if self.mir.local_decls[*local].is_user_variable.is_some() => { let local_decl = &self.mir.local_decls[*local]; - let suggestion = match local_decl.is_user_variable { - Some(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf)) => { + let suggestion = match local_decl.is_user_variable.as_ref().unwrap() { + ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf) => { Some(suggest_ampmut_self(local_decl)) }, - Some(ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { + ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { binding_mode: ty::BindingMode::BindByValue(_), opt_ty_info, .. - }))) => Some(suggest_ampmut( + })) => Some(suggest_ampmut( self.tcx, self.mir, *local, local_decl, - opt_ty_info, + *opt_ty_info, )), - Some(ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { + ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { binding_mode: ty::BindingMode::BindByReference(_), .. - }))) => suggest_ref_mut(self.tcx, local_decl), - - Some(ClearCrossCrate::Clear) => bug!("saw cleared local state"), + })) => suggest_ref_mut(self.tcx, local_decl), - None => bug!(), + ClearCrossCrate::Clear => bug!("saw cleared local state"), }; if let Some((err_help_span, suggested_code)) = suggestion { From 77d5f397716778fcc82a60ea9d6102c0cfea15f6 Mon Sep 17 00:00:00 2001 From: ashtneoi Date: Wed, 11 Jul 2018 03:45:25 -0700 Subject: [PATCH 06/16] Also test `&mut self` suggestion --- src/test/ui/suggestions/suggest-ref-mut.rs | 11 +++++++++++ src/test/ui/suggestions/suggest-ref-mut.stderr | 17 +++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/test/ui/suggestions/suggest-ref-mut.rs b/src/test/ui/suggestions/suggest-ref-mut.rs index 1f5c5b033286c..30b5371af1ac5 100644 --- a/src/test/ui/suggestions/suggest-ref-mut.rs +++ b/src/test/ui/suggestions/suggest-ref-mut.rs @@ -10,6 +10,17 @@ #![feature(nll)] +struct X(usize); + +impl X { + fn zap(&self) { + //~^ HELP + //~| SUGGESTION &mut self + self.0 = 32; + //~^ ERROR + } +} + fn main() { let ref foo = 16; //~^ HELP diff --git a/src/test/ui/suggestions/suggest-ref-mut.stderr b/src/test/ui/suggestions/suggest-ref-mut.stderr index d1590b3934e0b..0b2b240ef53a8 100644 --- a/src/test/ui/suggestions/suggest-ref-mut.stderr +++ b/src/test/ui/suggestions/suggest-ref-mut.stderr @@ -1,5 +1,14 @@ +error[E0594]: cannot assign to `self.0` which is behind a `&` reference + --> $DIR/suggest-ref-mut.rs:19:9 + | +LL | fn zap(&self) { + | ----- help: consider changing this to be a mutable reference: `&mut self` +... +LL | self.0 = 32; + | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written + error[E0594]: cannot assign to `*foo` which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:17:5 + --> $DIR/suggest-ref-mut.rs:28:5 | LL | let ref foo = 16; | ------- help: consider changing this to be a mutable reference: `ref mut foo` @@ -8,7 +17,7 @@ LL | *foo = 32; | ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*bar` which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:22:9 + --> $DIR/suggest-ref-mut.rs:33:9 | LL | if let Some(ref bar) = Some(16) { | ------- help: consider changing this to be a mutable reference: `ref mut bar` @@ -17,13 +26,13 @@ LL | *bar = 32; | ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*quo` which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:26:22 + --> $DIR/suggest-ref-mut.rs:37:22 | LL | ref quo => { *quo = 32; }, | ------- ^^^^^^^^^ `quo` is a `&` reference, so the data it refers to cannot be written | | | help: consider changing this to be a mutable reference: `ref mut quo` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0594`. From 246caea009fd7b652d00f1b0a94108b7ac5b7938 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Thu, 31 May 2018 22:31:13 +0800 Subject: [PATCH 07/16] fix wrong replacing --- src/librustc_borrowck/borrowck/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 7c2d5ba094ffa..072f94661e429 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -1214,7 +1214,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { db.span_label( let_span, format!("consider changing this to `{}`", - snippet.replace("ref ", "ref mut ")) + snippet.replacen("ref ", "ref mut ", 1)) ); } } From 4e5d22889bb299290fba61c9b51afe75bac583a0 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Thu, 31 May 2018 23:00:58 +0800 Subject: [PATCH 08/16] update test --- src/test/ui/suggestions/issue-51244.rs | 14 ++++++++++++++ src/test/ui/suggestions/issue-51244.stderr | 11 +++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/test/ui/suggestions/issue-51244.rs create mode 100644 src/test/ui/suggestions/issue-51244.stderr diff --git a/src/test/ui/suggestions/issue-51244.rs b/src/test/ui/suggestions/issue-51244.rs new file mode 100644 index 0000000000000..efb8a03a45cbc --- /dev/null +++ b/src/test/ui/suggestions/issue-51244.rs @@ -0,0 +1,14 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let ref my_ref @ _ = 0; + *my_ref = 0; +} diff --git a/src/test/ui/suggestions/issue-51244.stderr b/src/test/ui/suggestions/issue-51244.stderr new file mode 100644 index 0000000000000..b6663c3789ebc --- /dev/null +++ b/src/test/ui/suggestions/issue-51244.stderr @@ -0,0 +1,11 @@ +error[E0594]: cannot assign to immutable borrowed content `*my_ref` + --> $DIR/issue-51244.rs:13:5 + | +LL | let ref my_ref @ _ = 0; + | -------------- consider changing this to `ref mut my_ref @ _` +LL | *my_ref = 0; + | ^^^^^^^^^^^ cannot borrow as mutable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. From 1662daa23d77d77107743926efee72e8254d8f35 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Fri, 1 Jun 2018 12:08:31 +0800 Subject: [PATCH 09/16] lint with ref_span --- src/librustc_borrowck/borrowck/mod.rs | 12 +++++------- src/test/ui/suggestions/issue-51244.stderr | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 072f94661e429..f09feac51fcfb 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -1209,14 +1209,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let let_span = self.tcx.hir.span(node_id); match self.local_binding_mode(node_id) { ty::BindByReference(..) => { - let snippet = self.tcx.sess.codemap().span_to_snippet(let_span); - if let Ok(snippet) = snippet { + let ref_span = self.tcx.sess.codemap().span_until_whitespace(let_span); + if let Ok(_) = self.tcx.sess.codemap().span_to_snippet(let_span) { db.span_label( - let_span, - format!("consider changing this to `{}`", - snippet.replacen("ref ", "ref mut ", 1)) - ); - } + ref_span, + format!("consider changing this to `{}`", "ref mut")); + }; } ty::BindByValue(..) => { if let (Some(local_ty), is_implicit_self) = self.local_ty(node_id) { diff --git a/src/test/ui/suggestions/issue-51244.stderr b/src/test/ui/suggestions/issue-51244.stderr index b6663c3789ebc..f653a2a3359b1 100644 --- a/src/test/ui/suggestions/issue-51244.stderr +++ b/src/test/ui/suggestions/issue-51244.stderr @@ -2,7 +2,7 @@ error[E0594]: cannot assign to immutable borrowed content `*my_ref` --> $DIR/issue-51244.rs:13:5 | LL | let ref my_ref @ _ = 0; - | -------------- consider changing this to `ref mut my_ref @ _` + | --- consider changing this to `ref mut` LL | *my_ref = 0; | ^^^^^^^^^^^ cannot borrow as mutable From af5edc32df6a30bc7c8caa01bb9700b38354e21f Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Fri, 1 Jun 2018 19:00:15 +0800 Subject: [PATCH 10/16] replace ref --- src/librustc_borrowck/borrowck/mod.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index f09feac51fcfb..aa00ccd1f08cd 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -1209,11 +1209,16 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let let_span = self.tcx.hir.span(node_id); match self.local_binding_mode(node_id) { ty::BindByReference(..) => { - let ref_span = self.tcx.sess.codemap().span_until_whitespace(let_span); - if let Ok(_) = self.tcx.sess.codemap().span_to_snippet(let_span) { + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { + let replace_str = if snippet.starts_with("ref ") { + snippet.replacen("ref ", "ref mut ", 1) + } else { + snippet + }; db.span_label( - ref_span, - format!("consider changing this to `{}`", "ref mut")); + let_span, + format!("consider changing this to `{}`", replace_str) + ); }; } ty::BindByValue(..) => { From 212da122f798b1a4a58f41c7eeb8111dffaee4cb Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Fri, 1 Jun 2018 21:03:24 +0800 Subject: [PATCH 11/16] update test --- src/test/ui/suggestions/issue-51244.rs | 2 +- src/test/ui/suggestions/issue-51244.stderr | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/ui/suggestions/issue-51244.rs b/src/test/ui/suggestions/issue-51244.rs index efb8a03a45cbc..50a21184a98b9 100644 --- a/src/test/ui/suggestions/issue-51244.rs +++ b/src/test/ui/suggestions/issue-51244.rs @@ -10,5 +10,5 @@ fn main() { let ref my_ref @ _ = 0; - *my_ref = 0; + *my_ref = 0; //~ ERROR cannot assign to immutable borrowed content `*my_ref` [E0594] } diff --git a/src/test/ui/suggestions/issue-51244.stderr b/src/test/ui/suggestions/issue-51244.stderr index f653a2a3359b1..b4ce29756235b 100644 --- a/src/test/ui/suggestions/issue-51244.stderr +++ b/src/test/ui/suggestions/issue-51244.stderr @@ -2,8 +2,8 @@ error[E0594]: cannot assign to immutable borrowed content `*my_ref` --> $DIR/issue-51244.rs:13:5 | LL | let ref my_ref @ _ = 0; - | --- consider changing this to `ref mut` -LL | *my_ref = 0; + | -------------- consider changing this to `ref mut my_ref @ _` +LL | *my_ref = 0; //~ ERROR cannot assign to immutable borrowed content `*my_ref` [E0594] | ^^^^^^^^^^^ cannot borrow as mutable error: aborting due to previous error From 8932684ccc3b4a24a301bd68a6c21a182dfd6028 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Sun, 3 Jun 2018 12:06:21 +0800 Subject: [PATCH 12/16] add nll stderr --- src/test/ui/suggestions/issue-51244.nll.stderr | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/test/ui/suggestions/issue-51244.nll.stderr diff --git a/src/test/ui/suggestions/issue-51244.nll.stderr b/src/test/ui/suggestions/issue-51244.nll.stderr new file mode 100644 index 0000000000000..95b71c41cfa7b --- /dev/null +++ b/src/test/ui/suggestions/issue-51244.nll.stderr @@ -0,0 +1,11 @@ +error[E0594]: cannot assign to data in a `&` reference + --> $DIR/issue-51244.rs:13:5 + | +LL | let ref my_ref @ _ = 0; + | -------------- help: consider changing this to be a mutable reference: `&mut ef my_ref @ _` +LL | *my_ref = 0; //~ ERROR cannot assign to immutable borrowed content `*my_ref` [E0594] + | ^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. From 7a70140ed5a3fb5aa747d219f19f8b1d55812807 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Thu, 14 Jun 2018 09:12:50 +0800 Subject: [PATCH 13/16] span_suggestion --- src/librustc_borrowck/borrowck/mod.rs | 5 +++-- src/test/ui/nll/issue-51244.rs | 16 ++++++++++++++++ .../issue-51244.stderr} | 4 ++-- .../ui/rfc-2005-default-binding-mode/enum.stderr | 6 +++--- .../explicit-mut.stderr | 6 +++--- src/test/ui/suggestions/issue-51244.stderr | 2 +- 6 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/nll/issue-51244.rs rename src/test/ui/{suggestions/issue-51244.nll.stderr => nll/issue-51244.stderr} (72%) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index aa00ccd1f08cd..6a42189fb152f 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -1215,9 +1215,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } else { snippet }; - db.span_label( + db.span_suggestion( let_span, - format!("consider changing this to `{}`", replace_str) + "use a mutable reference instead", + replace_str, ); }; } diff --git a/src/test/ui/nll/issue-51244.rs b/src/test/ui/nll/issue-51244.rs new file mode 100644 index 0000000000000..56d9449c4679d --- /dev/null +++ b/src/test/ui/nll/issue-51244.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(nll)] + +fn main() { + let ref my_ref @ _ = 0; + *my_ref = 0; //~ ERROR cannot assign to data in a `&` reference [E0594] +} diff --git a/src/test/ui/suggestions/issue-51244.nll.stderr b/src/test/ui/nll/issue-51244.stderr similarity index 72% rename from src/test/ui/suggestions/issue-51244.nll.stderr rename to src/test/ui/nll/issue-51244.stderr index 95b71c41cfa7b..f1f47fc61ce8b 100644 --- a/src/test/ui/suggestions/issue-51244.nll.stderr +++ b/src/test/ui/nll/issue-51244.stderr @@ -1,9 +1,9 @@ error[E0594]: cannot assign to data in a `&` reference - --> $DIR/issue-51244.rs:13:5 + --> $DIR/issue-51244.rs:15:5 | LL | let ref my_ref @ _ = 0; | -------------- help: consider changing this to be a mutable reference: `&mut ef my_ref @ _` -LL | *my_ref = 0; //~ ERROR cannot assign to immutable borrowed content `*my_ref` [E0594] +LL | *my_ref = 0; //~ ERROR cannot assign to data in a `&` reference [E0594] | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/rfc-2005-default-binding-mode/enum.stderr b/src/test/ui/rfc-2005-default-binding-mode/enum.stderr index a7f3b507508e8..26d51e9338152 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/enum.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/enum.stderr @@ -2,7 +2,7 @@ error[E0594]: cannot assign to immutable borrowed content `*x` --> $DIR/enum.rs:19:5 | LL | let Wrap(x) = &Wrap(3); - | - consider changing this to `x` + | - help: use a mutable reference instead: `x` LL | *x += 1; //~ ERROR cannot assign to immutable | ^^^^^^^ cannot borrow as mutable @@ -10,7 +10,7 @@ error[E0594]: cannot assign to immutable borrowed content `*x` --> $DIR/enum.rs:23:9 | LL | if let Some(x) = &Some(3) { - | - consider changing this to `x` + | - help: use a mutable reference instead: `x` LL | *x += 1; //~ ERROR cannot assign to immutable | ^^^^^^^ cannot borrow as mutable @@ -18,7 +18,7 @@ error[E0594]: cannot assign to immutable borrowed content `*x` --> $DIR/enum.rs:29:9 | LL | while let Some(x) = &Some(3) { - | - consider changing this to `x` + | - help: use a mutable reference instead: `x` LL | *x += 1; //~ ERROR cannot assign to immutable | ^^^^^^^ cannot borrow as mutable diff --git a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr index f2b9bde41ab33..2f5eb8a3d8ecc 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr @@ -2,7 +2,7 @@ error[E0594]: cannot assign to immutable borrowed content `*n` --> $DIR/explicit-mut.rs:17:13 | LL | Some(n) => { - | - consider changing this to `n` + | - help: use a mutable reference instead: `n` LL | *n += 1; //~ ERROR cannot assign to immutable | ^^^^^^^ cannot borrow as mutable @@ -10,7 +10,7 @@ error[E0594]: cannot assign to immutable borrowed content `*n` --> $DIR/explicit-mut.rs:25:13 | LL | Some(n) => { - | - consider changing this to `n` + | - help: use a mutable reference instead: `n` LL | *n += 1; //~ ERROR cannot assign to immutable | ^^^^^^^ cannot borrow as mutable @@ -18,7 +18,7 @@ error[E0594]: cannot assign to immutable borrowed content `*n` --> $DIR/explicit-mut.rs:33:13 | LL | Some(n) => { - | - consider changing this to `n` + | - help: use a mutable reference instead: `n` LL | *n += 1; //~ ERROR cannot assign to immutable | ^^^^^^^ cannot borrow as mutable diff --git a/src/test/ui/suggestions/issue-51244.stderr b/src/test/ui/suggestions/issue-51244.stderr index b4ce29756235b..997a74295e565 100644 --- a/src/test/ui/suggestions/issue-51244.stderr +++ b/src/test/ui/suggestions/issue-51244.stderr @@ -2,7 +2,7 @@ error[E0594]: cannot assign to immutable borrowed content `*my_ref` --> $DIR/issue-51244.rs:13:5 | LL | let ref my_ref @ _ = 0; - | -------------- consider changing this to `ref mut my_ref @ _` + | -------------- help: use a mutable reference instead: `ref mut my_ref @ _` LL | *my_ref = 0; //~ ERROR cannot assign to immutable borrowed content `*my_ref` [E0594] | ^^^^^^^^^^^ cannot borrow as mutable From 323df7b5049f6026a5bed335e2d7bb1df89b47ef Mon Sep 17 00:00:00 2001 From: ashtneoi Date: Thu, 12 Jul 2018 13:11:47 -0700 Subject: [PATCH 14/16] Bless tests and update ERROR --- src/test/ui/nll/issue-51244.rs | 3 ++- src/test/ui/nll/issue-51244.stderr | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/test/ui/nll/issue-51244.rs b/src/test/ui/nll/issue-51244.rs index 56d9449c4679d..f00ad3d6505be 100644 --- a/src/test/ui/nll/issue-51244.rs +++ b/src/test/ui/nll/issue-51244.rs @@ -12,5 +12,6 @@ fn main() { let ref my_ref @ _ = 0; - *my_ref = 0; //~ ERROR cannot assign to data in a `&` reference [E0594] + *my_ref = 0; + //~^ ERROR cannot assign to `*my_ref` which is behind a `&` reference [E0594] } diff --git a/src/test/ui/nll/issue-51244.stderr b/src/test/ui/nll/issue-51244.stderr index f1f47fc61ce8b..4e04aec8fe1af 100644 --- a/src/test/ui/nll/issue-51244.stderr +++ b/src/test/ui/nll/issue-51244.stderr @@ -1,10 +1,10 @@ -error[E0594]: cannot assign to data in a `&` reference +error[E0594]: cannot assign to `*my_ref` which is behind a `&` reference --> $DIR/issue-51244.rs:15:5 | LL | let ref my_ref @ _ = 0; - | -------------- help: consider changing this to be a mutable reference: `&mut ef my_ref @ _` -LL | *my_ref = 0; //~ ERROR cannot assign to data in a `&` reference [E0594] - | ^^^^^^^^^^^ + | -------------- help: consider changing this to be a mutable reference: `ref mut my_ref @ _` +LL | *my_ref = 0; + | ^^^^^^^^^^^ `my_ref` is a `&` reference, so the data it refers to cannot be written error: aborting due to previous error From 531a68cea711be0b803799fd30cc6cca43bea449 Mon Sep 17 00:00:00 2001 From: ashtneoi Date: Thu, 12 Jul 2018 15:39:36 -0700 Subject: [PATCH 15/16] Factor out suggest_ref_mut; use it in rustc_borrowck Also teach rustc_borrowck not to show useless help messages like "use a mutable reference instead: `x`". --- src/librustc_borrowck/borrowck/mod.rs | 13 +++++------- src/librustc_mir/borrow_check/mod.rs | 21 ++----------------- src/librustc_mir/util/mod.rs | 20 ++++++++++++++++++ .../rfc-2005-default-binding-mode/enum.stderr | 6 ------ .../explicit-mut.stderr | 6 ------ 5 files changed, 27 insertions(+), 39 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 6a42189fb152f..79b4382369217 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -39,6 +39,7 @@ use rustc::middle::free_region::RegionRelations; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::query::Providers; use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin}; +use rustc_mir::util::suggest_ref_mut; use rustc::util::nodemap::FxHashSet; use std::cell::RefCell; @@ -1206,21 +1207,17 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.note_immutable_local(db, error_node_id, node_id) } Some(ImmutabilityBlame::LocalDeref(node_id)) => { - let let_span = self.tcx.hir.span(node_id); match self.local_binding_mode(node_id) { ty::BindByReference(..) => { - if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { - let replace_str = if snippet.starts_with("ref ") { - snippet.replacen("ref ", "ref mut ", 1) - } else { - snippet - }; + let let_span = self.tcx.hir.span(node_id); + let suggestion = suggest_ref_mut(self.tcx, let_span); + if let Some((let_span, replace_str)) = suggestion { db.span_suggestion( let_span, "use a mutable reference instead", replace_str, ); - }; + } } ty::BindByValue(..) => { if let (Some(local_ty), is_implicit_self) = self.local_ty(node_id) { diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index b754fde9069a5..7078d77f3fb2b 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -29,8 +29,6 @@ use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::small_vec::SmallVec; -use core::unicode::property::Pattern_White_Space; - use std::rc::Rc; use syntax_pos::Span; @@ -46,6 +44,7 @@ use dataflow::{EverInitializedPlaces, MovingOutStatements}; use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; use util::borrowck_errors::{BorrowckErrors, Origin}; use util::collect_writes::FindAssignments; +use util::suggest_ref_mut; use self::borrow_set::{BorrowData, BorrowSet}; use self::flows::Flows; @@ -1861,7 +1860,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ClearCrossCrate::Set(mir::BindingForm::Var(mir::VarBindingForm { binding_mode: ty::BindingMode::BindByReference(_), .. - })) => suggest_ref_mut(self.tcx, local_decl), + })) => suggest_ref_mut(self.tcx, local_decl.source_info.span), ClearCrossCrate::Clear => bug!("saw cleared local state"), }; @@ -1957,22 +1956,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { assert_eq!(ty_mut.mutbl, hir::MutImmutable); (highlight_span, format!("&mut {}", ty_mut.ty)) } - - fn suggest_ref_mut<'cx, 'gcx, 'tcx>( - tcx: TyCtxt<'cx, 'gcx, 'tcx>, - local_decl: &mir::LocalDecl<'tcx>, - ) -> Option<(Span, String)> { - let hi_span = local_decl.source_info.span; - let hi_src = tcx.sess.codemap().span_to_snippet(hi_span).unwrap(); - if hi_src.starts_with("ref") - && hi_src["ref".len()..].starts_with(Pattern_White_Space) - { - let suggestion = format!("ref mut{}", &hi_src["ref".len()..]); - Some((hi_span, suggestion)) - } else { - None - } - } } /// Adds the place into the used mutable variables set diff --git a/src/librustc_mir/util/mod.rs b/src/librustc_mir/util/mod.rs index 19cd376688627..78e9dd23e83ae 100644 --- a/src/librustc_mir/util/mod.rs +++ b/src/librustc_mir/util/mod.rs @@ -8,6 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::unicode::property::Pattern_White_Space; +use rustc::ty; +use syntax_pos::Span; + pub mod borrowck_errors; pub mod elaborate_drops; pub mod def_use; @@ -23,3 +27,19 @@ pub use self::alignment::is_disaligned; pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere}; pub use self::graphviz::{write_mir_graphviz}; pub use self::graphviz::write_node_label as write_graphviz_node_label; + +/// If possible, suggest replacing `ref` with `ref mut`. +pub fn suggest_ref_mut<'cx, 'gcx, 'tcx>( + tcx: ty::TyCtxt<'cx, 'gcx, 'tcx>, + pattern_span: Span, +) -> Option<(Span, String)> { + let hi_src = tcx.sess.codemap().span_to_snippet(pattern_span).unwrap(); + if hi_src.starts_with("ref") + && hi_src["ref".len()..].starts_with(Pattern_White_Space) + { + let replacement = format!("ref mut{}", &hi_src["ref".len()..]); + Some((pattern_span, replacement)) + } else { + None + } +} diff --git a/src/test/ui/rfc-2005-default-binding-mode/enum.stderr b/src/test/ui/rfc-2005-default-binding-mode/enum.stderr index 26d51e9338152..ad05de9f3575f 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/enum.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/enum.stderr @@ -1,24 +1,18 @@ error[E0594]: cannot assign to immutable borrowed content `*x` --> $DIR/enum.rs:19:5 | -LL | let Wrap(x) = &Wrap(3); - | - help: use a mutable reference instead: `x` LL | *x += 1; //~ ERROR cannot assign to immutable | ^^^^^^^ cannot borrow as mutable error[E0594]: cannot assign to immutable borrowed content `*x` --> $DIR/enum.rs:23:9 | -LL | if let Some(x) = &Some(3) { - | - help: use a mutable reference instead: `x` LL | *x += 1; //~ ERROR cannot assign to immutable | ^^^^^^^ cannot borrow as mutable error[E0594]: cannot assign to immutable borrowed content `*x` --> $DIR/enum.rs:29:9 | -LL | while let Some(x) = &Some(3) { - | - help: use a mutable reference instead: `x` LL | *x += 1; //~ ERROR cannot assign to immutable | ^^^^^^^ cannot borrow as mutable diff --git a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr index 2f5eb8a3d8ecc..8da67a6b5ee65 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr @@ -1,24 +1,18 @@ error[E0594]: cannot assign to immutable borrowed content `*n` --> $DIR/explicit-mut.rs:17:13 | -LL | Some(n) => { - | - help: use a mutable reference instead: `n` LL | *n += 1; //~ ERROR cannot assign to immutable | ^^^^^^^ cannot borrow as mutable error[E0594]: cannot assign to immutable borrowed content `*n` --> $DIR/explicit-mut.rs:25:13 | -LL | Some(n) => { - | - help: use a mutable reference instead: `n` LL | *n += 1; //~ ERROR cannot assign to immutable | ^^^^^^^ cannot borrow as mutable error[E0594]: cannot assign to immutable borrowed content `*n` --> $DIR/explicit-mut.rs:33:13 | -LL | Some(n) => { - | - help: use a mutable reference instead: `n` LL | *n += 1; //~ ERROR cannot assign to immutable | ^^^^^^^ cannot borrow as mutable From 1ed861910f1a875c7bf19ee398cad1570b92aad4 Mon Sep 17 00:00:00 2001 From: ashtneoi Date: Thu, 12 Jul 2018 23:11:57 -0700 Subject: [PATCH 16/16] Bless one more test --- src/test/ui/suggestions/issue-51244.nll.stderr | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/test/ui/suggestions/issue-51244.nll.stderr diff --git a/src/test/ui/suggestions/issue-51244.nll.stderr b/src/test/ui/suggestions/issue-51244.nll.stderr new file mode 100644 index 0000000000000..ce02ae2aec23f --- /dev/null +++ b/src/test/ui/suggestions/issue-51244.nll.stderr @@ -0,0 +1,11 @@ +error[E0594]: cannot assign to `*my_ref` which is behind a `&` reference + --> $DIR/issue-51244.rs:13:5 + | +LL | let ref my_ref @ _ = 0; + | -------------- help: consider changing this to be a mutable reference: `ref mut my_ref @ _` +LL | *my_ref = 0; //~ ERROR cannot assign to immutable borrowed content `*my_ref` [E0594] + | ^^^^^^^^^^^ `my_ref` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`.