From 7c96d90c2081f3ca84b3786a125cf2c415335e40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 8 Aug 2019 18:24:00 -0700 Subject: [PATCH 1/2] More explicit diagnostic when using a `vec![]` in a pattern ``` error: unexpected `(` after qualified path --> $DIR/vec-macro-in-pattern.rs:3:14 | LL | Some(vec![x]) => (), | ^^^^^^^ | | | unexpected `(` after qualified path | in this macro invocation | use a slice pattern here instead | = help: for more information, see https://doc.rust-lang.org/edition-guide/rust-2018/slice-patterns.html = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) ``` --- src/libsyntax/ext/expand.rs | 28 +++++++++++++++---- src/libsyntax/ext/tt/macro_rules.rs | 23 +++++++++++++++ src/test/ui/proc-macro/lifetimes.stderr | 2 +- .../ui/suggestions/vec-macro-in-pattern.rs | 6 ++++ .../suggestions/vec-macro-in-pattern.stderr | 15 ++++++++++ .../ui/type/ascription/issue-47666.stderr | 1 + 6 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/suggestions/vec-macro-in-pattern.rs create mode 100644 src/test/ui/suggestions/vec-macro-in-pattern.stderr diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 964c81dd46641..36f059531d39d 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -686,12 +686,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ); } - fn parse_ast_fragment(&mut self, - toks: TokenStream, - kind: AstFragmentKind, - path: &Path, - span: Span) - -> AstFragment { + fn parse_ast_fragment( + &mut self, + toks: TokenStream, + kind: AstFragmentKind, + path: &Path, + span: Span, + ) -> AstFragment { let mut parser = self.cx.new_parser_from_tts(&toks.into_trees().collect::>()); match parser.parse_ast_fragment(kind, false) { Ok(fragment) => { @@ -700,6 +701,21 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } Err(mut err) => { err.set_span(span); + match kind { + AstFragmentKind::Ty => { + err.span_label( + span, + "this macro call doesn't expand to a type", + ); + } + AstFragmentKind::Pat => { + err.span_label( + span, + "this macro call doesn't expand to a pattern", + ); + } + _ => {} + }; err.emit(); self.cx.trace_macros_diag(); kind.dummy(span) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 7401f25641236..a9d0b739d6ac7 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -70,6 +70,29 @@ impl<'a> ParserAnyMacro<'a> { } else if !parser.sess.source_map().span_to_filename(parser.token.span).is_real() { e.span_label(site_span, "in this macro invocation"); } + match kind { + AstFragmentKind::Ty => { + e.span_label( + site_span, + "this macro call doesn't expand to a type", + ); + } + AstFragmentKind::Pat if macro_ident.name == sym::vec => { + e.span_label( + site_span, + "use a slice pattern here instead", + ); + e.help("for more information, see https://doc.rust-lang.org/edition-guide/\ + rust-2018/slice-patterns.html"); + } + AstFragmentKind::Pat => { + e.span_label( + site_span, + "this macro call doesn't expand to a pattern", + ); + } + _ => {} + }; e })); diff --git a/src/test/ui/proc-macro/lifetimes.stderr b/src/test/ui/proc-macro/lifetimes.stderr index 2356a119530bb..6e91201405cc6 100644 --- a/src/test/ui/proc-macro/lifetimes.stderr +++ b/src/test/ui/proc-macro/lifetimes.stderr @@ -2,7 +2,7 @@ error: expected type, found `'` --> $DIR/lifetimes.rs:9:10 | LL | type A = single_quote_alone!(); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ this macro call doesn't expand to a type error: aborting due to previous error diff --git a/src/test/ui/suggestions/vec-macro-in-pattern.rs b/src/test/ui/suggestions/vec-macro-in-pattern.rs new file mode 100644 index 0000000000000..5c42a6bdbd44e --- /dev/null +++ b/src/test/ui/suggestions/vec-macro-in-pattern.rs @@ -0,0 +1,6 @@ +fn main() { + match Some(vec![3]) { + Some(vec![x]) => (), //~ ERROR unexpected `(` after qualified path + _ => (), + } +} diff --git a/src/test/ui/suggestions/vec-macro-in-pattern.stderr b/src/test/ui/suggestions/vec-macro-in-pattern.stderr new file mode 100644 index 0000000000000..f94cb93a520b5 --- /dev/null +++ b/src/test/ui/suggestions/vec-macro-in-pattern.stderr @@ -0,0 +1,15 @@ +error: unexpected `(` after qualified path + --> $DIR/vec-macro-in-pattern.rs:3:14 + | +LL | Some(vec![x]) => (), + | ^^^^^^^ + | | + | unexpected `(` after qualified path + | in this macro invocation + | use a slice pattern here instead + | + = help: for more information, see https://doc.rust-lang.org/edition-guide/rust-2018/slice-patterns.html + = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/src/test/ui/type/ascription/issue-47666.stderr b/src/test/ui/type/ascription/issue-47666.stderr index 965bbe5ea41f7..2f052341faead 100644 --- a/src/test/ui/type/ascription/issue-47666.stderr +++ b/src/test/ui/type/ascription/issue-47666.stderr @@ -6,6 +6,7 @@ LL | let _ = Option:Some(vec![0, 1]); | | | | | expected type | | in this macro invocation + | | this macro call doesn't expand to a type | help: maybe write a path separator here: `::` | = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` From 75c5ad2e827a077c3738dee11d9e0dc99962f384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 9 Aug 2019 09:39:30 -0700 Subject: [PATCH 2/2] review comments: use structured suggestion --- src/libsyntax/ext/expand.rs | 17 +----- src/libsyntax/ext/tt/macro_rules.rs | 53 ++++++++++++------- .../ui/suggestions/vec-macro-in-pattern.fixed | 8 +++ .../ui/suggestions/vec-macro-in-pattern.rs | 6 ++- .../suggestions/vec-macro-in-pattern.stderr | 8 +-- 5 files changed, 52 insertions(+), 40 deletions(-) create mode 100644 src/test/ui/suggestions/vec-macro-in-pattern.fixed diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 36f059531d39d..9a3195b1165b1 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -6,6 +6,7 @@ use crate::config::StripUnconfigured; use crate::ext::base::*; use crate::ext::proc_macro::collect_derives; use crate::ext::hygiene::{ExpnId, SyntaxContext, ExpnInfo, ExpnKind}; +use crate::ext::tt::macro_rules::annotate_err_with_kind; use crate::ext::placeholders::{placeholder, PlaceholderExpander}; use crate::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err}; use crate::mut_visit::*; @@ -701,21 +702,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } Err(mut err) => { err.set_span(span); - match kind { - AstFragmentKind::Ty => { - err.span_label( - span, - "this macro call doesn't expand to a type", - ); - } - AstFragmentKind::Pat => { - err.span_label( - span, - "this macro call doesn't expand to a pattern", - ); - } - _ => {} - }; + annotate_err_with_kind(&mut err, kind, span); err.emit(); self.cx.trace_macros_diag(); kind.dummy(span) diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index a9d0b739d6ac7..b057a9ad44d0b 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -17,7 +17,7 @@ use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree}; use crate::{ast, attr, attr::TransparencyError}; -use errors::FatalError; +use errors::{DiagnosticBuilder, FatalError}; use log::debug; use syntax_pos::Span; @@ -43,6 +43,18 @@ pub struct ParserAnyMacro<'a> { arm_span: Span, } +pub fn annotate_err_with_kind(err: &mut DiagnosticBuilder<'_>, kind: AstFragmentKind, span: Span) { + match kind { + AstFragmentKind::Ty => { + err.span_label(span, "this macro call doesn't expand to a type"); + } + AstFragmentKind::Pat => { + err.span_label(span, "this macro call doesn't expand to a pattern"); + } + _ => {} + }; +} + impl<'a> ParserAnyMacro<'a> { pub fn make(mut self: Box>, kind: AstFragmentKind) -> AstFragment { let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self; @@ -71,27 +83,30 @@ impl<'a> ParserAnyMacro<'a> { e.span_label(site_span, "in this macro invocation"); } match kind { - AstFragmentKind::Ty => { - e.span_label( - site_span, - "this macro call doesn't expand to a type", - ); - } AstFragmentKind::Pat if macro_ident.name == sym::vec => { - e.span_label( - site_span, - "use a slice pattern here instead", - ); + let mut suggestion = None; + if let Ok(code) = parser.sess.source_map().span_to_snippet(site_span) { + if let Some(bang) = code.find('!') { + suggestion = Some(code[bang + 1..].to_string()); + } + } + if let Some(suggestion) = suggestion { + e.span_suggestion( + site_span, + "use a slice pattern here instead", + suggestion, + Applicability::MachineApplicable, + ); + } else { + e.span_label( + site_span, + "use a slice pattern here instead", + ); + } e.help("for more information, see https://doc.rust-lang.org/edition-guide/\ - rust-2018/slice-patterns.html"); - } - AstFragmentKind::Pat => { - e.span_label( - site_span, - "this macro call doesn't expand to a pattern", - ); + rust-2018/slice-patterns.html"); } - _ => {} + _ => annotate_err_with_kind(&mut e, kind, site_span), }; e })); diff --git a/src/test/ui/suggestions/vec-macro-in-pattern.fixed b/src/test/ui/suggestions/vec-macro-in-pattern.fixed new file mode 100644 index 0000000000000..e1695d6820a81 --- /dev/null +++ b/src/test/ui/suggestions/vec-macro-in-pattern.fixed @@ -0,0 +1,8 @@ +// run-rustfix +fn main() { + // everything after `.as_ref` should be suggested + match Some(vec![3]).as_ref().map(|v| v.as_slice()) { + Some([_x]) => (), //~ ERROR unexpected `(` after qualified path + _ => (), + } +} diff --git a/src/test/ui/suggestions/vec-macro-in-pattern.rs b/src/test/ui/suggestions/vec-macro-in-pattern.rs index 5c42a6bdbd44e..4843629fbcf90 100644 --- a/src/test/ui/suggestions/vec-macro-in-pattern.rs +++ b/src/test/ui/suggestions/vec-macro-in-pattern.rs @@ -1,6 +1,8 @@ +// run-rustfix fn main() { - match Some(vec![3]) { - Some(vec![x]) => (), //~ ERROR unexpected `(` after qualified path + // everything after `.as_ref` should be suggested + match Some(vec![3]).as_ref().map(|v| v.as_slice()) { + Some(vec![_x]) => (), //~ ERROR unexpected `(` after qualified path _ => (), } } diff --git a/src/test/ui/suggestions/vec-macro-in-pattern.stderr b/src/test/ui/suggestions/vec-macro-in-pattern.stderr index f94cb93a520b5..59ca8ebbf6339 100644 --- a/src/test/ui/suggestions/vec-macro-in-pattern.stderr +++ b/src/test/ui/suggestions/vec-macro-in-pattern.stderr @@ -1,12 +1,12 @@ error: unexpected `(` after qualified path - --> $DIR/vec-macro-in-pattern.rs:3:14 + --> $DIR/vec-macro-in-pattern.rs:5:14 | -LL | Some(vec![x]) => (), - | ^^^^^^^ +LL | Some(vec![_x]) => (), + | ^^^^^^^^ | | | unexpected `(` after qualified path | in this macro invocation - | use a slice pattern here instead + | help: use a slice pattern here instead: `[_x]` | = help: for more information, see https://doc.rust-lang.org/edition-guide/rust-2018/slice-patterns.html = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)