]> git.lizzy.rs Git - rust.git/commitdiff
E0034: provide disambiguated syntax for candidates
authorEsteban Küber <esteban@kuber.com.ar>
Mon, 5 Dec 2016 02:10:59 +0000 (18:10 -0800)
committerEsteban Küber <esteban@kuber.com.ar>
Thu, 12 Jan 2017 22:54:05 +0000 (14:54 -0800)
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)
  |     ^^^
```

src/librustc/ty/sty.rs
src/librustc_typeck/check/method/suggest.rs
src/librustc_typeck/check/mod.rs
src/test/compile-fail/issue-7575.rs [deleted file]
src/test/ui/span/issue-37767.rs [new file with mode: 0644]
src/test/ui/span/issue-37767.stderr [new file with mode: 0644]
src/test/ui/span/issue-7575.rs [new file with mode: 0644]
src/test/ui/span/issue-7575.stderr [new file with mode: 0644]

index 81b0a55841ad839e58547a58565e207dca8af488..b02bb7c6e4dd803f17d796604d63d3193d9a5105 100644 (file)
@@ -1121,6 +1121,17 @@ pub fn is_region_ptr(&self) -> bool {
         }
     }
 
+    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,
index 04ec9292d1410ee727c3684ffe90b060adcb2df1..b1705425e6eb0cdd77501f93cfe76b1f6a2a99f5 100644 (file)
@@ -27,6 +27,7 @@
 use syntax_pos::Span;
 
 use rustc::hir;
+use rustc::hir::print;
 use rustc::infer::type_variable::TypeVariableOrigin;
 
 use std::cell;
@@ -71,7 +72,8 @@ pub fn report_method_error(&self,
                                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 @@ pub fn report_method_error(&self,
                                    "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())));
                     }
                 }
             }
index 0b316c5d37525261de55f0c47206aa7a09635163..e240c70aaa3a56baf77c2959f0dd7e319d1504b0 100644 (file)
@@ -2867,8 +2867,12 @@ fn check_method_call(&self,
             }
             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 @@ pub fn resolve_ty_and_def_ufcs<'b>(&self,
                     _ => 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/compile-fail/issue-7575.rs b/src/test/compile-fail/issue-7575.rs
deleted file mode 100644 (file)
index 3cb3098..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2014 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.
-
-// Test the mechanism for warning about possible missing `self` declarations.
-// ignore-tidy-linelength
-
-trait CtxtFn {
-    fn f8(self, usize) -> usize;
-    fn f9(usize) -> usize; //~ NOTE candidate
-}
-
-trait OtherTrait {
-    fn f9(usize) -> usize; //~ NOTE candidate
-}
-
-// Note: this trait is not implemented, but we can't really tell
-// whether or not an impl would match anyhow without a self
-// declaration to match against, so we wind up prisizeing it as a
-// candidate. This seems not unreasonable -- perhaps the user meant to
-// implement it, after all.
-trait UnusedTrait {
-    fn f9(usize) -> usize; //~ NOTE candidate
-}
-
-impl CtxtFn for usize {
-    fn f8(self, i: usize) -> usize {
-        i * 4
-    }
-
-    fn f9(i: usize) -> usize {
-        i * 4
-    }
-}
-
-impl OtherTrait for usize {
-    fn f9(i: usize) -> usize {
-        i * 8
-    }
-}
-
-struct Myisize(isize);
-
-impl Myisize {
-    fn fff(i: isize) -> isize { //~ NOTE candidate
-        i
-    }
-}
-
-trait ManyImplTrait {
-    fn is_str() -> bool { //~ NOTE candidate
-        false
-    }
-}
-
-impl ManyImplTrait for String {
-    fn is_str() -> bool {
-        true
-    }
-}
-
-impl ManyImplTrait for usize {}
-impl ManyImplTrait for isize {}
-impl ManyImplTrait for char {}
-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
-}
-
-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
-}
-
-fn main() {
-}
diff --git a/src/test/ui/span/issue-37767.rs b/src/test/ui/span/issue-37767.rs
new file mode 100644 (file)
index 0000000..49ad402
--- /dev/null
@@ -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 (file)
index 0000000..7cf74ea
--- /dev/null
@@ -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/ui/span/issue-7575.rs b/src/test/ui/span/issue-7575.rs
new file mode 100644 (file)
index 0000000..2d271f0
--- /dev/null
@@ -0,0 +1,92 @@
+// Copyright 2014 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.
+
+// Test the mechanism for warning about possible missing `self` declarations.
+// ignore-tidy-linelength
+
+trait CtxtFn {
+    fn f8(self, usize) -> usize;
+    fn f9(usize) -> usize; //~ NOTE candidate
+}
+
+trait OtherTrait {
+    fn f9(usize) -> usize; //~ NOTE candidate
+}
+
+// Note: this trait is not implemented, but we can't really tell
+// whether or not an impl would match anyhow without a self
+// declaration to match against, so we wind up prisizeing it as a
+// candidate. This seems not unreasonable -- perhaps the user meant to
+// implement it, after all.
+trait UnusedTrait {
+    fn f9(usize) -> usize; //~ NOTE candidate
+}
+
+impl CtxtFn for usize {
+    fn f8(self, i: usize) -> usize {
+        i * 4
+    }
+
+    fn f9(i: usize) -> usize {
+        i * 4
+    }
+}
+
+impl OtherTrait for usize {
+    fn f9(i: usize) -> usize {
+        i * 8
+    }
+}
+
+struct Myisize(isize);
+
+impl Myisize {
+    fn fff(i: isize) -> isize { //~ NOTE candidate
+        i
+    }
+}
+
+trait ManyImplTrait {
+    fn is_str() -> bool { //~ NOTE candidate
+        false
+    }
+}
+
+impl ManyImplTrait for String {
+    fn is_str() -> bool {
+        true
+    }
+}
+
+impl ManyImplTrait for usize {}
+impl ManyImplTrait for isize {}
+impl ManyImplTrait for char {}
+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
+            //~| 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 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 (file)
index 0000000..765acef
--- /dev/null
@@ -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
+