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)