about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAndy Russell <arussell123@gmail.com>2019-01-02 17:01:03 -0500
committerAndy Russell <arussell123@gmail.com>2019-01-03 13:42:52 -0500
commite3fe0ee97b95abd13e257fa92c70248c0746165c (patch)
tree62123e7745fe7bdb6fe6a63251ffd9156a9332f0
parentcae164753f557f668cb75610abda4f790981e5e6 (diff)
downloadrust-e3fe0ee97b95abd13e257fa92c70248c0746165c.tar.gz
rust-e3fe0ee97b95abd13e257fa92c70248c0746165c.zip
use structured suggestion for method calls
Furthermore, don't suggest calling the method if it is part of a place
expression, as this is invalid syntax.
-rw-r--r--src/librustc_typeck/check/method/mod.rs37
-rw-r--r--src/librustc_typeck/check/mod.rs52
-rw-r--r--src/test/ui/assign-to-method.rs1
-rw-r--r--src/test/ui/assign-to-method.stderr12
-rw-r--r--src/test/ui/did_you_mean/issue-40396.stderr8
-rw-r--r--src/test/ui/error-codes/E0615.stderr4
-rw-r--r--src/test/ui/implicit-method-bind.stderr4
-rw-r--r--src/test/ui/issues/issue-13853-2.stderr4
-rw-r--r--src/test/ui/issues/issue-26472.rs4
-rw-r--r--src/test/ui/issues/issue-26472.stderr14
-rw-r--r--src/test/ui/methods/method-missing-call.stderr8
-rw-r--r--src/test/ui/union/union-suggest-field.rs3
-rw-r--r--src/test/ui/union/union-suggest-field.stderr4
13 files changed, 116 insertions, 39 deletions
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 1758f762524..02687df6a94 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -11,6 +11,7 @@ pub use self::CandidateSource::*;
 pub use self::suggest::{SelfSource, TraitInfo};
 
 use check::FnCtxt;
+use errors::{Applicability, DiagnosticBuilder};
 use namespace::Namespace;
 use rustc_data_structures::sync::Lrc;
 use rustc::hir;
@@ -123,6 +124,42 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    /// Add a suggestion to call the given method to the provided diagnostic.
+    crate fn suggest_method_call(
+        &self,
+        err: &mut DiagnosticBuilder<'a>,
+        msg: &str,
+        method_name: ast::Ident,
+        self_ty: Ty<'tcx>,
+        call_expr_id: ast::NodeId,
+    ) {
+        let has_params = self
+            .probe_for_name(
+                method_name.span,
+                probe::Mode::MethodCall,
+                method_name,
+                IsSuggestion(false),
+                self_ty,
+                call_expr_id,
+                ProbeScope::TraitsInScope,
+            )
+            .and_then(|pick| {
+                let sig = self.tcx.fn_sig(pick.item.def_id);
+                Ok(sig.inputs().skip_binder().len() > 1)
+            });
+
+        let (suggestion, applicability) = if has_params.unwrap_or_default() {
+            (
+                format!("{}(...)", method_name),
+                Applicability::HasPlaceholders,
+            )
+        } else {
+            (format!("{}()", method_name), Applicability::MaybeIncorrect)
+        };
+
+        err.span_suggestion_with_applicability(method_name.span, msg, suggestion, applicability);
+    }
+
     /// Performs method lookup. If lookup is successful, it will return the callee
     /// and store an appropriate adjustment for the self-expr. In some cases it may
     /// report an error (e.g., invoking the `drop` method).
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index d78d7273a36..781f4eae426 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3412,19 +3412,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                            "field `{}` of struct `{}` is private",
                                            field, struct_path);
             // Also check if an accessible method exists, which is often what is meant.
-            if self.method_exists(field, expr_t, expr.id, false) {
-                err.note(&format!("a method `{}` also exists, perhaps you wish to call it", field));
+            if self.method_exists(field, expr_t, expr.id, false) && !self.expr_in_place(expr.id) {
+                self.suggest_method_call(
+                    &mut err,
+                    &format!("a method `{}` also exists, call it with parentheses", field),
+                    field,
+                    expr_t,
+                    expr.id,
+                );
             }
             err.emit();
             field_ty
         } else if field.name == keywords::Invalid.name() {
             self.tcx().types.err
         } else if self.method_exists(field, expr_t, expr.id, true) {
-            type_error_struct!(self.tcx().sess, field.span, expr_t, E0615,
+            let mut err = type_error_struct!(self.tcx().sess, field.span, expr_t, E0615,
                                "attempted to take value of method `{}` on type `{}`",
-                               field, expr_t)
-                .help("maybe a `()` to call it is missing?")
-                .emit();
+                               field, expr_t);
+
+            if !self.expr_in_place(expr.id) {
+                self.suggest_method_call(
+                    &mut err,
+                    "use parentheses to call the method",
+                    field,
+                    expr_t,
+                    expr.id
+                );
+            } else {
+                err.help("methods are immutable and cannot be assigned to");
+            }
+
+            err.emit();
             self.tcx().types.err
         } else {
             if !expr_t.is_primitive_ty() {
@@ -5435,6 +5453,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             original_values,
             query_result)
     }
+
+    /// Returns whether an expression is contained inside the LHS of an assignment expression.
+    fn expr_in_place(&self, mut expr_id: ast::NodeId) -> bool {
+        let mut contained_in_place = false;
+
+        while let hir::Node::Expr(parent_expr) =
+            self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id))
+        {
+            match &parent_expr.node {
+                hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => {
+                    if lhs.id == expr_id {
+                        contained_in_place = true;
+                        break;
+                    }
+                }
+                _ => (),
+            }
+            expr_id = parent_expr.id;
+        }
+
+        contained_in_place
+    }
 }
 
 pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
diff --git a/src/test/ui/assign-to-method.rs b/src/test/ui/assign-to-method.rs
index a7f3ab6d80d..95f066c382c 100644
--- a/src/test/ui/assign-to-method.rs
+++ b/src/test/ui/assign-to-method.rs
@@ -18,4 +18,5 @@ fn cat(in_x : usize, in_y : isize) -> Cat {
 fn main() {
   let nyan : Cat = cat(52, 99);
   nyan.speak = || println!("meow"); //~ ERROR attempted to take value of method
+  nyan.speak += || println!("meow"); //~ ERROR attempted to take value of method
 }
diff --git a/src/test/ui/assign-to-method.stderr b/src/test/ui/assign-to-method.stderr
index a08ac192a22..f79f0750d89 100644
--- a/src/test/ui/assign-to-method.stderr
+++ b/src/test/ui/assign-to-method.stderr
@@ -4,8 +4,16 @@ error[E0615]: attempted to take value of method `speak` on type `Cat`
 LL |   nyan.speak = || println!("meow"); //~ ERROR attempted to take value of method
    |        ^^^^^
    |
-   = help: maybe a `()` to call it is missing?
+   = help: methods are immutable and cannot be assigned to
 
-error: aborting due to previous error
+error[E0615]: attempted to take value of method `speak` on type `Cat`
+  --> $DIR/assign-to-method.rs:21:8
+   |
+LL |   nyan.speak += || println!("meow"); //~ ERROR attempted to take value of method
+   |        ^^^^^
+   |
+   = help: methods are immutable and cannot be assigned to
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0615`.
diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr
index 3f6886bc3f6..86bbf2bf27a 100644
--- a/src/test/ui/did_you_mean/issue-40396.stderr
+++ b/src/test/ui/did_you_mean/issue-40396.stderr
@@ -80,17 +80,13 @@ error[E0615]: attempted to take value of method `collect` on type `std::ops::Ran
   --> $DIR/issue-40396.rs:2:13
    |
 LL |     (0..13).collect<Vec<i32>>();
-   |             ^^^^^^^
-   |
-   = help: maybe a `()` to call it is missing?
+   |             ^^^^^^^ help: use parentheses to call the method: `collect()`
 
 error[E0615]: attempted to take value of method `collect` on type `std::ops::Range<{integer}>`
   --> $DIR/issue-40396.rs:18:13
    |
 LL |     (0..13).collect<Vec<i32>();
-   |             ^^^^^^^
-   |
-   = help: maybe a `()` to call it is missing?
+   |             ^^^^^^^ help: use parentheses to call the method: `collect()`
 
 error[E0308]: mismatched types
   --> $DIR/issue-40396.rs:18:29
diff --git a/src/test/ui/error-codes/E0615.stderr b/src/test/ui/error-codes/E0615.stderr
index 423948666db..d86ee5b9b4b 100644
--- a/src/test/ui/error-codes/E0615.stderr
+++ b/src/test/ui/error-codes/E0615.stderr
@@ -2,9 +2,7 @@ error[E0615]: attempted to take value of method `method` on type `Foo`
   --> $DIR/E0615.rs:11:7
    |
 LL |     f.method; //~ ERROR E0615
-   |       ^^^^^^
-   |
-   = help: maybe a `()` to call it is missing?
+   |       ^^^^^^ help: use parentheses to call the method: `method()`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/implicit-method-bind.stderr b/src/test/ui/implicit-method-bind.stderr
index 6f0ed4c5b58..7c70709c6b9 100644
--- a/src/test/ui/implicit-method-bind.stderr
+++ b/src/test/ui/implicit-method-bind.stderr
@@ -2,9 +2,7 @@ error[E0615]: attempted to take value of method `abs` on type `i32`
   --> $DIR/implicit-method-bind.rs:2:20
    |
 LL |     let _f = 10i32.abs; //~ ERROR attempted to take value of method
-   |                    ^^^
-   |
-   = help: maybe a `()` to call it is missing?
+   |                    ^^^ help: use parentheses to call the method: `abs()`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-13853-2.stderr b/src/test/ui/issues/issue-13853-2.stderr
index 522042d3a65..3e711243b4e 100644
--- a/src/test/ui/issues/issue-13853-2.stderr
+++ b/src/test/ui/issues/issue-13853-2.stderr
@@ -2,9 +2,7 @@ error[E0615]: attempted to take value of method `get` on type `std::boxed::Box<(
   --> $DIR/issue-13853-2.rs:5:39
    |
 LL | fn foo(res : Box<ResponseHook>) { res.get } //~ ERROR attempted to take value of method
-   |                                       ^^^
-   |
-   = help: maybe a `()` to call it is missing?
+   |                                       ^^^ help: use parentheses to call the method: `get()`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-26472.rs b/src/test/ui/issues/issue-26472.rs
index 4659c0d6902..4eb38d10a70 100644
--- a/src/test/ui/issues/issue-26472.rs
+++ b/src/test/ui/issues/issue-26472.rs
@@ -8,6 +8,6 @@ mod sub {
 
 fn main() {
     let s = sub::S::new();
-    let v = s.len;
-    //~^ ERROR field `len` of struct `sub::S` is private
+    let v = s.len; //~ ERROR field `len` of struct `sub::S` is private
+    s.len = v; //~ ERROR field `len` of struct `sub::S` is private
 }
diff --git a/src/test/ui/issues/issue-26472.stderr b/src/test/ui/issues/issue-26472.stderr
index dd7941e9a6e..8c261d2a3f3 100644
--- a/src/test/ui/issues/issue-26472.stderr
+++ b/src/test/ui/issues/issue-26472.stderr
@@ -1,11 +1,17 @@
 error[E0616]: field `len` of struct `sub::S` is private
   --> $DIR/issue-26472.rs:11:13
    |
-LL |     let v = s.len;
-   |             ^^^^^
+LL |     let v = s.len; //~ ERROR field `len` of struct `sub::S` is private
+   |             ^^---
+   |               |
+   |               help: a method `len` also exists, call it with parentheses: `len()`
+
+error[E0616]: field `len` of struct `sub::S` is private
+  --> $DIR/issue-26472.rs:12:5
    |
-   = note: a method `len` also exists, perhaps you wish to call it
+LL |     s.len = v; //~ ERROR field `len` of struct `sub::S` is private
+   |     ^^^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0616`.
diff --git a/src/test/ui/methods/method-missing-call.stderr b/src/test/ui/methods/method-missing-call.stderr
index 22c907ed002..886d92aa925 100644
--- a/src/test/ui/methods/method-missing-call.stderr
+++ b/src/test/ui/methods/method-missing-call.stderr
@@ -2,17 +2,13 @@ error[E0615]: attempted to take value of method `get_x` on type `Point`
   --> $DIR/method-missing-call.rs:22:26
    |
 LL |                         .get_x;//~ ERROR attempted to take value of method `get_x` on type `Point`
-   |                          ^^^^^
-   |
-   = help: maybe a `()` to call it is missing?
+   |                          ^^^^^ help: use parentheses to call the method: `get_x()`
 
 error[E0615]: attempted to take value of method `filter_map` on type `std::iter::Filter<std::iter::Map<std::slice::Iter<'_, {integer}>, [closure@$DIR/method-missing-call.rs:27:20: 27:25]>, [closure@$DIR/method-missing-call.rs:28:23: 28:35]>`
   --> $DIR/method-missing-call.rs:29:16
    |
 LL |               .filter_map; //~ ERROR attempted to take value of method `filter_map` on type
-   |                ^^^^^^^^^^
-   |
-   = help: maybe a `()` to call it is missing?
+   |                ^^^^^^^^^^ help: use parentheses to call the method: `filter_map(...)`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/union/union-suggest-field.rs b/src/test/ui/union/union-suggest-field.rs
index b2d8c0efea8..d84a22cee5a 100644
--- a/src/test/ui/union/union-suggest-field.rs
+++ b/src/test/ui/union/union-suggest-field.rs
@@ -16,5 +16,6 @@ fn main() {
                           //~| SUGGESTION principal
 
     let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U`
-                         //~| HELP maybe a `()` to call it is missing
+                         //~| HELP use parentheses to call the method
+                         //~| SUGGESTION calculate()
 }
diff --git a/src/test/ui/union/union-suggest-field.stderr b/src/test/ui/union/union-suggest-field.stderr
index 91d6b30ea02..8ea07360d0f 100644
--- a/src/test/ui/union/union-suggest-field.stderr
+++ b/src/test/ui/union/union-suggest-field.stderr
@@ -14,9 +14,7 @@ error[E0615]: attempted to take value of method `calculate` on type `U`
   --> $DIR/union-suggest-field.rs:18:15
    |
 LL |     let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U`
-   |               ^^^^^^^^^
-   |
-   = help: maybe a `()` to call it is missing?
+   |               ^^^^^^^^^ help: use parentheses to call the method: `calculate()`
 
 error: aborting due to 3 previous errors