From f595ea25841eab1139ca10c5fe0349e51cc2b6c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 4 Dec 2016 18:10:59 -0800 Subject: [PATCH] E0034: provide disambiguated syntax for candidates For a given file ```rust trait A { fn foo(&self) {} } trait B : A { fn foo(&self) {} } fn bar(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 | 11 +++ src/librustc_typeck/check/method/suggest.rs | 22 +++++- src/librustc_typeck/check/mod.rs | 10 ++- src/test/ui/span/issue-37767.rs | 51 ++++++++++++++ src/test/ui/span/issue-37767.stderr | 59 ++++++++++++++++ .../{compile-fail => ui/span}/issue-7575.rs | 12 ++-- src/test/ui/span/issue-7575.stderr | 67 +++++++++++++++++++ 7 files changed, 224 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/span/issue-37767.rs create mode 100644 src/test/ui/span/issue-37767.stderr rename src/test/{compile-fail => ui/span}/issue-7575.rs (73%) create mode 100644 src/test/ui/span/issue-7575.stderr diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 81b0a55841ad8..b02bb7c6e4dd8 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 04ec9292d1410..b1705425e6eb0 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::>() + .join(", ")).unwrap_or("...".to_owned()))); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0b316c5d37525..e240c70aaa3a5 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 0000000000000..49ad40259d91f --- /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 or the MIT license +// , 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(a: &T) { + a.foo() +} + +trait C { + fn foo(&self) {} +} + +trait D : C { + fn foo(&self) {} +} + +fn quz(a: &T) { + a.foo() +} + +trait E : Sized { + fn foo(self) {} +} + +trait F : E { + fn foo(self) {} +} + +fn foo(a: T) { + a.foo() +} + +fn pass(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 0000000000000..7cf74eaab8db1 --- /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 similarity index 73% rename from src/test/compile-fail/issue-7575.rs rename to src/test/ui/span/issue-7575.rs index 3cb30981b673c..2d271f0bf1708 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: 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 0000000000000..765aceffe655b --- /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 +