From 67a24c2e184b8c7f515d52225b8f67f94abe6ff2 Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Tue, 8 Nov 2016 09:21:53 +0300 Subject: [PATCH] add hint to fix error for immutable ref in arg --- src/librustc_borrowck/borrowck/mod.rs | 129 +++++++++++------- ...rrowck-borrow-overloaded-auto-deref-mut.rs | 0 ...ck-borrow-overloaded-auto-deref-mut.stderr | 86 ++++++++++++ .../borrowck-borrow-overloaded-deref-mut.rs | 0 ...orrowck-borrow-overloaded-deref-mut.stderr | 34 +++++ .../borrowck-call-is-borrow-issue-12224.rs | 0 ...borrowck-call-is-borrow-issue-12224.stderr | 43 ++++++ ...borrowck-call-method-from-mut-aliasable.rs | 0 ...owck-call-method-from-mut-aliasable.stderr | 11 ++ .../span}/borrowck-fn-in-const-b.rs | 0 .../ui/span/borrowck-fn-in-const-b.stderr | 10 ++ .../span}/borrowck-object-mutability.rs | 0 .../ui/span/borrowck-object-mutability.stderr | 17 +++ src/test/ui/span/mut-arg-hint.rs | 32 +++++ src/test/ui/span/mut-arg-hint.stderr | 26 ++++ 15 files changed, 342 insertions(+), 46 deletions(-) rename src/test/{compile-fail/borrowck => ui/span}/borrowck-borrow-overloaded-auto-deref-mut.rs (100%) create mode 100644 src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr rename src/test/{compile-fail/borrowck => ui/span}/borrowck-borrow-overloaded-deref-mut.rs (100%) create mode 100644 src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr rename src/test/{compile-fail/borrowck => ui/span}/borrowck-call-is-borrow-issue-12224.rs (100%) create mode 100644 src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr rename src/test/{compile-fail/borrowck => ui/span}/borrowck-call-method-from-mut-aliasable.rs (100%) create mode 100644 src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr rename src/test/{compile-fail/borrowck => ui/span}/borrowck-fn-in-const-b.rs (100%) create mode 100644 src/test/ui/span/borrowck-fn-in-const-b.stderr rename src/test/{compile-fail/borrowck => ui/span}/borrowck-object-mutability.rs (100%) create mode 100644 src/test/ui/span/borrowck-object-mutability.stderr create mode 100644 src/test/ui/span/mut-arg-hint.rs create mode 100644 src/test/ui/span/mut-arg-hint.stderr diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 5e54e333bb90c..0c52aacdbdb14 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -24,7 +24,7 @@ use self::InteriorKind::*; use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; -use rustc::hir::map::blocks::FnParts; +use rustc::hir::map::blocks::{FnParts, FnLikeNode}; use rustc::cfg; use rustc::middle::dataflow::DataFlowContext; use rustc::middle::dataflow::BitwiseOperator; @@ -970,51 +970,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>, error_span: Span) { - let code = err.code; - match code { - err_mutbl => { - match err.cmt.note { - mc::NoteClosureEnv(upvar_id) | mc::NoteUpvarRef(upvar_id) => { - // If this is an `Fn` closure, it simply can't mutate upvars. - // If it's an `FnMut` closure, the original variable was declared immutable. - // We need to determine which is the case here. - let kind = match err.cmt.upvar().unwrap().cat { - Categorization::Upvar(mc::Upvar { kind, .. }) => kind, - _ => bug!() - }; - if kind == ty::ClosureKind::Fn { - db.span_help( - self.tcx.map.span(upvar_id.closure_expr_id), - "consider changing this closure to take \ - self by mutable reference"); - } - } - _ => { - if let Categorization::Local(local_id) = err.cmt.cat { - let span = self.tcx.map.span(local_id); - if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { - if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") { - db.span_label(error_span, &format!("cannot reborrow mutably")); - db.span_label(error_span, &format!("try removing `&mut` here")); - } else { - if snippet.starts_with("ref ") { - db.span_label(span, - &format!("use `{}` here to make mutable", - snippet.replace("ref ", "ref mut "))); - } else if snippet != "self" { - db.span_label(span, - &format!("use `mut {}` here to make mutable", snippet)); - } - db.span_label(error_span, &format!("cannot borrow mutably")); - } - } else { - db.span_label(error_span, &format!("cannot borrow mutably")); - } - } - } - } - } - + match err.code { + err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span), err_out_of_scope(super_scope, sub_scope, cause) => { let (value_kind, value_msg) = match err.cmt.cat { mc::Categorization::Rvalue(_) => @@ -1135,6 +1092,86 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } + fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder, err: &BckError<'tcx>, + error_span: &Span) { + match err.cmt.note { + mc::NoteClosureEnv(upvar_id) | mc::NoteUpvarRef(upvar_id) => { + // If this is an `Fn` closure, it simply can't mutate upvars. + // If it's an `FnMut` closure, the original variable was declared immutable. + // We need to determine which is the case here. + let kind = match err.cmt.upvar().unwrap().cat { + Categorization::Upvar(mc::Upvar { kind, .. }) => kind, + _ => bug!() + }; + if kind == ty::ClosureKind::Fn { + db.span_help(self.tcx.map.span(upvar_id.closure_expr_id), + "consider changing this closure to take \ + self by mutable reference"); + } + } + _ => { + if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat { + if let Categorization::Local(local_id) = inner_cmt.cat { + let parent = self.tcx.map.get_parent_node(local_id); + let opt_fn_decl = FnLikeNode::from_node(self.tcx.map.get(parent)) + .map(|fn_like| fn_like.decl()); + + if let Some(fn_decl) = opt_fn_decl { + if let Some(ref arg) = fn_decl.inputs.iter() + .find(|ref arg| arg.pat.id == local_id) { + if let hir::TyRptr( + opt_lifetime, + hir::MutTy{mutbl: hir::Mutability::MutImmutable, ref ty}) = + arg.ty.node { + if let Some(lifetime) = opt_lifetime { + if let Ok(snippet) = self.tcx.sess.codemap() + .span_to_snippet(ty.span) { + if let Ok(lifetime_snippet) = self.tcx.sess.codemap() + .span_to_snippet(lifetime.span) { + db.span_label(arg.ty.span, + &format!("use `&{} mut {}` \ + here to make mutable", + lifetime_snippet, + snippet)); + } + } + } + else if let Ok(snippet) = self.tcx.sess.codemap() + .span_to_snippet(arg.ty.span) { + if snippet.starts_with("&") { + db.span_label(arg.ty.span, + &format!("use `{}` here to make mutable", + snippet.replace("&", "&mut "))); + } + } + } + } + } + } + } else if let Categorization::Local(local_id) = err.cmt.cat { + let span = self.tcx.map.span(local_id); + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { + if snippet.starts_with("ref mut ") || snippet.starts_with("&mut ") { + db.span_label(*error_span, &format!("cannot reborrow mutably")); + db.span_label(*error_span, &format!("try removing `&mut` here")); + } else { + if snippet.starts_with("ref ") { + db.span_label(span, &format!("use `{}` here to make mutable", + snippet.replace("ref ", "ref mut "))); + } else if snippet != "self" { + db.span_label(span, + &format!("use `mut {}` here to make mutable", + snippet)); + } + db.span_label(*error_span, &format!("cannot borrow mutably")); + } + } else { + db.span_label(*error_span, &format!("cannot borrow mutably")); + } + } + } + } + } pub fn append_loan_path_to_string(&self, loan_path: &LoanPath<'tcx>, out: &mut String) { diff --git a/src/test/compile-fail/borrowck/borrowck-borrow-overloaded-auto-deref-mut.rs b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.rs similarity index 100% rename from src/test/compile-fail/borrowck/borrowck-borrow-overloaded-auto-deref-mut.rs rename to src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.rs diff --git a/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr new file mode 100644 index 0000000000000..1109351bff839 --- /dev/null +++ b/src/test/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr @@ -0,0 +1,86 @@ +error: cannot borrow immutable argument `x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:63:24 + | +62 | fn deref_mut_field1(x: Own) { + | - use `mut x` here to make mutable +63 | let __isize = &mut x.y; //~ ERROR cannot borrow + | ^ cannot borrow mutably + +error: cannot borrow immutable borrowed content `*x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:75:10 + | +74 | fn deref_extend_mut_field1(x: &Own) -> &mut isize { + | ----------- use `&mut Own` here to make mutable +75 | &mut x.y //~ ERROR cannot borrow + | ^ + +error[E0499]: cannot borrow `*x` as mutable more than once at a time + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:88:19 + | +87 | let _x = &mut x.x; + | - first mutable borrow occurs here +88 | let _y = &mut x.y; //~ ERROR cannot borrow + | ^ second mutable borrow occurs here +89 | } + | - first borrow ends here + +error: cannot borrow immutable argument `x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:98:5 + | +97 | fn assign_field1<'a>(x: Own) { + | - use `mut x` here to make mutable +98 | x.y = 3; //~ ERROR cannot borrow + | ^ cannot borrow mutably + +error: cannot borrow immutable borrowed content `*x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:102:5 + | +101 | fn assign_field2<'a>(x: &'a Own) { + | -------------- use `&'a mut Own` here to make mutable +102 | x.y = 3; //~ ERROR cannot borrow + | ^ + +error[E0499]: cannot borrow `*x` as mutable more than once at a time + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:111:5 + | +110 | let _p: &mut Point = &mut **x; + | -- first mutable borrow occurs here +111 | x.y = 3; //~ ERROR cannot borrow + | ^ second mutable borrow occurs here +112 | } + | - first borrow ends here + +error: cannot borrow immutable argument `x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:119:5 + | +118 | fn deref_mut_method1(x: Own) { + | - use `mut x` here to make mutable +119 | x.set(0, 0); //~ ERROR cannot borrow + | ^ cannot borrow mutably + +error: cannot borrow immutable borrowed content `*x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:131:5 + | +130 | fn deref_extend_mut_method1(x: &Own) -> &mut isize { + | ----------- use `&mut Own` here to make mutable +131 | x.y_mut() //~ ERROR cannot borrow + | ^ + +error: cannot borrow immutable argument `x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6 + | +138 | fn assign_method1<'a>(x: Own) { + | - use `mut x` here to make mutable +139 | *x.y_mut() = 3; //~ ERROR cannot borrow + | ^ cannot borrow mutably + +error: cannot borrow immutable borrowed content `*x` as mutable + --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:143:6 + | +142 | fn assign_method2<'a>(x: &'a Own) { + | -------------- use `&'a mut Own` here to make mutable +143 | *x.y_mut() = 3; //~ ERROR cannot borrow + | ^ + +error: aborting due to 10 previous errors + diff --git a/src/test/compile-fail/borrowck/borrowck-borrow-overloaded-deref-mut.rs b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.rs similarity index 100% rename from src/test/compile-fail/borrowck/borrowck-borrow-overloaded-deref-mut.rs rename to src/test/ui/span/borrowck-borrow-overloaded-deref-mut.rs diff --git a/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr new file mode 100644 index 0000000000000..a5b7045916141 --- /dev/null +++ b/src/test/ui/span/borrowck-borrow-overloaded-deref-mut.stderr @@ -0,0 +1,34 @@ +error: cannot borrow immutable argument `x` as mutable + --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:39:25 + | +38 | fn deref_mut1(x: Own) { + | - use `mut x` here to make mutable +39 | let __isize = &mut *x; //~ ERROR cannot borrow + | ^ cannot borrow mutably + +error: cannot borrow immutable borrowed content `*x` as mutable + --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:51:11 + | +50 | fn deref_extend_mut1<'a>(x: &'a Own) -> &'a mut isize { + | -------------- use `&'a mut Own` here to make mutable +51 | &mut **x //~ ERROR cannot borrow + | ^^ + +error: cannot borrow immutable argument `x` as mutable + --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6 + | +58 | fn assign1<'a>(x: Own) { + | - use `mut x` here to make mutable +59 | *x = 3; //~ ERROR cannot borrow + | ^ cannot borrow mutably + +error: cannot borrow immutable borrowed content `*x` as mutable + --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:63:6 + | +62 | fn assign2<'a>(x: &'a Own) { + | -------------- use `&'a mut Own` here to make mutable +63 | **x = 3; //~ ERROR cannot borrow + | ^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs similarity index 100% rename from src/test/compile-fail/borrowck/borrowck-call-is-borrow-issue-12224.rs rename to src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr new file mode 100644 index 0000000000000..16bb60013674f --- /dev/null +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -0,0 +1,43 @@ +error[E0499]: cannot borrow `f` as mutable more than once at a time + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:23:16 + | +23 | f(Box::new(|| { + | - ^^ second mutable borrow occurs here + | | + | first mutable borrow occurs here +24 | //~^ ERROR: cannot borrow `f` as mutable more than once +25 | f((Box::new(|| {}))) + | - borrow occurs due to use of `f` in closure +26 | })); + | - first borrow ends here + +error: cannot borrow immutable borrowed content `*f` as mutable + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:36:5 + | +35 | fn test2(f: &F) where F: FnMut() { + | -- use `&mut F` here to make mutable +36 | (*f)(); //~ ERROR: cannot borrow immutable borrowed content `*f` as mutable + | ^^^^ + +error: cannot borrow immutable `Box` content `*f.f` as mutable + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:44:5 + | +44 | f.f.call_mut(()) //~ ERROR: cannot borrow immutable `Box` content `*f.f` as mutable + | ^^^ + +error[E0504]: cannot move `f` into closure because it is borrowed + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13 + | +62 | f(Box::new(|a| { + | - borrow of `f` occurs here +63 | foo(f); + | ^ move into closure occurs here + +error[E0507]: cannot move out of captured outer variable in an `FnMut` closure + --> $DIR/borrowck-call-is-borrow-issue-12224.rs:63:13 + | +63 | foo(f); + | ^ cannot move out of captured outer variable in an `FnMut` closure + +error: aborting due to 5 previous errors + diff --git a/src/test/compile-fail/borrowck/borrowck-call-method-from-mut-aliasable.rs b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.rs similarity index 100% rename from src/test/compile-fail/borrowck/borrowck-call-method-from-mut-aliasable.rs rename to src/test/ui/span/borrowck-call-method-from-mut-aliasable.rs diff --git a/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr new file mode 100644 index 0000000000000..a1af1ca7408a2 --- /dev/null +++ b/src/test/ui/span/borrowck-call-method-from-mut-aliasable.stderr @@ -0,0 +1,11 @@ +error: cannot borrow immutable borrowed content `*x` as mutable + --> $DIR/borrowck-call-method-from-mut-aliasable.rs:27:5 + | +25 | fn b(x: &Foo) { + | ---- use `&mut Foo` here to make mutable +26 | x.f(); +27 | x.h(); //~ ERROR cannot borrow + | ^ + +error: aborting due to previous error + diff --git a/src/test/compile-fail/borrowck/borrowck-fn-in-const-b.rs b/src/test/ui/span/borrowck-fn-in-const-b.rs similarity index 100% rename from src/test/compile-fail/borrowck/borrowck-fn-in-const-b.rs rename to src/test/ui/span/borrowck-fn-in-const-b.rs diff --git a/src/test/ui/span/borrowck-fn-in-const-b.stderr b/src/test/ui/span/borrowck-fn-in-const-b.stderr new file mode 100644 index 0000000000000..41f549c708a29 --- /dev/null +++ b/src/test/ui/span/borrowck-fn-in-const-b.stderr @@ -0,0 +1,10 @@ +error: cannot borrow immutable borrowed content `*x` as mutable + --> $DIR/borrowck-fn-in-const-b.rs:17:9 + | +16 | fn broken(x: &Vec) { + | ------------ use `&mut Vec` here to make mutable +17 | x.push(format!("this is broken")); + | ^ + +error: aborting due to previous error + diff --git a/src/test/compile-fail/borrowck/borrowck-object-mutability.rs b/src/test/ui/span/borrowck-object-mutability.rs similarity index 100% rename from src/test/compile-fail/borrowck/borrowck-object-mutability.rs rename to src/test/ui/span/borrowck-object-mutability.rs diff --git a/src/test/ui/span/borrowck-object-mutability.stderr b/src/test/ui/span/borrowck-object-mutability.stderr new file mode 100644 index 0000000000000..32e4da18056ff --- /dev/null +++ b/src/test/ui/span/borrowck-object-mutability.stderr @@ -0,0 +1,17 @@ +error: cannot borrow immutable borrowed content `*x` as mutable + --> $DIR/borrowck-object-mutability.rs:19:5 + | +17 | fn borrowed_receiver(x: &Foo) { + | ---- use `&mut Foo` here to make mutable +18 | x.borrowed(); +19 | x.borrowed_mut(); //~ ERROR cannot borrow + | ^ + +error: cannot borrow immutable `Box` content `*x` as mutable + --> $DIR/borrowck-object-mutability.rs:29:5 + | +29 | x.borrowed_mut(); //~ ERROR cannot borrow + | ^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/span/mut-arg-hint.rs b/src/test/ui/span/mut-arg-hint.rs new file mode 100644 index 0000000000000..296ee6ca10e05 --- /dev/null +++ b/src/test/ui/span/mut-arg-hint.rs @@ -0,0 +1,32 @@ +// Copyright 2015 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. + +trait B { + fn foo(mut a: &String) { + a.push_str("bar"); + } +} + +pub fn foo<'a>(mut a: &'a String) { + a.push_str("foo"); +} + +struct A {} + +impl A { + pub fn foo(mut a: &String) { + a.push_str("foo"); + } +} + +fn main() { + foo(&"a".to_string()); + A::foo(&"a".to_string()); +} diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr new file mode 100644 index 0000000000000..5e9a0b915031e --- /dev/null +++ b/src/test/ui/span/mut-arg-hint.stderr @@ -0,0 +1,26 @@ +error: cannot borrow immutable borrowed content `*a` as mutable + --> $DIR/mut-arg-hint.rs:13:9 + | +12 | fn foo(mut a: &String) { + | ------- use `&mut String` here to make mutable +13 | a.push_str("bar"); + | ^ + +error: cannot borrow immutable borrowed content `*a` as mutable + --> $DIR/mut-arg-hint.rs:18:5 + | +17 | pub fn foo<'a>(mut a: &'a String) { + | ---------- use `&'a mut String` here to make mutable +18 | a.push_str("foo"); + | ^ + +error: cannot borrow immutable borrowed content `*a` as mutable + --> $DIR/mut-arg-hint.rs:25:9 + | +24 | pub fn foo(mut a: &String) { + | ------- use `&mut String` here to make mutable +25 | a.push_str("foo"); + | ^ + +error: aborting due to 3 previous errors +