From 539041437956abf05bd4ad0b6ecb253591df3085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 17 Mar 2019 21:18:06 -0700 Subject: [PATCH 1/2] Provide suggestion when using field access instead of path When trying to access an associated constant as if it were a field of an instance, provide a suggestion for the correct syntax. --- src/librustc_resolve/error_reporting.rs | 8 ++++++++ src/test/ui/suggestions/assoc-const-as-field.rs | 13 +++++++++++++ src/test/ui/suggestions/assoc-const-as-field.stderr | 11 +++++++++++ 3 files changed, 32 insertions(+) create mode 100644 src/test/ui/suggestions/assoc-const-as-field.rs create mode 100644 src/test/ui/suggestions/assoc-const-as-field.stderr diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs index fc8452e49ad1b..0da10176d299a 100644 --- a/src/librustc_resolve/error_reporting.rs +++ b/src/librustc_resolve/error_reporting.rs @@ -379,6 +379,14 @@ impl<'a> Resolver<'a> { Applicability::MaybeIncorrect ); }, + ExprKind::Field(ref _expr, ident) => { + err.span_suggestion( + sm.start_point(parent.span).to(ident.span), + "use `::` to access an associated item", + format!("{}::{}", path_str, ident), + Applicability::MaybeIncorrect + ); + } _ => { err.span_label( span, diff --git a/src/test/ui/suggestions/assoc-const-as-field.rs b/src/test/ui/suggestions/assoc-const-as-field.rs new file mode 100644 index 0000000000000..678b58936a8d6 --- /dev/null +++ b/src/test/ui/suggestions/assoc-const-as-field.rs @@ -0,0 +1,13 @@ +pub mod Mod { + pub struct Foo {} + impl Foo { + pub const BAR: usize = 42; + } +} + +fn foo(_: usize) {} + +fn main() { + foo(Mod::Foo.Bar); + //~^ ERROR expected value, found +} diff --git a/src/test/ui/suggestions/assoc-const-as-field.stderr b/src/test/ui/suggestions/assoc-const-as-field.stderr new file mode 100644 index 0000000000000..3f23ae57c3d1c --- /dev/null +++ b/src/test/ui/suggestions/assoc-const-as-field.stderr @@ -0,0 +1,11 @@ +error[E0423]: expected value, found struct `Mod::Foo` + --> $DIR/assoc-const-as-field.rs:11:9 + | +LL | foo(Mod::Foo.Bar); + | ^^^^^^^^---- + | | + | help: use `::` to access an associated item: `Mod::Foo::Bar` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0423`. From 4beea1720af3f1bc2d89ecedec539cc4c788cc91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 20 Mar 2019 16:03:29 -0700 Subject: [PATCH 2/2] Deduplicate code for path suggestion --- src/librustc_resolve/error_reporting.rs | 103 +++++++----------- src/test/ui/resolve/issue-22692.stderr | 2 +- .../suggestions/assoc-const-as-field.stderr | 2 +- 3 files changed, 43 insertions(+), 64 deletions(-) diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs index 0da10176d299a..461d02e515d38 100644 --- a/src/librustc_resolve/error_reporting.rs +++ b/src/librustc_resolve/error_reporting.rs @@ -5,7 +5,7 @@ use log::debug; use rustc::hir::def::{Def, CtorKind, Namespace::*}; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::session::config::nightly_options; -use syntax::ast::{ExprKind}; +use syntax::ast::{Expr, ExprKind}; use syntax::symbol::keywords; use syntax_pos::Span; @@ -250,6 +250,29 @@ impl<'a> Resolver<'a> { let ns = source.namespace(); let is_expected = &|def| source.is_expected(def); + let path_sep = |err: &mut DiagnosticBuilder<'_>, expr: &Expr| match expr.node { + ExprKind::Field(_, ident) => { + err.span_suggestion( + expr.span, + "use the path separator to refer to an item", + format!("{}::{}", path_str, ident), + Applicability::MaybeIncorrect, + ); + true + } + ExprKind::MethodCall(ref segment, ..) => { + let span = expr.span.with_hi(segment.ident.span.hi()); + err.span_suggestion( + span, + "use the path separator to refer to an item", + format!("{}::{}", path_str, segment.ident), + Applicability::MaybeIncorrect, + ); + true + } + _ => false, + }; + match (def, source) { (Def::Macro(..), _) => { err.span_suggestion( @@ -259,8 +282,7 @@ impl<'a> Resolver<'a> { Applicability::MaybeIncorrect, ); if path_str == "try" && span.rust_2015() { - err.note("if you want the `try` keyword, \ - you need to be in the 2018 edition"); + err.note("if you want the `try` keyword, you need to be in the 2018 edition"); } } (Def::TyAlias(..), PathSource::Trait(_)) => { @@ -269,25 +291,8 @@ impl<'a> Resolver<'a> { err.note("did you mean to use a trait alias?"); } } - (Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node { - ExprKind::Field(_, ident) => { - err.span_suggestion( - parent.span, - "use the path separator to refer to an item", - format!("{}::{}", path_str, ident), - Applicability::MaybeIncorrect, - ); - } - ExprKind::MethodCall(ref segment, ..) => { - let span = parent.span.with_hi(segment.ident.span.hi()); - err.span_suggestion( - span, - "use the path separator to refer to an item", - format!("{}::{}", path_str, segment.ident), - Applicability::MaybeIncorrect, - ); - } - _ => return false, + (Def::Mod(..), PathSource::Expr(Some(parent))) => if !path_sep(err, &parent) { + return false; }, (Def::Enum(..), PathSource::TupleStruct) | (Def::Enum(..), PathSource::Expr(..)) => { @@ -315,8 +320,10 @@ impl<'a> Resolver<'a> { = self.struct_constructors.get(&def_id).cloned() { let accessible_ctor = self.is_accessible(ctor_vis); if is_expected(ctor_def) && !accessible_ctor { - err.span_label(span, format!("constructor is not visible \ - here due to private fields")); + err.span_label( + span, + format!("constructor is not visible here due to private fields"), + ); } } else { // HACK(estebank): find a better way to figure out that this was a @@ -366,36 +373,12 @@ impl<'a> Resolver<'a> { } } match source { - PathSource::Expr(Some(parent)) => { - match parent.node { - ExprKind::MethodCall(ref path_assignment, _) => { - err.span_suggestion( - sm.start_point(parent.span) - .to(path_assignment.ident.span), - "use `::` to access an associated function", - format!("{}::{}", - path_str, - path_assignment.ident), - Applicability::MaybeIncorrect - ); - }, - ExprKind::Field(ref _expr, ident) => { - err.span_suggestion( - sm.start_point(parent.span).to(ident.span), - "use `::` to access an associated item", - format!("{}::{}", path_str, ident), - Applicability::MaybeIncorrect - ); - } - _ => { - err.span_label( - span, - format!("did you mean `{} {{ /* fields */ }}`?", - path_str), - ); - }, - } - }, + PathSource::Expr(Some(parent)) => if !path_sep(err, &parent) { + err.span_label( + span, + format!("did you mean `{} {{ /* fields */ }}`?", path_str), + ); + } PathSource::Expr(None) if followed_by_brace == true => { if let Some((sp, snippet)) = closing_brace { err.span_suggestion( @@ -407,16 +390,14 @@ impl<'a> Resolver<'a> { } else { err.span_label( span, - format!("did you mean `({} {{ /* fields */ }})`?", - path_str), + format!("did you mean `({} {{ /* fields */ }})`?", path_str), ); } }, _ => { err.span_label( span, - format!("did you mean `{} {{ /* fields */ }}`?", - path_str), + format!("did you mean `{} {{ /* fields */ }}`?", path_str), ); }, } @@ -425,13 +406,11 @@ impl<'a> Resolver<'a> { (Def::Union(..), _) | (Def::Variant(..), _) | (Def::Ctor(_, _, CtorKind::Fictive), _) if ns == ValueNS => { - err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", - path_str)); + err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?", path_str)); } (Def::SelfTy(..), _) if ns == ValueNS => { err.span_label(span, fallback_label); - err.note("can't use `Self` as a constructor, you must use the \ - implemented struct"); + err.note("can't use `Self` as a constructor, you must use the implemented struct"); } (Def::TyAlias(_), _) | (Def::AssociatedTy(..), _) if ns == ValueNS => { err.note("can't use a type alias as a constructor"); diff --git a/src/test/ui/resolve/issue-22692.stderr b/src/test/ui/resolve/issue-22692.stderr index 13752430e714b..e076419f68d47 100644 --- a/src/test/ui/resolve/issue-22692.stderr +++ b/src/test/ui/resolve/issue-22692.stderr @@ -4,7 +4,7 @@ error[E0423]: expected value, found struct `String` LL | let _ = String.new(); | ^^^^^^---- | | - | help: use `::` to access an associated function: `String::new` + | help: use the path separator to refer to an item: `String::new` error: aborting due to previous error diff --git a/src/test/ui/suggestions/assoc-const-as-field.stderr b/src/test/ui/suggestions/assoc-const-as-field.stderr index 3f23ae57c3d1c..5e746ecb2f28f 100644 --- a/src/test/ui/suggestions/assoc-const-as-field.stderr +++ b/src/test/ui/suggestions/assoc-const-as-field.stderr @@ -4,7 +4,7 @@ error[E0423]: expected value, found struct `Mod::Foo` LL | foo(Mod::Foo.Bar); | ^^^^^^^^---- | | - | help: use `::` to access an associated item: `Mod::Foo::Bar` + | help: use the path separator to refer to an item: `Mod::Foo::Bar` error: aborting due to previous error