From aaa14d1d20f3cc1104bb619f66c78a49762182ff Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 8 Aug 2017 14:12:06 +0200 Subject: [PATCH] Improve error message when duplicate names for type and trait method --- src/librustc_typeck/check/method/mod.rs | 5 ++-- src/librustc_typeck/check/method/probe.rs | 2 +- src/librustc_typeck/check/method/suggest.rs | 32 ++++++++++++++------- src/librustc_typeck/check/mod.rs | 2 +- src/test/ui/trait-method-private.rs | 30 +++++++++++++++++++ src/test/ui/trait-method-private.stderr | 12 ++++++++ 6 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/trait-method-private.rs create mode 100644 src/test/ui/trait-method-private.stderr diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index dd5b0cdda42..1ccb1e64a98 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -58,8 +58,9 @@ pub enum MethodError<'tcx> { ClosureAmbiguity(// DefId of fn trait DefId), - // Found an applicable method, but it is not visible. - PrivateMatch(Def), + // Found an applicable method, but it is not visible. The second argument contains a list of + // not-in-scope traits which may work. + PrivateMatch(Def, Vec), // Found a `Self: Sized` bound where `Self` is a trait object, also the caller may have // forgotten to import a trait. diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 3195b10404d..f771fc11b5a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1015,7 +1015,7 @@ fn pick(mut self) -> PickResult<'tcx> { }; if let Some(def) = private_candidate { - return Err(MethodError::PrivateMatch(def)); + return Err(MethodError::PrivateMatch(def, out_of_scope_traits)); } Err(MethodError::NoMatch(NoMatchData::new(static_candidates, diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 53da9e19ee0..56eacc3194d 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -311,9 +311,11 @@ macro_rules! report_function { self.sess().span_err(span, &msg); } - MethodError::PrivateMatch(def) => { - struct_span_err!(self.tcx.sess, span, E0624, - "{} `{}` is private", def.kind_name(), item_name).emit(); + MethodError::PrivateMatch(def, out_of_scope_traits) => { + let mut err = struct_span_err!(self.tcx.sess, span, E0624, + "{} `{}` is private", def.kind_name(), item_name); + self.suggest_valid_traits(&mut err, out_of_scope_traits); + err.emit(); } MethodError::IllegalSizedBound(candidates) => { @@ -353,13 +355,9 @@ fn suggest_use_candidates(&self, err.note(&msg[..]); } - fn suggest_traits_to_import(&self, - err: &mut DiagnosticBuilder, - span: Span, - rcvr_ty: Ty<'tcx>, - item_name: ast::Name, - rcvr_expr: Option<&hir::Expr>, - valid_out_of_scope_traits: Vec) { + fn suggest_valid_traits(&self, + err: &mut DiagnosticBuilder, + valid_out_of_scope_traits: Vec) -> bool { if !valid_out_of_scope_traits.is_empty() { let mut candidates = valid_out_of_scope_traits; candidates.sort(); @@ -379,6 +377,20 @@ fn suggest_traits_to_import(&self, }); self.suggest_use_candidates(err, msg, candidates); + true + } else { + false + } + } + + fn suggest_traits_to_import(&self, + err: &mut DiagnosticBuilder, + span: Span, + rcvr_ty: Ty<'tcx>, + item_name: ast::Name, + rcvr_expr: Option<&hir::Expr>, + valid_out_of_scope_traits: Vec) { + if self.suggest_valid_traits(err, valid_out_of_scope_traits) { return; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e53e5e7b08c..73e8bf305af 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4016,7 +4016,7 @@ pub fn resolve_ty_and_def_ufcs<'b>(&self, Ok(def) => def, Err(error) => { let def = match error { - method::MethodError::PrivateMatch(def) => def, + method::MethodError::PrivateMatch(def, _) => def, _ => Def::Err, }; if item_name != keywords::Invalid.name() { diff --git a/src/test/ui/trait-method-private.rs b/src/test/ui/trait-method-private.rs new file mode 100644 index 00000000000..5c1bd668ac6 --- /dev/null +++ b/src/test/ui/trait-method-private.rs @@ -0,0 +1,30 @@ +// Copyright 2017 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. + +mod inner { + pub trait Bar { + fn method(&self); + } + + pub struct Foo; + + impl Foo { + fn method(&self) {} + } + + impl Bar for Foo { + fn method(&self) {} + } +} + +fn main() { + let foo = inner::Foo; + foo.method(); +} diff --git a/src/test/ui/trait-method-private.stderr b/src/test/ui/trait-method-private.stderr new file mode 100644 index 00000000000..c7a7b689edc --- /dev/null +++ b/src/test/ui/trait-method-private.stderr @@ -0,0 +1,12 @@ +error[E0624]: method `method` is private + --> $DIR/trait-method-private.rs:29:9 + | +29 | foo.method(); + | ^^^^^^ + | + = help: items from traits can only be used if the trait is in scope + = note: the following trait is implemented but not in scope, perhaps add a `use` for it: + candidate #1: `use inner::Bar;` + +error: aborting due to previous error + -- 2.44.0