Auto merge of #133436 - nnethercote:rm-NtVis-NtTy, r=petrochenkov
Remove `NtVis` and `NtTy` The next part of #124141. The first actual remove of `Nonterminal` variants. `NtVis` is a simple case that doesn't get much use, but `NtTy` is more complex. r? `@petrochenkov`
This commit is contained in:
commit
b6d3be4948
20 changed files with 229 additions and 76 deletions
|
@ -203,10 +203,8 @@ impl HasTokens for Nonterminal {
|
|||
Nonterminal::NtStmt(stmt) => stmt.tokens(),
|
||||
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(),
|
||||
Nonterminal::NtPat(pat) => pat.tokens(),
|
||||
Nonterminal::NtTy(ty) => ty.tokens(),
|
||||
Nonterminal::NtMeta(attr_item) => attr_item.tokens(),
|
||||
Nonterminal::NtPath(path) => path.tokens(),
|
||||
Nonterminal::NtVis(vis) => vis.tokens(),
|
||||
Nonterminal::NtBlock(block) => block.tokens(),
|
||||
}
|
||||
}
|
||||
|
@ -216,10 +214,8 @@ impl HasTokens for Nonterminal {
|
|||
Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
|
||||
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
|
||||
Nonterminal::NtPat(pat) => pat.tokens_mut(),
|
||||
Nonterminal::NtTy(ty) => ty.tokens_mut(),
|
||||
Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
|
||||
Nonterminal::NtPath(path) => path.tokens_mut(),
|
||||
Nonterminal::NtVis(vis) => vis.tokens_mut(),
|
||||
Nonterminal::NtBlock(block) => block.tokens_mut(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -907,7 +907,6 @@ fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) {
|
|||
}),
|
||||
token::NtPat(pat) => vis.visit_pat(pat),
|
||||
token::NtExpr(expr) => vis.visit_expr(expr),
|
||||
token::NtTy(ty) => vis.visit_ty(ty),
|
||||
token::NtLiteral(expr) => vis.visit_expr(expr),
|
||||
token::NtMeta(item) => {
|
||||
let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut();
|
||||
|
@ -916,7 +915,6 @@ fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) {
|
|||
visit_lazy_tts(vis, tokens);
|
||||
}
|
||||
token::NtPath(path) => vis.visit_path(path),
|
||||
token::NtVis(visib) => vis.visit_vis(visib),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,9 @@ pub enum MetaVarKind {
|
|||
// This field is needed for `Token::can_begin_string_literal`.
|
||||
can_begin_string_literal: bool,
|
||||
},
|
||||
Ty,
|
||||
Ty {
|
||||
is_path: bool,
|
||||
},
|
||||
Ident,
|
||||
Lifetime,
|
||||
Literal,
|
||||
|
@ -104,7 +106,7 @@ impl fmt::Display for MetaVarKind {
|
|||
MetaVarKind::Pat(PatParam { inferred: false }) => sym::pat_param,
|
||||
MetaVarKind::Expr { kind: Expr2021 { inferred: true } | Expr, .. } => sym::expr,
|
||||
MetaVarKind::Expr { kind: Expr2021 { inferred: false }, .. } => sym::expr_2021,
|
||||
MetaVarKind::Ty => sym::ty,
|
||||
MetaVarKind::Ty { .. } => sym::ty,
|
||||
MetaVarKind::Ident => sym::ident,
|
||||
MetaVarKind::Lifetime => sym::lifetime,
|
||||
MetaVarKind::Literal => sym::literal,
|
||||
|
@ -659,7 +661,6 @@ impl Token {
|
|||
| NtMeta(..)
|
||||
| NtPat(..)
|
||||
| NtPath(..)
|
||||
| NtTy(..)
|
||||
),
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Expr { .. } |
|
||||
|
@ -667,7 +668,7 @@ impl Token {
|
|||
MetaVarKind::Meta |
|
||||
MetaVarKind::Pat(_) |
|
||||
MetaVarKind::Path |
|
||||
MetaVarKind::Ty
|
||||
MetaVarKind::Ty { .. }
|
||||
))) => true,
|
||||
_ => false,
|
||||
}
|
||||
|
@ -688,9 +689,9 @@ impl Token {
|
|||
Lifetime(..) | // lifetime bound in trait object
|
||||
Lt | BinOp(Shl) | // associated path
|
||||
PathSep => true, // global path
|
||||
Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)),
|
||||
Interpolated(ref nt) => matches!(&**nt, NtPath(..)),
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Ty |
|
||||
MetaVarKind::Ty { .. } |
|
||||
MetaVarKind::Path
|
||||
))) => true,
|
||||
// For anonymous structs or unions, which only appear in specific positions
|
||||
|
@ -969,6 +970,15 @@ impl Token {
|
|||
}
|
||||
}
|
||||
|
||||
/// Is this an invisible open delimiter at the start of a token sequence
|
||||
/// from an expanded metavar?
|
||||
pub fn is_metavar_seq(&self) -> Option<MetaVarKind> {
|
||||
match self.kind {
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => Some(kind),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn glue(&self, joint: &Token) -> Option<Token> {
|
||||
let kind = match self.kind {
|
||||
Eq => match joint.kind {
|
||||
|
@ -1067,12 +1077,10 @@ pub enum Nonterminal {
|
|||
NtStmt(P<ast::Stmt>),
|
||||
NtPat(P<ast::Pat>),
|
||||
NtExpr(P<ast::Expr>),
|
||||
NtTy(P<ast::Ty>),
|
||||
NtLiteral(P<ast::Expr>),
|
||||
/// Stuff inside brackets for attributes
|
||||
NtMeta(P<ast::AttrItem>),
|
||||
NtPath(P<ast::Path>),
|
||||
NtVis(P<ast::Visibility>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
|
||||
|
@ -1166,10 +1174,8 @@ impl Nonterminal {
|
|||
NtStmt(stmt) => stmt.span,
|
||||
NtPat(pat) => pat.span,
|
||||
NtExpr(expr) | NtLiteral(expr) => expr.span,
|
||||
NtTy(ty) => ty.span,
|
||||
NtMeta(attr_item) => attr_item.span(),
|
||||
NtPath(path) => path.span,
|
||||
NtVis(vis) => vis.span,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1181,10 +1187,8 @@ impl Nonterminal {
|
|||
NtPat(..) => "pattern",
|
||||
NtExpr(..) => "expression",
|
||||
NtLiteral(..) => "literal",
|
||||
NtTy(..) => "type",
|
||||
NtMeta(..) => "attribute",
|
||||
NtPath(..) => "path",
|
||||
NtVis(..) => "visibility",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1207,11 +1211,9 @@ impl fmt::Debug for Nonterminal {
|
|||
NtStmt(..) => f.pad("NtStmt(..)"),
|
||||
NtPat(..) => f.pad("NtPat(..)"),
|
||||
NtExpr(..) => f.pad("NtExpr(..)"),
|
||||
NtTy(..) => f.pad("NtTy(..)"),
|
||||
NtLiteral(..) => f.pad("NtLiteral(..)"),
|
||||
NtMeta(..) => f.pad("NtMeta(..)"),
|
||||
NtPath(..) => f.pad("NtPath(..)"),
|
||||
NtVis(..) => f.pad("NtVis(..)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -469,10 +469,8 @@ impl TokenStream {
|
|||
}
|
||||
Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt),
|
||||
Nonterminal::NtPat(pat) => TokenStream::from_ast(pat),
|
||||
Nonterminal::NtTy(ty) => TokenStream::from_ast(ty),
|
||||
Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr),
|
||||
Nonterminal::NtPath(path) => TokenStream::from_ast(path),
|
||||
Nonterminal::NtVis(vis) => TokenStream::from_ast(vis),
|
||||
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::ExprKind;
|
||||
use rustc_ast::mut_visit::{self, MutVisitor};
|
||||
use rustc_ast::token::{self, Delimiter, IdentIsRaw, Lit, LitKind, Nonterminal, Token, TokenKind};
|
||||
use rustc_ast::token::{
|
||||
self, Delimiter, IdentIsRaw, InvisibleOrigin, Lit, LitKind, MetaVarKind, Nonterminal, Token,
|
||||
TokenKind,
|
||||
};
|
||||
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::{ExprKind, TyKind};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::{Diag, DiagCtxtHandle, PResult, pluralize};
|
||||
use rustc_parse::lexer::nfc_normalize;
|
||||
|
@ -274,6 +277,33 @@ pub(super) fn transcribe<'a>(
|
|||
// some of the unnecessary whitespace.
|
||||
let ident = MacroRulesNormalizedIdent::new(original_ident);
|
||||
if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
|
||||
// We wrap the tokens in invisible delimiters, unless they are already wrapped
|
||||
// in invisible delimiters with the same `MetaVarKind`. Because some proc
|
||||
// macros can't multiple layers of invisible delimiters of the same
|
||||
// `MetaVarKind`. This loses some span info, though it hopefully won't matter.
|
||||
let mut mk_delimited = |mv_kind, mut stream: TokenStream| {
|
||||
if stream.len() == 1 {
|
||||
let tree = stream.iter().next().unwrap();
|
||||
if let TokenTree::Delimited(_, _, delim, inner) = tree
|
||||
&& let Delimiter::Invisible(InvisibleOrigin::MetaVar(mvk)) = delim
|
||||
&& mv_kind == *mvk
|
||||
{
|
||||
stream = inner.clone();
|
||||
}
|
||||
}
|
||||
|
||||
// Emit as a token stream within `Delimiter::Invisible` to maintain
|
||||
// parsing priorities.
|
||||
marker.visit_span(&mut sp);
|
||||
// Both the open delim and close delim get the same span, which covers the
|
||||
// `$foo` in the decl macro RHS.
|
||||
TokenTree::Delimited(
|
||||
DelimSpan::from_single(sp),
|
||||
DelimSpacing::new(Spacing::Alone, Spacing::Alone),
|
||||
Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)),
|
||||
stream,
|
||||
)
|
||||
};
|
||||
let tt = match cur_matched {
|
||||
MatchedSingle(ParseNtResult::Tt(tt)) => {
|
||||
// `tt`s are emitted into the output stream directly as "raw tokens",
|
||||
|
@ -292,6 +322,13 @@ pub(super) fn transcribe<'a>(
|
|||
let kind = token::NtLifetime(*ident, *is_raw);
|
||||
TokenTree::token_alone(kind, sp)
|
||||
}
|
||||
MatchedSingle(ParseNtResult::Ty(ty)) => {
|
||||
let is_path = matches!(&ty.kind, TyKind::Path(None, _path));
|
||||
mk_delimited(MetaVarKind::Ty { is_path }, TokenStream::from_ast(ty))
|
||||
}
|
||||
MatchedSingle(ParseNtResult::Vis(vis)) => {
|
||||
mk_delimited(MetaVarKind::Vis, TokenStream::from_ast(vis))
|
||||
}
|
||||
MatchedSingle(ParseNtResult::Nt(nt)) => {
|
||||
// Other variables are emitted into the output stream as groups with
|
||||
// `Delimiter::Invisible` to maintain parsing priorities.
|
||||
|
|
|
@ -117,12 +117,15 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath {
|
|||
($self: expr, $allow_qpath_recovery: expr) => {
|
||||
if $allow_qpath_recovery
|
||||
&& $self.may_recover()
|
||||
&& $self.look_ahead(1, |t| t == &token::PathSep)
|
||||
&& let token::Interpolated(nt) = &$self.token.kind
|
||||
&& let token::NtTy(ty) = &**nt
|
||||
&& let Some(mv_kind) = $self.token.is_metavar_seq()
|
||||
&& let token::MetaVarKind::Ty { .. } = mv_kind
|
||||
&& $self.check_noexpect_past_close_delim(&token::PathSep)
|
||||
{
|
||||
let ty = ty.clone();
|
||||
$self.bump();
|
||||
// Reparse the type, then move to recovery.
|
||||
let ty = $self
|
||||
.eat_metavar_seq(mv_kind, |this| this.parse_ty_no_question_mark_recover())
|
||||
.expect("metavar seq ty");
|
||||
|
||||
return $self.maybe_recover_from_bad_qpath_stage_2($self.prev_token.span, ty);
|
||||
}
|
||||
};
|
||||
|
@ -614,6 +617,24 @@ impl<'a> Parser<'a> {
|
|||
self.token == *tok
|
||||
}
|
||||
|
||||
// Check the first token after the delimiter that closes the current
|
||||
// delimited sequence. (Panics if used in the outermost token stream, which
|
||||
// has no delimiters.) It uses a clone of the relevant tree cursor to skip
|
||||
// past the entire `TokenTree::Delimited` in a single step, avoiding the
|
||||
// need for unbounded token lookahead.
|
||||
//
|
||||
// Primarily used when `self.token` matches
|
||||
// `OpenDelim(Delimiter::Invisible(_))`, to look ahead through the current
|
||||
// metavar expansion.
|
||||
fn check_noexpect_past_close_delim(&self, tok: &TokenKind) -> bool {
|
||||
let mut tree_cursor = self.token_cursor.stack.last().unwrap().clone();
|
||||
tree_cursor.bump();
|
||||
matches!(
|
||||
tree_cursor.curr(),
|
||||
Some(TokenTree::Token(token::Token { kind, .. }, _)) if kind == tok
|
||||
)
|
||||
}
|
||||
|
||||
/// Consumes a token 'tok' if it exists. Returns whether the given token was present.
|
||||
///
|
||||
/// the main purpose of this function is to reduce the cluttering of the suggestions list
|
||||
|
@ -721,6 +742,43 @@ impl<'a> Parser<'a> {
|
|||
if !self.eat_keyword(exp) { self.unexpected() } else { Ok(()) }
|
||||
}
|
||||
|
||||
/// Consume a sequence produced by a metavar expansion, if present.
|
||||
fn eat_metavar_seq<T>(
|
||||
&mut self,
|
||||
mv_kind: MetaVarKind,
|
||||
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
) -> Option<T> {
|
||||
self.eat_metavar_seq_with_matcher(|mvk| mvk == mv_kind, f)
|
||||
}
|
||||
|
||||
/// A slightly more general form of `eat_metavar_seq`, for use with the
|
||||
/// `MetaVarKind` variants that have parameters, where an exact match isn't
|
||||
/// desired.
|
||||
fn eat_metavar_seq_with_matcher<T>(
|
||||
&mut self,
|
||||
match_mv_kind: impl Fn(MetaVarKind) -> bool,
|
||||
mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
|
||||
) -> Option<T> {
|
||||
if let token::OpenDelim(delim) = self.token.kind
|
||||
&& let Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)) = delim
|
||||
&& match_mv_kind(mv_kind)
|
||||
{
|
||||
self.bump();
|
||||
let res = f(self).expect("failed to reparse {mv_kind:?}");
|
||||
if let token::CloseDelim(delim) = self.token.kind
|
||||
&& let Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)) = delim
|
||||
&& match_mv_kind(mv_kind)
|
||||
{
|
||||
self.bump();
|
||||
Some(res)
|
||||
} else {
|
||||
panic!("no close delim when reparsing {mv_kind:?}");
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the given keyword `kw` followed by a non-reserved identifier?
|
||||
fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool {
|
||||
self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident())
|
||||
|
@ -1455,7 +1513,11 @@ impl<'a> Parser<'a> {
|
|||
/// so emit a proper diagnostic.
|
||||
// Public for rustfmt usage.
|
||||
pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> {
|
||||
maybe_whole!(self, NtVis, |vis| vis.into_inner());
|
||||
if let Some(vis) = self
|
||||
.eat_metavar_seq(MetaVarKind::Vis, |this| this.parse_visibility(FollowedByType::Yes))
|
||||
{
|
||||
return Ok(vis);
|
||||
}
|
||||
|
||||
if !self.eat_keyword(exp!(Pub)) {
|
||||
// We need a span for our `Spanned<VisibilityKind>`, but there's inherently no
|
||||
|
@ -1683,7 +1745,9 @@ pub enum ParseNtResult {
|
|||
Tt(TokenTree),
|
||||
Ident(Ident, IdentIsRaw),
|
||||
Lifetime(Ident, IdentIsRaw),
|
||||
Ty(P<ast::Ty>),
|
||||
Vis(P<ast::Visibility>),
|
||||
|
||||
/// This case will eventually be removed, along with `Token::Interpolate`.
|
||||
/// This variant will eventually be removed, along with `Token::Interpolate`.
|
||||
Nt(Arc<Nonterminal>),
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ impl<'a> Parser<'a> {
|
|||
MetaVarKind::Stmt
|
||||
| MetaVarKind::Pat(_)
|
||||
| MetaVarKind::Expr { .. }
|
||||
| MetaVarKind::Ty
|
||||
| MetaVarKind::Ty { .. }
|
||||
| MetaVarKind::Literal // `true`, `false`
|
||||
| MetaVarKind::Meta
|
||||
| MetaVarKind::Path => true,
|
||||
|
@ -51,14 +51,11 @@ impl<'a> Parser<'a> {
|
|||
NtStmt(_)
|
||||
| NtPat(_)
|
||||
| NtExpr(_)
|
||||
| NtTy(_)
|
||||
| NtLiteral(_) // `true`, `false`
|
||||
| NtMeta(_)
|
||||
| NtPath(_) => true,
|
||||
|
||||
NtItem(_)
|
||||
| NtBlock(_)
|
||||
| NtVis(_) => false,
|
||||
NtItem(_) | NtBlock(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,7 +85,7 @@ impl<'a> Parser<'a> {
|
|||
NonterminalKind::Ident => get_macro_ident(token).is_some(),
|
||||
NonterminalKind::Literal => token.can_begin_literal_maybe_minus(),
|
||||
NonterminalKind::Vis => match token.kind {
|
||||
// The follow-set of :vis + "priv" keyword + interpolated
|
||||
// The follow-set of :vis + "priv" keyword + interpolated/metavar-expansion.
|
||||
token::Comma
|
||||
| token::Ident(..)
|
||||
| token::NtIdent(..)
|
||||
|
@ -102,7 +99,7 @@ impl<'a> Parser<'a> {
|
|||
token::NtLifetime(..) => true,
|
||||
token::Interpolated(nt) => match &**nt {
|
||||
NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
|
||||
NtItem(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) | NtVis(_) => false,
|
||||
NtItem(_) | NtPat(_) | NtMeta(_) | NtPath(_) => false,
|
||||
},
|
||||
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k {
|
||||
MetaVarKind::Block
|
||||
|
@ -111,7 +108,7 @@ impl<'a> Parser<'a> {
|
|||
| MetaVarKind::Literal => true,
|
||||
MetaVarKind::Item
|
||||
| MetaVarKind::Pat(_)
|
||||
| MetaVarKind::Ty
|
||||
| MetaVarKind::Ty { .. }
|
||||
| MetaVarKind::Meta
|
||||
| MetaVarKind::Path
|
||||
| MetaVarKind::Vis => false,
|
||||
|
@ -189,7 +186,9 @@ impl<'a> Parser<'a> {
|
|||
NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?)
|
||||
}
|
||||
NonterminalKind::Ty => {
|
||||
NtTy(self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?)
|
||||
return Ok(ParseNtResult::Ty(
|
||||
self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?,
|
||||
));
|
||||
}
|
||||
// this could be handled like a token, since it is one
|
||||
NonterminalKind::Ident => {
|
||||
|
@ -208,8 +207,9 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
NonterminalKind::Meta => NtMeta(P(self.parse_attr_item(ForceCollect::Yes)?)),
|
||||
NonterminalKind::Vis => {
|
||||
NtVis(P(self
|
||||
.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))
|
||||
return Ok(ParseNtResult::Vis(P(self.collect_tokens_no_attrs(|this| {
|
||||
this.parse_visibility(FollowedByType::Yes)
|
||||
})?)));
|
||||
}
|
||||
NonterminalKind::Lifetime => {
|
||||
// We want to keep `'keyword` parsing, just like `keyword` is still
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::mem;
|
|||
|
||||
use ast::token::IdentIsRaw;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::token::{self, Delimiter, MetaVarKind, Token, TokenKind};
|
||||
use rustc_ast::{
|
||||
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint,
|
||||
AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
|
||||
|
@ -196,14 +196,12 @@ impl<'a> Parser<'a> {
|
|||
|
||||
maybe_whole!(self, NtPath, |path| reject_generics_if_mod_style(self, path.into_inner()));
|
||||
|
||||
if let token::Interpolated(nt) = &self.token.kind {
|
||||
if let token::NtTy(ty) = &**nt {
|
||||
if let ast::TyKind::Path(None, path) = &ty.kind {
|
||||
let path = path.clone();
|
||||
self.bump();
|
||||
return Ok(reject_generics_if_mod_style(self, path));
|
||||
}
|
||||
}
|
||||
// If we have a `ty` metavar in the form of a path, reparse it directly as a path, instead
|
||||
// of reparsing it as a `ty` and then extracting the path.
|
||||
if let Some(path) = self.eat_metavar_seq(MetaVarKind::Ty { is_path: true }, |this| {
|
||||
this.parse_path(PathStyle::Type)
|
||||
}) {
|
||||
return Ok(reject_generics_if_mod_style(self, path));
|
||||
}
|
||||
|
||||
let lo = self.token.span;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token, TokenKind};
|
||||
use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, MetaVarKind, Token, TokenKind};
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy,
|
||||
|
@ -18,7 +18,7 @@ use crate::errors::{
|
|||
HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
|
||||
NestedCVariadicType, ReturnTypesUseThinArrow,
|
||||
};
|
||||
use crate::{exp, maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||
use crate::{exp, maybe_recover_from_interpolated_ty_qpath};
|
||||
|
||||
/// Signals whether parsing a type should allow `+`.
|
||||
///
|
||||
|
@ -183,7 +183,8 @@ impl<'a> Parser<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
/// Parse a type without recovering `:` as `->` to avoid breaking code such as `where fn() : for<'a>`
|
||||
/// Parse a type without recovering `:` as `->` to avoid breaking code such
|
||||
/// as `where fn() : for<'a>`.
|
||||
pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> {
|
||||
self.parse_ty_common(
|
||||
AllowPlus::Yes,
|
||||
|
@ -247,7 +248,13 @@ impl<'a> Parser<'a> {
|
|||
) -> PResult<'a, P<Ty>> {
|
||||
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
|
||||
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
|
||||
maybe_whole!(self, NtTy, |ty| ty);
|
||||
|
||||
if let Some(ty) = self.eat_metavar_seq_with_matcher(
|
||||
|mv_kind| matches!(mv_kind, MetaVarKind::Ty { .. }),
|
||||
|this| this.parse_ty_no_question_mark_recover(),
|
||||
) {
|
||||
return Ok(ty);
|
||||
}
|
||||
|
||||
let lo = self.token.span;
|
||||
let mut impl_dyn_multi = false;
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
fn e() {
|
||||
type_ascribe!(p, a<p:p<e=6>>);
|
||||
//~^ ERROR cannot find type `a` in this scope
|
||||
//~| ERROR path separator must be a double colon
|
||||
//~| ERROR cannot find value
|
||||
//~| ERROR associated const equality
|
||||
//~| ERROR cannot find trait `p` in this scope
|
||||
//~| ERROR associated const equality
|
||||
//~| ERROR failed to resolve: use of unresolved module or unlinked crate `p`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
error: path separator must be a double colon
|
||||
--> $DIR/issue-93835.rs:4:25
|
||||
|
|
||||
LL | type_ascribe!(p, a<p:p<e=6>>);
|
||||
| ^
|
||||
|
|
||||
= note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
|
||||
help: use a double colon instead
|
||||
|
|
||||
LL | type_ascribe!(p, a<p::p<e=6>>);
|
||||
| +
|
||||
|
||||
error[E0425]: cannot find value `p` in this scope
|
||||
--> $DIR/issue-93835.rs:4:19
|
||||
|
|
||||
|
@ -10,12 +22,6 @@ error[E0412]: cannot find type `a` in this scope
|
|||
LL | type_ascribe!(p, a<p:p<e=6>>);
|
||||
| ^ not found in this scope
|
||||
|
||||
error[E0405]: cannot find trait `p` in this scope
|
||||
--> $DIR/issue-93835.rs:4:26
|
||||
|
|
||||
LL | type_ascribe!(p, a<p:p<e=6>>);
|
||||
| ^ not found in this scope
|
||||
|
||||
error[E0658]: associated const equality is incomplete
|
||||
--> $DIR/issue-93835.rs:4:28
|
||||
|
|
||||
|
@ -26,7 +32,26 @@ LL | type_ascribe!(p, a<p:p<e=6>>);
|
|||
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error[E0658]: associated const equality is incomplete
|
||||
--> $DIR/issue-93835.rs:4:28
|
||||
|
|
||||
LL | type_ascribe!(p, a<p:p<e=6>>);
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
|
||||
= help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
Some errors have detailed explanations: E0405, E0412, E0425, E0658.
|
||||
For more information about an error, try `rustc --explain E0405`.
|
||||
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `p`
|
||||
--> $DIR/issue-93835.rs:4:24
|
||||
|
|
||||
LL | type_ascribe!(p, a<p:p<e=6>>);
|
||||
| ^ use of unresolved module or unlinked crate `p`
|
||||
|
|
||||
= help: you might be missing a crate named `p`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0412, E0425, E0433, E0658.
|
||||
For more information about an error, try `rustc --explain E0412`.
|
||||
|
|
17
tests/ui/macros/block-to-expr-metavar.rs
Normal file
17
tests/ui/macros/block-to-expr-metavar.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
//@ check-pass
|
||||
//
|
||||
// A test case where a `block` fragment specifier is interpreted as an `expr`
|
||||
// fragment specifier. It's an interesting case for the handling of invisible
|
||||
// delimiters.
|
||||
|
||||
macro_rules! m_expr {
|
||||
($e:expr) => { const _CURRENT: u32 = $e; };
|
||||
}
|
||||
|
||||
macro_rules! m_block {
|
||||
($b:block) => ( m_expr!($b); );
|
||||
}
|
||||
|
||||
fn main() {
|
||||
m_block!({ 1 });
|
||||
}
|
|
@ -19,7 +19,7 @@ macro_rules! qpath {
|
|||
|
||||
(ty, <$type:ty as $trait:ty>::$name:ident) => {
|
||||
<$type as $trait>::$name
|
||||
//~^ ERROR expected identifier, found `!`
|
||||
//~^ ERROR expected identifier, found metavariable
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
error: expected identifier, found `!`
|
||||
error: expected identifier, found metavariable
|
||||
--> $DIR/macro-interpolation.rs:21:19
|
||||
|
|
||||
LL | <$type as $trait>::$name
|
||||
| ^^^^^^ expected identifier
|
||||
| ^^^^^^ expected identifier, found metavariable
|
||||
...
|
||||
LL | let _: qpath!(ty, <str as !>::Owned);
|
||||
| -----------------------------
|
||||
|
|
|
@ -9,8 +9,8 @@ macro_rules! values {
|
|||
}
|
||||
};
|
||||
}
|
||||
//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)`
|
||||
//~| ERROR macro expansion ignores type `(String)` and any tokens following
|
||||
//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable
|
||||
//~| ERROR macro expansion ignores `ty` metavariable and any tokens following
|
||||
|
||||
values!(STRING(1) as (String) => cfg(test),);
|
||||
//~^ ERROR expected one of `!` or `::`, found `<eof>`
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)`
|
||||
error: expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable
|
||||
--> $DIR/syntax-error-recovery.rs:7:26
|
||||
|
|
||||
LL | $token $($inner)? = $value,
|
||||
|
@ -10,7 +10,7 @@ LL | values!(STRING(1) as (String) => cfg(test),);
|
|||
= help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
|
||||
= note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: macro expansion ignores type `(String)` and any tokens following
|
||||
error: macro expansion ignores `ty` metavariable and any tokens following
|
||||
--> $DIR/syntax-error-recovery.rs:7:26
|
||||
|
|
||||
LL | $token $($inner)? = $value,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
macro_rules! test_macro {
|
||||
( $( $t:ty ),* $(),*) => {
|
||||
enum SomeEnum {
|
||||
$( $t, )* //~ ERROR expected identifier, found `String`
|
||||
$( $t, )* //~ ERROR expected identifier, found metavariable
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
error: expected identifier, found `String`
|
||||
error: expected identifier, found metavariable
|
||||
--> $DIR/issue-37113.rs:4:16
|
||||
|
|
||||
LL | enum SomeEnum {
|
||||
| -------- while parsing this enum
|
||||
LL | $( $t, )*
|
||||
| ^^ expected identifier
|
||||
| ^^ expected identifier, found metavariable
|
||||
...
|
||||
LL | test_macro!(String,);
|
||||
| -------------------- in this macro invocation
|
||||
|
|
|
@ -10,5 +10,6 @@ macro_rules! m {
|
|||
fn main() {
|
||||
m!('static);
|
||||
//~^ ERROR lifetime in trait object type must be followed by `+`
|
||||
//~| ERROR lifetime in trait object type must be followed by `+`
|
||||
//~| ERROR at least one trait is required for an object type
|
||||
}
|
||||
|
|
|
@ -4,12 +4,20 @@ error: lifetime in trait object type must be followed by `+`
|
|||
LL | m!('static);
|
||||
| ^^^^^^^
|
||||
|
||||
error: lifetime in trait object type must be followed by `+`
|
||||
--> $DIR/trait-object-macro-matcher.rs:11:8
|
||||
|
|
||||
LL | m!('static);
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
|
||||
error[E0224]: at least one trait is required for an object type
|
||||
--> $DIR/trait-object-macro-matcher.rs:11:8
|
||||
|
|
||||
LL | m!('static);
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0224`.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue