Skip to content

Commit

Permalink
E0034: provide disambiguated syntax for candidates
Browse files Browse the repository at this point in the history
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)
  |     ^^^
```
  • Loading branch information
estebank committed Jan 12, 2017
1 parent 27b9e6d commit f595ea2
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 8 deletions.
11 changes: 11 additions & 0 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
22 changes: 21 additions & 1 deletion src/librustc_typeck/check/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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())));
}
}
}
Expand Down
10 changes: 7 additions & 3 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand Down
51 changes: 51 additions & 0 deletions src/test/ui/span/issue-37767.rs
Original file line number Diff line number Diff line change
@@ -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() {}
59 changes: 59 additions & 0 deletions src/test/ui/span/issue-37767.stderr
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
67 changes: 67 additions & 0 deletions src/test/ui/span/issue-7575.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit f595ea2

Please sign in to comment.