about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-01-18 04:45:25 +0000
committerbors <bors@rust-lang.org>2017-01-18 04:45:25 +0000
commitc8af93f0901c336e873ce18274026d0fd9bc7c1f (patch)
treef2a4fd67379bc004f4b2bcbf78d33f68b96d836a
parentbe1daa4a18b6685f42194ea1407f8d5def10b342 (diff)
parentf595ea25841eab1139ca10c5fe0349e51cc2b6c5 (diff)
downloadrust-c8af93f0901c336e873ce18274026d0fd9bc7c1f.tar.gz
rust-c8af93f0901c336e873ce18274026d0fd9bc7c1f.zip
Auto merge of #38168 - estebank:help-E0034, r=nrc
E0034: provide disambiguated syntax for candidates

For a given file

```rust
trait A { fn foo(&self) {} }
trait B : A { fn foo(&self) {} }

fn bar<T: B>(a: &T) {
  a.foo()
}
```

provide the following output

```
error[E0034]: multiple applicable items in scope
 --> file.rs:6:5
  |
6 |   a.foo(1)
  |     ^^^ multiple `foo` found
  |
note: candidate #1 is defined in the trait `A`
 --> file.rs:2:11
  |
2 | trait A { fn foo(&self, a: usize) {} }
  |           ^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to use it here write `A::foo(&a, 1)` instead
 --> file.rs:6:5
  |
6 |   a.foo(1)
  |     ^^^
note: candidate #2 is defined in the trait `B`
 --> file.rs:3:15
  |
3 | trait B : A { fn foo(&self, a: usize) {} }
  |               ^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to use it here write `B::foo(&a, 1)` instead
 --> file.rs:6:5
  |
6 |   a.foo(1)
  |     ^^^
```

Fix #37767.
-rw-r--r--src/librustc/ty/sty.rs11
-rw-r--r--src/librustc_typeck/check/method/suggest.rs22
-rw-r--r--src/librustc_typeck/check/mod.rs10
-rw-r--r--src/test/ui/span/issue-37767.rs51
-rw-r--r--src/test/ui/span/issue-37767.stderr59
-rw-r--r--src/test/ui/span/issue-7575.rs (renamed from src/test/compile-fail/issue-7575.rs)12
-rw-r--r--src/test/ui/span/issue-7575.stderr67
7 files changed, 224 insertions, 8 deletions
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 81b0a55841a..b02bb7c6e4d 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -1121,6 +1121,17 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
         }
     }
 
+    pub fn is_mutable_pointer(&self) -> bool {
+        match self.sty {
+            TyRawPtr(tnm) | TyRef(_, tnm) => if let hir::Mutability::MutMutable = tnm.mutbl {
+                true
+            } else {
+                false
+            },
+            _ => false
+        }
+    }
+
     pub fn is_unsafe_ptr(&self) -> bool {
         match self.sty {
             TyRawPtr(_) => return true,
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 04ec9292d14..b1705425e6e 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -27,6 +27,7 @@ use errors::DiagnosticBuilder;
 use syntax_pos::Span;
 
 use rustc::hir;
+use rustc::hir::print;
 use rustc::infer::type_variable::TypeVariableOrigin;
 
 use std::cell;
@@ -71,7 +72,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                rcvr_ty: Ty<'tcx>,
                                item_name: ast::Name,
                                rcvr_expr: Option<&hir::Expr>,
-                               error: MethodError<'tcx>) {
+                               error: MethodError<'tcx>,
+                               args: Option<&'gcx [hir::Expr]>) {
         // avoid suggestions when we don't know what's going on.
         if rcvr_ty.references_error() {
             return;
@@ -131,6 +133,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                    "candidate #{} is defined in the trait `{}`",
                                    idx + 1,
                                    self.tcx.item_path_str(trait_did));
+                        err.help(&format!("to disambiguate the method call, write `{}::{}({}{})` \
+                                          instead",
+                                          self.tcx.item_path_str(trait_did),
+                                          item_name,
+                                          if rcvr_ty.is_region_ptr() && args.is_some() {
+                                              if rcvr_ty.is_mutable_pointer() {
+                                                  "&mut "
+                                              } else {
+                                                  "&"
+                                              }
+                                          } else {
+                                              ""
+                                          },
+                                          args.map(|arg| arg.iter()
+                                              .map(|arg| print::to_string(print::NO_ANN,
+                                                                          |s| s.print_expr(arg)))
+                                              .collect::<Vec<_>>()
+                                              .join(", ")).unwrap_or("...".to_owned())));
                     }
                 }
             }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 0b316c5d375..e240c70aaa3 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2867,8 +2867,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             Err(error) => {
                 if method_name.node != keywords::Invalid.name() {
-                    self.report_method_error(method_name.span, expr_t,
-                                             method_name.node, Some(rcvr), error);
+                    self.report_method_error(method_name.span,
+                                             expr_t,
+                                             method_name.node,
+                                             Some(rcvr),
+                                             error,
+                                             Some(args));
                 }
                 self.write_error(expr.id);
                 self.tcx.types.err
@@ -4051,7 +4055,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     _ => Def::Err,
                 };
                 if item_name != keywords::Invalid.name() {
-                    self.report_method_error(span, ty, item_name, None, error);
+                    self.report_method_error(span, ty, item_name, None, error, None);
                 }
                 def
             }
diff --git a/src/test/ui/span/issue-37767.rs b/src/test/ui/span/issue-37767.rs
new file mode 100644
index 00000000000..49ad40259d9
--- /dev/null
+++ b/src/test/ui/span/issue-37767.rs
@@ -0,0 +1,51 @@
+// Copyright 2016 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait A {
+    fn foo(&mut self) {}
+}
+
+trait B : A {
+    fn foo(&mut self) {}
+}
+
+fn bar<T: B>(a: &T) {
+    a.foo()
+}
+
+trait C {
+    fn foo(&self) {}
+}
+
+trait D : C {
+    fn foo(&self) {}
+}
+
+fn quz<T: D>(a: &T) {
+    a.foo()
+}
+
+trait E : Sized {
+    fn foo(self) {}
+}
+
+trait F : E {
+    fn foo(self) {}
+}
+
+fn foo<T: F>(a: T) {
+    a.foo()
+}
+
+fn pass<T: C>(a: &T) {
+    a.foo()
+}
+
+fn main() {}
diff --git a/src/test/ui/span/issue-37767.stderr b/src/test/ui/span/issue-37767.stderr
new file mode 100644
index 00000000000..7cf74eaab8d
--- /dev/null
+++ b/src/test/ui/span/issue-37767.stderr
@@ -0,0 +1,59 @@
+error[E0034]: multiple applicable items in scope
+  --> $DIR/issue-37767.rs:20:7
+   |
+20 |     a.foo()
+   |       ^^^ multiple `foo` found
+   |
+note: candidate #1 is defined in the trait `A`
+  --> $DIR/issue-37767.rs:12:5
+   |
+12 |     fn foo(&mut self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `A::foo(&a)` instead
+note: candidate #2 is defined in the trait `B`
+  --> $DIR/issue-37767.rs:16:5
+   |
+16 |     fn foo(&mut self) {}
+   |     ^^^^^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `B::foo(&a)` instead
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/issue-37767.rs:32:7
+   |
+32 |     a.foo()
+   |       ^^^ multiple `foo` found
+   |
+note: candidate #1 is defined in the trait `C`
+  --> $DIR/issue-37767.rs:24:5
+   |
+24 |     fn foo(&self) {}
+   |     ^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `C::foo(&a)` instead
+note: candidate #2 is defined in the trait `D`
+  --> $DIR/issue-37767.rs:28:5
+   |
+28 |     fn foo(&self) {}
+   |     ^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `D::foo(&a)` instead
+
+error[E0034]: multiple applicable items in scope
+  --> $DIR/issue-37767.rs:44:7
+   |
+44 |     a.foo()
+   |       ^^^ multiple `foo` found
+   |
+note: candidate #1 is defined in the trait `E`
+  --> $DIR/issue-37767.rs:36:5
+   |
+36 |     fn foo(self) {}
+   |     ^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `E::foo(a)` instead
+note: candidate #2 is defined in the trait `F`
+  --> $DIR/issue-37767.rs:40:5
+   |
+40 |     fn foo(self) {}
+   |     ^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `F::foo(a)` instead
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/compile-fail/issue-7575.rs b/src/test/ui/span/issue-7575.rs
index 3cb30981b67..2d271f0bf17 100644
--- a/src/test/compile-fail/issue-7575.rs
+++ b/src/test/ui/span/issue-7575.rs
@@ -73,15 +73,19 @@ impl ManyImplTrait for Myisize {}
 fn no_param_bound(u: usize, m: Myisize) -> usize {
     u.f8(42) + u.f9(342) + m.fff(42)
             //~^ ERROR no method named `f9` found for type `usize` in the current scope
-            //~^^ NOTE found the following associated functions; to be used as methods, functions must have a `self` parameter
-            //~^^^ ERROR no method named `fff` found for type `Myisize` in the current scope
-            //~^^^^ NOTE found the following associated functions; to be used as methods, functions must have a `self` parameter
+            //~| NOTE found the following associated functions; to be used as methods, functions must have a `self` parameter
+            //~| NOTE to use it here write `CtxtFn::f9(u, 342)` instead
+            //~| ERROR no method named `fff` found for type `Myisize` in the current scope
+            //~| NOTE found the following associated functions; to be used as methods, functions must have a `self` parameter
+            //~| NOTE to use it here write `OtherTrait::f9(u, 342)` instead
+            //~| NOTE to use it here write `UnusedTrait::f9(u, 342)` instead
 }
 
 fn param_bound<T: ManyImplTrait>(t: T) -> bool {
     t.is_str()
     //~^ ERROR no method named `is_str` found for type `T` in the current scope
-    //~^^ NOTE found the following associated functions; to be used as methods, functions must have a `self` parameter
+    //~| NOTE found the following associated functions; to be used as methods, functions must have a `self` parameter
+    //~| NOTE to use it here write `ManyImplTrait::is_str(t)` instead
 }
 
 fn main() {
diff --git a/src/test/ui/span/issue-7575.stderr b/src/test/ui/span/issue-7575.stderr
new file mode 100644
index 00000000000..765aceffe65
--- /dev/null
+++ b/src/test/ui/span/issue-7575.stderr
@@ -0,0 +1,67 @@
+error: no method named `f9` found for type `usize` in the current scope
+  --> $DIR/issue-7575.rs:74:18
+   |
+74 |     u.f8(42) + u.f9(342) + m.fff(42)
+   |                  ^^
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: candidate #1 is defined in the trait `CtxtFn`
+  --> $DIR/issue-7575.rs:16:5
+   |
+16 |     fn f9(usize) -> usize; //~ NOTE candidate
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `CtxtFn::f9(u, 342)` instead
+note: candidate #2 is defined in the trait `OtherTrait`
+  --> $DIR/issue-7575.rs:20:5
+   |
+20 |     fn f9(usize) -> usize; //~ NOTE candidate
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `OtherTrait::f9(u, 342)` instead
+note: candidate #3 is defined in the trait `UnusedTrait`
+  --> $DIR/issue-7575.rs:29:5
+   |
+29 |     fn f9(usize) -> usize; //~ NOTE candidate
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   = help: to disambiguate the method call, write `UnusedTrait::f9(u, 342)` instead
+   = help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item `f9`, perhaps you need to implement one of them:
+   = help: candidate #1: `CtxtFn`
+   = help: candidate #2: `OtherTrait`
+   = help: candidate #3: `UnusedTrait`
+
+error: no method named `fff` found for type `Myisize` in the current scope
+  --> $DIR/issue-7575.rs:74:30
+   |
+74 |     u.f8(42) + u.f9(342) + m.fff(42)
+   |                              ^^^
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: candidate #1 is defined in an impl for the type `Myisize`
+  --> $DIR/issue-7575.rs:51:5
+   |
+51 |       fn fff(i: isize) -> isize { //~ NOTE candidate
+   |  _____^ starting here...
+52 | |         i
+53 | |     }
+   | |_____^ ...ending here
+
+error: no method named `is_str` found for type `T` in the current scope
+  --> $DIR/issue-7575.rs:85:7
+   |
+85 |     t.is_str()
+   |       ^^^^^^
+   |
+   = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: candidate #1 is defined in the trait `ManyImplTrait`
+  --> $DIR/issue-7575.rs:57:5
+   |
+57 |       fn is_str() -> bool { //~ NOTE candidate
+   |  _____^ starting here...
+58 | |         false
+59 | |     }
+   | |_____^ ...ending here
+   = help: to disambiguate the method call, write `ManyImplTrait::is_str(t)` instead
+   = help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `is_str`, perhaps you need to implement it:
+   = help: candidate #1: `ManyImplTrait`
+
+error: aborting due to 3 previous errors
+