diff options
Diffstat (limited to 'compiler/rustc_ast/src')
| -rw-r--r-- | compiler/rustc_ast/src/ast.rs | 65 | ||||
| -rw-r--r-- | compiler/rustc_ast/src/ast_traits.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_ast/src/attr/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_ast/src/mut_visit.rs | 68 | ||||
| -rw-r--r-- | compiler/rustc_ast/src/token.rs | 104 | ||||
| -rw-r--r-- | compiler/rustc_ast/src/tokenstream.rs | 25 | ||||
| -rw-r--r-- | compiler/rustc_ast/src/util/classify.rs | 98 | ||||
| -rw-r--r-- | compiler/rustc_ast/src/visit.rs | 30 |
8 files changed, 265 insertions, 129 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7951b7e7b75..1a166956075 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2105,7 +2105,7 @@ impl Ty { #[derive(Clone, Encodable, Decodable, Debug)] pub struct BareFnTy { - pub unsafety: Unsafe, + pub safety: Safety, pub ext: Extern, pub generic_params: ThinVec<GenericParam>, pub decl: P<FnDecl>, @@ -2484,11 +2484,15 @@ pub enum IsAuto { No, } +/// Safety of items. #[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable, Debug)] #[derive(HashStable_Generic)] -pub enum Unsafe { - Yes(Span), - No, +pub enum Safety { + /// `unsafe` an item is explicitly marked as `unsafe`. + Unsafe(Span), + /// Default means no value was provided, it will take a default value given the context in + /// which is used. + Default, } /// Describes what kind of coroutine markers, if any, a function has. @@ -2692,7 +2696,7 @@ pub struct ModSpans { pub struct ForeignMod { /// `unsafe` keyword accepted syntactically for macro DSLs, but not /// semantically by Rust. - pub unsafety: Unsafe, + pub safety: Safety, pub abi: Option<StrLit>, pub items: ThinVec<P<ForeignItem>>, } @@ -2729,6 +2733,13 @@ pub enum UseTreeKind { /// `use prefix` or `use prefix as rename` Simple(Option<Ident>), /// `use prefix::{...}` + /// + /// The span represents the braces of the nested group and all elements within: + /// + /// ```text + /// use foo::{bar, baz}; + /// ^^^^^^^^^^ + /// ``` Nested { items: ThinVec<(UseTree, NodeId)>, span: Span }, /// `use prefix::*` Glob, @@ -2961,6 +2972,7 @@ impl Item { | ItemKind::GlobalAsm(_) | ItemKind::MacCall(_) | ItemKind::Delegation(_) + | ItemKind::DelegationMac(_) | ItemKind::MacroDef(_) => None, ItemKind::Static(_) => None, ItemKind::Const(i) => Some(&i.generics), @@ -3010,8 +3022,8 @@ impl Extern { /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`). #[derive(Clone, Copy, Encodable, Decodable, Debug)] pub struct FnHeader { - /// The `unsafe` keyword, if any - pub unsafety: Unsafe, + /// Whether this is `unsafe`, or has a default safety + pub safety: Safety, /// Whether this is `async`, `gen`, or nothing. pub coroutine_kind: Option<CoroutineKind>, /// The `const` keyword, if any @@ -3023,8 +3035,8 @@ pub struct FnHeader { impl FnHeader { /// Does this function header have any qualifiers or is it empty? pub fn has_qualifiers(&self) -> bool { - let Self { unsafety, coroutine_kind, constness, ext } = self; - matches!(unsafety, Unsafe::Yes(_)) + let Self { safety, coroutine_kind, constness, ext } = self; + matches!(safety, Safety::Unsafe(_)) || coroutine_kind.is_some() || matches!(constness, Const::Yes(_)) || !matches!(ext, Extern::None) @@ -3034,7 +3046,7 @@ impl FnHeader { impl Default for FnHeader { fn default() -> FnHeader { FnHeader { - unsafety: Unsafe::No, + safety: Safety::Default, coroutine_kind: None, constness: Const::No, ext: Extern::None, @@ -3044,7 +3056,7 @@ impl Default for FnHeader { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Trait { - pub unsafety: Unsafe, + pub safety: Safety, pub is_auto: IsAuto, pub generics: Generics, pub bounds: GenericBounds, @@ -3100,7 +3112,7 @@ pub struct TyAlias { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Impl { pub defaultness: Defaultness, - pub unsafety: Unsafe, + pub safety: Safety, pub generics: Generics, pub constness: Const, pub polarity: ImplPolarity, @@ -3123,8 +3135,16 @@ pub struct Delegation { /// Path resolution id. pub id: NodeId, pub qself: Option<P<QSelf>>, - pub rename: Option<Ident>, pub path: Path, + pub rename: Option<Ident>, + pub body: Option<P<Block>>, +} + +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct DelegationMac { + pub qself: Option<P<QSelf>>, + pub prefix: Path, + pub suffixes: ThinVec<(Ident, Option<Ident>)>, pub body: Option<P<Block>>, } @@ -3200,7 +3220,7 @@ pub enum ItemKind { /// E.g., `mod foo;` or `mod foo { .. }`. /// `unsafe` keyword on modules is accepted syntactically for macro DSLs, but not /// semantically by Rust. - Mod(Unsafe, ModKind), + Mod(Safety, ModKind), /// An external module (`extern`). /// /// E.g., `extern {}` or `extern "C" {}`. @@ -3243,19 +3263,23 @@ pub enum ItemKind { /// A macro definition. MacroDef(MacroDef), - /// A delegation item (`reuse`). + /// A single delegation item (`reuse`). /// /// E.g. `reuse <Type as Trait>::name { target_expr_template }`. Delegation(Box<Delegation>), + /// A list delegation item (`reuse prefix::{a, b, c}`). + /// Treated similarly to a macro call and expanded early. + DelegationMac(Box<DelegationMac>), } impl ItemKind { + /// "a" or "an" pub fn article(&self) -> &'static str { use ItemKind::*; match self { Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..) | Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..) - | Delegation(..) => "a", + | Delegation(..) | DelegationMac(..) => "a", ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an", } } @@ -3280,6 +3304,7 @@ impl ItemKind { ItemKind::MacroDef(..) => "macro definition", ItemKind::Impl { .. } => "implementation", ItemKind::Delegation(..) => "delegated function", + ItemKind::DelegationMac(..) => "delegation", } } @@ -3323,6 +3348,8 @@ pub enum AssocItemKind { MacCall(P<MacCall>), /// An associated delegation item. Delegation(Box<Delegation>), + /// An associated delegation item list. + DelegationMac(Box<DelegationMac>), } impl AssocItemKind { @@ -3331,7 +3358,9 @@ impl AssocItemKind { Self::Const(box ConstItem { defaultness, .. }) | Self::Fn(box Fn { defaultness, .. }) | Self::Type(box TyAlias { defaultness, .. }) => defaultness, - Self::MacCall(..) | Self::Delegation(..) => Defaultness::Final, + Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => { + Defaultness::Final + } } } } @@ -3344,6 +3373,7 @@ impl From<AssocItemKind> for ItemKind { AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind), AssocItemKind::MacCall(a) => ItemKind::MacCall(a), AssocItemKind::Delegation(delegation) => ItemKind::Delegation(delegation), + AssocItemKind::DelegationMac(delegation) => ItemKind::DelegationMac(delegation), } } } @@ -3358,6 +3388,7 @@ impl TryFrom<ItemKind> for AssocItemKind { ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind), ItemKind::MacCall(a) => AssocItemKind::MacCall(a), ItemKind::Delegation(d) => AssocItemKind::Delegation(d), + ItemKind::DelegationMac(d) => AssocItemKind::DelegationMac(d), _ => return Err(item_kind), }) } diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index a0486227f2a..2cf811e9122 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -240,7 +240,6 @@ impl HasTokens for Nonterminal { Nonterminal::NtPath(path) => path.tokens(), Nonterminal::NtVis(vis) => vis.tokens(), Nonterminal::NtBlock(block) => block.tokens(), - Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None, } } fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> { @@ -254,7 +253,6 @@ impl HasTokens for Nonterminal { Nonterminal::NtPath(path) => path.tokens_mut(), Nonterminal::NtVis(vis) => vis.tokens_mut(), Nonterminal::NtBlock(block) => block.tokens_mut(), - Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None, } } } diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 0f12fd31975..0684163617f 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -345,7 +345,7 @@ impl MetaItem { let span = span.with_hi(segments.last().unwrap().ident.span.hi()); Path { span, segments, tokens: None } } - Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &nt.0 { + Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &**nt { token::Nonterminal::NtMeta(item) => return item.meta(item.path.span), token::Nonterminal::NtPath(path) => (**path).clone(), _ => return None, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 379c2e273eb..566b20c490e 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -499,8 +499,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) { vis.visit_mt(mt); } TyKind::BareFn(bft) => { - let BareFnTy { unsafety, ext: _, generic_params, decl, decl_span } = bft.deref_mut(); - visit_unsafety(unsafety, vis); + let BareFnTy { safety, ext: _, generic_params, decl, decl_span } = bft.deref_mut(); + visit_safety(safety, vis); generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_fn_decl(decl); vis.visit_span(decl_span); @@ -543,8 +543,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) { } fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) { - let ForeignMod { unsafety, abi: _, items } = foreign_mod; - visit_unsafety(unsafety, vis); + let ForeignMod { safety, abi: _, items } = foreign_mod; + visit_safety(safety, vis); items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); } @@ -781,10 +781,14 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) { *span = ident.span; return; // Avoid visiting the span for the second time. } + token::NtIdent(ident, _is_raw) => { + vis.visit_ident(ident); + } + token::NtLifetime(ident) => { + vis.visit_ident(ident); + } token::Interpolated(nt) => { let nt = Lrc::make_mut(nt); - let (nt, sp) = (&mut nt.0, &mut nt.1); - vis.visit_span(sp); visit_nonterminal(nt, vis); } _ => {} @@ -834,8 +838,6 @@ fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) { token::NtPat(pat) => vis.visit_pat(pat), token::NtExpr(expr) => vis.visit_expr(expr), token::NtTy(ty) => vis.visit_ty(ty), - token::NtIdent(ident, _is_raw) => vis.visit_ident(ident), - token::NtLifetime(ident) => vis.visit_ident(ident), token::NtLiteral(expr) => vis.visit_expr(expr), token::NtMeta(item) => { let AttrItem { path, args, tokens } = item.deref_mut(); @@ -857,10 +859,10 @@ fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut T) } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -fn visit_unsafety<T: MutVisitor>(unsafety: &mut Unsafe, vis: &mut T) { - match unsafety { - Unsafe::Yes(span) => vis.visit_span(span), - Unsafe::No => {} +fn visit_safety<T: MutVisitor>(safety: &mut Safety, vis: &mut T) { + match safety { + Safety::Unsafe(span) => vis.visit_span(span), + Safety::Default => {} } } @@ -1090,8 +1092,8 @@ impl NoopVisitItemKind for ItemKind { vis.visit_generics(generics); visit_opt(body, |body| vis.visit_block(body)); } - ItemKind::Mod(unsafety, mod_kind) => { - visit_unsafety(unsafety, vis); + ItemKind::Mod(safety, mod_kind) => { + visit_safety(safety, vis); match mod_kind { ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => { vis.visit_span(inner_span); @@ -1128,7 +1130,7 @@ impl NoopVisitItemKind for ItemKind { } ItemKind::Impl(box Impl { defaultness, - unsafety, + safety, generics, constness, polarity, @@ -1137,7 +1139,7 @@ impl NoopVisitItemKind for ItemKind { items, }) => { visit_defaultness(defaultness, vis); - visit_unsafety(unsafety, vis); + visit_safety(safety, vis); vis.visit_generics(generics); visit_constness(constness, vis); visit_polarity(polarity, vis); @@ -1145,8 +1147,8 @@ impl NoopVisitItemKind for ItemKind { vis.visit_ty(self_ty); items.flat_map_in_place(|item| vis.flat_map_impl_item(item)); } - ItemKind::Trait(box Trait { unsafety, is_auto: _, generics, bounds, items }) => { - visit_unsafety(unsafety, vis); + ItemKind::Trait(box Trait { safety, is_auto: _, generics, bounds, items }) => { + visit_safety(safety, vis); vis.visit_generics(generics); visit_bounds(bounds, vis); items.flat_map_in_place(|item| vis.flat_map_trait_item(item)); @@ -1168,6 +1170,19 @@ impl NoopVisitItemKind for ItemKind { vis.visit_block(body); } } + ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { + vis.visit_qself(qself); + vis.visit_path(prefix); + for (ident, rename) in suffixes { + vis.visit_ident(ident); + if let Some(rename) = rename { + vis.visit_ident(rename); + } + } + if let Some(body) = body { + vis.visit_block(body); + } + } } } } @@ -1211,6 +1226,19 @@ impl NoopVisitItemKind for AssocItemKind { visitor.visit_block(body); } } + AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { + visitor.visit_qself(qself); + visitor.visit_path(prefix); + for (ident, rename) in suffixes { + visitor.visit_ident(ident); + if let Some(rename) = rename { + visitor.visit_ident(rename); + } + } + if let Some(body) = body { + visitor.visit_block(body); + } + } } } } @@ -1226,10 +1254,10 @@ fn visit_const_item<T: MutVisitor>( } fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) { - let FnHeader { unsafety, coroutine_kind, constness, ext: _ } = header; + let FnHeader { safety, coroutine_kind, constness, ext: _ } = header; visit_constness(constness, vis); coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind)); - visit_unsafety(unsafety, vis); + visit_safety(safety, vis); } pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) { diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 72f89737f99..099a6096d0b 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -111,7 +111,7 @@ impl Lit { Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)), Literal(token_lit) => Some(token_lit), Interpolated(ref nt) - if let NtExpr(expr) | NtLiteral(expr) = &nt.0 + if let NtExpr(expr) | NtLiteral(expr) = &**nt && let ast::ExprKind::Lit(token_lit) = expr.kind => { Some(token_lit) @@ -318,11 +318,20 @@ pub enum TokenKind { /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to /// treat regular and interpolated identifiers in the same way. Ident(Symbol, IdentIsRaw), + /// This identifier (and its span) is the identifier passed to the + /// declarative macro. The span in the surrounding `Token` is the span of + /// the `ident` metavariable in the macro's RHS. + NtIdent(Ident, IdentIsRaw), + /// Lifetime identifier token. /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers. /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to /// treat regular and interpolated lifetime identifiers in the same way. Lifetime(Symbol), + /// This identifier (and its span) is the lifetime passed to the + /// declarative macro. The span in the surrounding `Token` is the span of + /// the `lifetime` metavariable in the macro's RHS. + NtLifetime(Ident), /// An embedded AST node, as produced by a macro. This only exists for /// historical reasons. We'd like to get rid of it, for multiple reasons. @@ -333,7 +342,11 @@ pub enum TokenKind { /// - It prevents `Token` from implementing `Copy`. /// It adds complexity and likely slows things down. Please don't add new /// occurrences of this token kind! - Interpolated(Lrc<(Nonterminal, Span)>), + /// + /// The span in the surrounding `Token` is that of the metavariable in the + /// macro's RHS. The span within the Nonterminal is that of the fragment + /// passed to the macro at the call site. + Interpolated(Lrc<Nonterminal>), /// A doc comment token. /// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc) @@ -440,8 +453,9 @@ impl Token { /// Note that keywords are also identifiers, so they should use this /// if they keep spans or perform edition checks. pub fn uninterpolated_span(&self) -> Span { - match &self.kind { - Interpolated(nt) => nt.0.use_span(), + match self.kind { + NtIdent(ident, _) | NtLifetime(ident) => ident.span, + Interpolated(ref nt) => nt.use_span(), _ => self.span, } } @@ -459,7 +473,7 @@ impl Token { } OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) - | Lifetime(..) | Interpolated(..) | Eof => false, + | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false, } } @@ -486,7 +500,7 @@ impl Token { PathSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes - Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) | + Interpolated(ref nt) => matches!(&**nt, NtLiteral(..) | NtExpr(..) | NtBlock(..) | NtPath(..)), @@ -510,7 +524,7 @@ impl Token { | DotDot | DotDotDot | DotDotEq // ranges | Lt | BinOp(Shl) // associated path | PathSep => true, // global path - Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) | + Interpolated(ref nt) => matches!(&**nt, NtLiteral(..) | NtPat(..) | NtBlock(..) | NtPath(..)), @@ -533,7 +547,7 @@ impl Token { Lifetime(..) | // lifetime bound in trait object Lt | BinOp(Shl) | // associated path PathSep => true, // global path - Interpolated(ref nt) => matches!(&nt.0, NtTy(..) | NtPath(..)), + Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)), // For anonymous structs or unions, which only appear in specific positions // (type of struct fields or union fields), we don't consider them as regular types _ => false, @@ -544,7 +558,7 @@ impl Token { pub fn can_begin_const_arg(&self) -> bool { match self.kind { OpenDelim(Delimiter::Brace) => true, - Interpolated(ref nt) => matches!(&nt.0, NtExpr(..) | NtBlock(..) | NtLiteral(..)), + Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)), _ => self.can_begin_literal_maybe_minus(), } } @@ -589,7 +603,7 @@ impl Token { match self.uninterpolate().kind { Literal(..) | BinOp(Minus) => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, - Interpolated(ref nt) => match &nt.0 { + Interpolated(ref nt) => match &**nt { NtLiteral(_) => true, NtExpr(e) => match &e.kind { ast::ExprKind::Lit(_) => true, @@ -609,14 +623,9 @@ impl Token { /// into the regular identifier or lifetime token it refers to, /// otherwise returns the original token. pub fn uninterpolate(&self) -> Cow<'_, Token> { - match &self.kind { - Interpolated(nt) => match &nt.0 { - NtIdent(ident, is_raw) => { - Cow::Owned(Token::new(Ident(ident.name, *is_raw), ident.span)) - } - NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)), - _ => Cow::Borrowed(self), - }, + match self.kind { + NtIdent(ident, is_raw) => Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span)), + NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)), _ => Cow::Borrowed(self), } } @@ -625,12 +634,9 @@ impl Token { #[inline] pub fn ident(&self) -> Option<(Ident, IdentIsRaw)> { // We avoid using `Token::uninterpolate` here because it's slow. - match &self.kind { - &Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)), - Interpolated(nt) => match &nt.0 { - NtIdent(ident, is_raw) => Some((*ident, *is_raw)), - _ => None, - }, + match self.kind { + Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)), + NtIdent(ident, is_raw) => Some((ident, is_raw)), _ => None, } } @@ -639,12 +645,9 @@ impl Token { #[inline] pub fn lifetime(&self) -> Option<Ident> { // We avoid using `Token::uninterpolate` here because it's slow. - match &self.kind { - &Lifetime(name) => Some(Ident::new(name, self.span)), - Interpolated(nt) => match &nt.0 { - NtLifetime(ident) => Some(*ident), - _ => None, - }, + match self.kind { + Lifetime(name) => Some(Ident::new(name, self.span)), + NtLifetime(ident) => Some(ident), _ => None, } } @@ -668,7 +671,7 @@ impl Token { /// Returns `true` if the token is an interpolated path. fn is_whole_path(&self) -> bool { if let Interpolated(nt) = &self.kind - && let NtPath(..) = &nt.0 + && let NtPath(..) = &**nt { return true; } @@ -681,7 +684,7 @@ impl Token { /// (which happens while parsing the result of macro expansion)? pub fn is_whole_expr(&self) -> bool { if let Interpolated(nt) = &self.kind - && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &nt.0 + && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &**nt { return true; } @@ -692,7 +695,7 @@ impl Token { /// Is the token an interpolated block (`$b:block`)? pub fn is_whole_block(&self) -> bool { if let Interpolated(nt) = &self.kind - && let NtBlock(..) = &nt.0 + && let NtBlock(..) = &**nt { return true; } @@ -833,8 +836,10 @@ impl Token { Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotDotEq | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar - | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) - | Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None, + | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..) + | Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof => { + return None; + } }; Some(Token::new(kind, self.span.to(joint.span))) @@ -857,8 +862,6 @@ pub enum Nonterminal { NtPat(P<ast::Pat>), NtExpr(P<ast::Expr>), NtTy(P<ast::Ty>), - NtIdent(Ident, IdentIsRaw), - NtLifetime(Ident), NtLiteral(P<ast::Expr>), /// Stuff inside brackets for attributes NtMeta(P<ast::AttrItem>), @@ -878,6 +881,8 @@ pub enum NonterminalKind { }, PatWithOr, Expr, + /// Matches an expression using the rules from edition 2021 and earlier. + Expr2021, Ty, Ident, Lifetime, @@ -907,6 +912,7 @@ impl NonterminalKind { }, sym::pat_param => NonterminalKind::PatParam { inferred: false }, sym::expr => NonterminalKind::Expr, + sym::expr_2021 if edition().at_least_rust_2021() => NonterminalKind::Expr2021, sym::ty => NonterminalKind::Ty, sym::ident => NonterminalKind::Ident, sym::lifetime => NonterminalKind::Lifetime, @@ -926,6 +932,7 @@ impl NonterminalKind { NonterminalKind::PatParam { inferred: false } => sym::pat_param, NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat, NonterminalKind::Expr => sym::expr, + NonterminalKind::Expr2021 => sym::expr_2021, NonterminalKind::Ty => sym::ty, NonterminalKind::Ident => sym::ident, NonterminalKind::Lifetime => sym::lifetime, @@ -953,7 +960,6 @@ impl Nonterminal { NtPat(pat) => pat.span, NtExpr(expr) | NtLiteral(expr) => expr.span, NtTy(ty) => ty.span, - NtIdent(ident, _) | NtLifetime(ident) => ident.span, NtMeta(attr_item) => attr_item.span(), NtPath(path) => path.span, NtVis(vis) => vis.span, @@ -969,8 +975,6 @@ impl Nonterminal { NtExpr(..) => "expression", NtLiteral(..) => "literal", NtTy(..) => "type", - NtIdent(..) => "identifier", - NtLifetime(..) => "lifetime", NtMeta(..) => "attribute", NtPath(..) => "path", NtVis(..) => "visibility", @@ -979,18 +983,12 @@ impl Nonterminal { } impl PartialEq for Nonterminal { - fn eq(&self, rhs: &Self) -> bool { - match (self, rhs) { - (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => { - ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs - } - (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs, - // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them - // correctly based on data from AST. This will prevent them from matching each other - // in macros. The comparison will become possible only when each nonterminal has an - // attached token stream from which it was parsed. - _ => false, - } + fn eq(&self, _rhs: &Self) -> bool { + // FIXME: Assume that all nonterminals are not equal, we can't compare them + // correctly based on data from AST. This will prevent them from matching each other + // in macros. The comparison will become possible only when each nonterminal has an + // attached token stream from which it was parsed. + false } } @@ -1003,12 +1001,10 @@ impl fmt::Debug for Nonterminal { NtPat(..) => f.pad("NtPat(..)"), NtExpr(..) => f.pad("NtExpr(..)"), NtTy(..) => f.pad("NtTy(..)"), - NtIdent(..) => f.pad("NtIdent(..)"), NtLiteral(..) => f.pad("NtLiteral(..)"), NtMeta(..) => f.pad("NtMeta(..)"), NtPath(..) => f.pad("NtPath(..)"), NtVis(..) => f.pad("NtVis(..)"), - NtLifetime(..) => f.pad("NtLifetime(..)"), } } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 8e80161af1b..fb666550e93 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -466,12 +466,6 @@ impl TokenStream { pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { match nt { - Nonterminal::NtIdent(ident, is_raw) => { - TokenStream::token_alone(token::Ident(ident.name, *is_raw), ident.span) - } - Nonterminal::NtLifetime(ident) => { - TokenStream::token_alone(token::Lifetime(ident.name), ident.span) - } Nonterminal::NtItem(item) => TokenStream::from_ast(item), Nonterminal::NtBlock(block) => TokenStream::from_ast(block), Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => { @@ -489,15 +483,21 @@ impl TokenStream { } fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree { - match &token.kind { - token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = nt.0 => { + match token.kind { + token::NtIdent(ident, is_raw) => { TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing) } - token::Interpolated(nt) => TokenTree::Delimited( + token::NtLifetime(ident) => TokenTree::Delimited( + DelimSpan::from_single(token.span), + DelimSpacing::new(Spacing::JointHidden, spacing), + Delimiter::Invisible, + TokenStream::token_alone(token::Lifetime(ident.name), ident.span), + ), + token::Interpolated(ref nt) => TokenTree::Delimited( DelimSpan::from_single(token.span), DelimSpacing::new(Spacing::JointHidden, spacing), Delimiter::Invisible, - TokenStream::from_nonterminal_ast(&nt.0).flattened(), + TokenStream::from_nonterminal_ast(&nt).flattened(), ), _ => TokenTree::Token(token.clone(), spacing), } @@ -516,7 +516,10 @@ impl TokenStream { pub fn flattened(&self) -> TokenStream { fn can_skip(stream: &TokenStream) -> bool { stream.trees().all(|tree| match tree { - TokenTree::Token(token, _) => !matches!(token.kind, token::Interpolated(_)), + TokenTree::Token(token, _) => !matches!( + token.kind, + token::NtIdent(..) | token::NtLifetime(..) | token::Interpolated(..) + ), TokenTree::Delimited(.., inner) => can_skip(inner), }) } diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index f21a9cabb81..f6e9e1a87c4 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -1,34 +1,88 @@ -//! Routines the parser uses to classify AST nodes - -// Predicates on exprs and stmts that the pretty-printer and parser use +//! Routines the parser and pretty-printer use to classify AST nodes. +use crate::ast::ExprKind::*; use crate::{ast, token::Delimiter}; -/// Does this expression require a semicolon to be treated -/// as a statement? The negation of this: 'can this expression -/// be used as a statement without a semicolon' -- is used -/// as an early-bail-out in the parser so that, for instance, -/// if true {...} else {...} -/// |x| 5 -/// isn't parsed as (if true {...} else {...} | x) | 5 -pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { - !matches!( +/// This classification determines whether various syntactic positions break out +/// of parsing the current expression (true) or continue parsing more of the +/// same expression (false). +/// +/// For example, it's relevant in the parsing of match arms: +/// +/// ```ignore (illustrative) +/// match ... { +/// // Is this calling $e as a function, or is it the start of a new arm +/// // with a tuple pattern? +/// _ => $e ( +/// ^ ) +/// +/// // Is this an Index operation, or new arm with a slice pattern? +/// _ => $e [ +/// ^ ] +/// +/// // Is this a binary operator, or leading vert in a new arm? Same for +/// // other punctuation which can either be a binary operator in +/// // expression or unary operator in pattern, such as `&` and `-`. +/// _ => $e | +/// ^ +/// } +/// ``` +/// +/// If $e is something like `{}` or `if … {}`, then terminate the current +/// arm and parse a new arm. +/// +/// If $e is something like `path::to` or `(…)`, continue parsing the same +/// arm. +/// +/// *Almost* the same classification is used as an early bail-out for parsing +/// statements. See `expr_requires_semi_to_be_stmt`. +pub fn expr_is_complete(e: &ast::Expr) -> bool { + matches!( e.kind, - ast::ExprKind::If(..) - | ast::ExprKind::Match(..) - | ast::ExprKind::Block(..) - | ast::ExprKind::While(..) - | ast::ExprKind::Loop(..) - | ast::ExprKind::ForLoop { .. } - | ast::ExprKind::TryBlock(..) - | ast::ExprKind::ConstBlock(..) + If(..) + | Match(..) + | Block(..) + | While(..) + | Loop(..) + | ForLoop { .. } + | TryBlock(..) + | ConstBlock(..) ) } +/// Does this expression require a semicolon to be treated as a statement? +/// +/// The negation of this: "can this expression be used as a statement without a +/// semicolon" -- is used as an early bail-out when parsing statements so that, +/// for instance, +/// +/// ```ignore (illustrative) +/// if true {...} else {...} +/// |x| 5 +/// ``` +/// +/// isn't parsed as `(if true {...} else {...} | x) | 5`. +/// +/// Surprising special case: even though braced macro calls like `m! {}` +/// normally do not introduce a boundary when found at the head of a match arm, +/// they do terminate the parsing of a statement. +/// +/// ```ignore (illustrative) +/// match ... { +/// _ => m! {} (), // macro that expands to a function, which is then called +/// } +/// +/// let _ = { m! {} () }; // macro call followed by unit +/// ``` +pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { + match &e.kind { + MacCall(mac_call) => mac_call.args.delim != Delimiter::Brace, + _ => !expr_is_complete(e), + } +} + /// If an expression ends with `}`, returns the innermost expression ending in the `}` pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> { - use ast::ExprKind::*; - loop { match &expr.kind { AddrOf(_, _, e) diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d36193ef7b0..93de42b55cc 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -366,7 +366,7 @@ impl WalkItemKind for ItemKind { } ItemKind::Impl(box Impl { defaultness: _, - unsafety: _, + safety: _, generics, constness: _, polarity: _, @@ -384,7 +384,7 @@ impl WalkItemKind for ItemKind { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_variant_data(struct_definition)); } - ItemKind::Trait(box Trait { unsafety: _, is_auto: _, generics, bounds, items }) => { + ItemKind::Trait(box Trait { safety: _, is_auto: _, generics, bounds, items }) => { try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds, BoundKind::SuperTraits); walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait); @@ -403,6 +403,19 @@ impl WalkItemKind for ItemKind { visit_opt!(visitor, visit_ident, *rename); visit_opt!(visitor, visit_block, body); } + ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { + if let Some(qself) = qself { + try_visit!(visitor.visit_ty(&qself.ty)); + } + try_visit!(visitor.visit_path(prefix, item.id)); + for (ident, rename) in suffixes { + visitor.visit_ident(*ident); + if let Some(rename) = rename { + visitor.visit_ident(*rename); + } + } + visit_opt!(visitor, visit_block, body); + } } V::Result::output() } @@ -815,6 +828,19 @@ impl WalkItemKind for AssocItemKind { visit_opt!(visitor, visit_ident, *rename); visit_opt!(visitor, visit_block, body); } + AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { + if let Some(qself) = qself { + try_visit!(visitor.visit_ty(&qself.ty)); + } + try_visit!(visitor.visit_path(prefix, item.id)); + for (ident, rename) in suffixes { + visitor.visit_ident(*ident); + if let Some(rename) = rename { + visitor.visit_ident(*rename); + } + } + visit_opt!(visitor, visit_block, body); + } } V::Result::output() } |
