]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast/src/token.rs
Rollup merge of #77739 - est31:remove_unused_code, r=petrochenkov,varkor
[rust.git] / compiler / rustc_ast / src / token.rs
1 pub use BinOpToken::*;
2 pub use DelimToken::*;
3 pub use LitKind::*;
4 pub use Nonterminal::*;
5 pub use TokenKind::*;
6
7 use crate::ast;
8 use crate::ptr::P;
9 use crate::tokenstream::TokenTree;
10
11 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
12 use rustc_data_structures::sync::Lrc;
13 use rustc_macros::HashStable_Generic;
14 use rustc_span::hygiene::ExpnKind;
15 use rustc_span::source_map::SourceMap;
16 use rustc_span::symbol::{kw, sym};
17 use rustc_span::symbol::{Ident, Symbol};
18 use rustc_span::{self, FileName, RealFileName, Span, DUMMY_SP};
19 use std::borrow::Cow;
20 use std::{fmt, mem};
21
22 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
23 pub enum CommentKind {
24     Line,
25     Block,
26 }
27
28 #[derive(Clone, PartialEq, Encodable, Decodable, Hash, Debug, Copy)]
29 #[derive(HashStable_Generic)]
30 pub enum BinOpToken {
31     Plus,
32     Minus,
33     Star,
34     Slash,
35     Percent,
36     Caret,
37     And,
38     Or,
39     Shl,
40     Shr,
41 }
42
43 /// A delimiter token.
44 #[derive(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug, Copy)]
45 #[derive(HashStable_Generic)]
46 pub enum DelimToken {
47     /// A round parenthesis (i.e., `(` or `)`).
48     Paren,
49     /// A square bracket (i.e., `[` or `]`).
50     Bracket,
51     /// A curly brace (i.e., `{` or `}`).
52     Brace,
53     /// An empty delimiter.
54     NoDelim,
55 }
56
57 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
58 pub enum LitKind {
59     Bool, // AST only, must never appear in a `Token`
60     Byte,
61     Char,
62     Integer,
63     Float,
64     Str,
65     StrRaw(u16), // raw string delimited by `n` hash symbols
66     ByteStr,
67     ByteStrRaw(u16), // raw byte string delimited by `n` hash symbols
68     Err,
69 }
70
71 /// A literal token.
72 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
73 pub struct Lit {
74     pub kind: LitKind,
75     pub symbol: Symbol,
76     pub suffix: Option<Symbol>,
77 }
78
79 impl fmt::Display for Lit {
80     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81         let Lit { kind, symbol, suffix } = *self;
82         match kind {
83             Byte => write!(f, "b'{}'", symbol)?,
84             Char => write!(f, "'{}'", symbol)?,
85             Str => write!(f, "\"{}\"", symbol)?,
86             StrRaw(n) => write!(
87                 f,
88                 "r{delim}\"{string}\"{delim}",
89                 delim = "#".repeat(n as usize),
90                 string = symbol
91             )?,
92             ByteStr => write!(f, "b\"{}\"", symbol)?,
93             ByteStrRaw(n) => write!(
94                 f,
95                 "br{delim}\"{string}\"{delim}",
96                 delim = "#".repeat(n as usize),
97                 string = symbol
98             )?,
99             Integer | Float | Bool | Err => write!(f, "{}", symbol)?,
100         }
101
102         if let Some(suffix) = suffix {
103             write!(f, "{}", suffix)?;
104         }
105
106         Ok(())
107     }
108 }
109
110 impl LitKind {
111     /// An English article for the literal token kind.
112     pub fn article(self) -> &'static str {
113         match self {
114             Integer | Err => "an",
115             _ => "a",
116         }
117     }
118
119     pub fn descr(self) -> &'static str {
120         match self {
121             Bool => panic!("literal token contains `Lit::Bool`"),
122             Byte => "byte",
123             Char => "char",
124             Integer => "integer",
125             Float => "float",
126             Str | StrRaw(..) => "string",
127             ByteStr | ByteStrRaw(..) => "byte string",
128             Err => "error",
129         }
130     }
131
132     crate fn may_have_suffix(self) -> bool {
133         match self {
134             Integer | Float | Err => true,
135             _ => false,
136         }
137     }
138 }
139
140 impl Lit {
141     pub fn new(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Lit {
142         Lit { kind, symbol, suffix }
143     }
144 }
145
146 pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
147     let ident_token = Token::new(Ident(name, is_raw), span);
148
149     !ident_token.is_reserved_ident()
150         || ident_token.is_path_segment_keyword()
151         || [
152             kw::Async,
153             kw::Do,
154             kw::Box,
155             kw::Break,
156             kw::Continue,
157             kw::False,
158             kw::For,
159             kw::If,
160             kw::Let,
161             kw::Loop,
162             kw::Match,
163             kw::Move,
164             kw::Return,
165             kw::True,
166             kw::Try,
167             kw::Unsafe,
168             kw::While,
169             kw::Yield,
170             kw::Static,
171         ]
172         .contains(&name)
173 }
174
175 fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool {
176     let ident_token = Token::new(Ident(name, is_raw), span);
177
178     !ident_token.is_reserved_ident()
179         || ident_token.is_path_segment_keyword()
180         || [kw::Underscore, kw::For, kw::Impl, kw::Fn, kw::Unsafe, kw::Extern, kw::Typeof, kw::Dyn]
181             .contains(&name)
182 }
183
184 #[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
185 pub enum TokenKind {
186     /* Expression-operator symbols. */
187     Eq,
188     Lt,
189     Le,
190     EqEq,
191     Ne,
192     Ge,
193     Gt,
194     AndAnd,
195     OrOr,
196     Not,
197     Tilde,
198     BinOp(BinOpToken),
199     BinOpEq(BinOpToken),
200
201     /* Structural symbols */
202     At,
203     Dot,
204     DotDot,
205     DotDotDot,
206     DotDotEq,
207     Comma,
208     Semi,
209     Colon,
210     ModSep,
211     RArrow,
212     LArrow,
213     FatArrow,
214     Pound,
215     Dollar,
216     Question,
217     /// Used by proc macros for representing lifetimes, not generated by lexer right now.
218     SingleQuote,
219     /// An opening delimiter (e.g., `{`).
220     OpenDelim(DelimToken),
221     /// A closing delimiter (e.g., `}`).
222     CloseDelim(DelimToken),
223
224     /* Literals */
225     Literal(Lit),
226
227     /// Identifier token.
228     /// Do not forget about `NtIdent` when you want to match on identifiers.
229     /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
230     /// treat regular and interpolated identifiers in the same way.
231     Ident(Symbol, /* is_raw */ bool),
232     /// Lifetime identifier token.
233     /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
234     /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
235     /// treat regular and interpolated lifetime identifiers in the same way.
236     Lifetime(Symbol),
237
238     Interpolated(Lrc<Nonterminal>),
239
240     /// A doc comment token.
241     /// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
242     /// similarly to symbols in string literal tokens.
243     DocComment(CommentKind, ast::AttrStyle, Symbol),
244
245     Eof,
246 }
247
248 // `TokenKind` is used a lot. Make sure it doesn't unintentionally get bigger.
249 #[cfg(target_arch = "x86_64")]
250 rustc_data_structures::static_assert_size!(TokenKind, 16);
251
252 #[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
253 pub struct Token {
254     pub kind: TokenKind,
255     pub span: Span,
256 }
257
258 impl TokenKind {
259     pub fn lit(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> TokenKind {
260         Literal(Lit::new(kind, symbol, suffix))
261     }
262
263     // An approximation to proc-macro-style single-character operators used by rustc parser.
264     // If the operator token can be broken into two tokens, the first of which is single-character,
265     // then this function performs that operation, otherwise it returns `None`.
266     pub fn break_two_token_op(&self) -> Option<(TokenKind, TokenKind)> {
267         Some(match *self {
268             Le => (Lt, Eq),
269             EqEq => (Eq, Eq),
270             Ne => (Not, Eq),
271             Ge => (Gt, Eq),
272             AndAnd => (BinOp(And), BinOp(And)),
273             OrOr => (BinOp(Or), BinOp(Or)),
274             BinOp(Shl) => (Lt, Lt),
275             BinOp(Shr) => (Gt, Gt),
276             BinOpEq(Plus) => (BinOp(Plus), Eq),
277             BinOpEq(Minus) => (BinOp(Minus), Eq),
278             BinOpEq(Star) => (BinOp(Star), Eq),
279             BinOpEq(Slash) => (BinOp(Slash), Eq),
280             BinOpEq(Percent) => (BinOp(Percent), Eq),
281             BinOpEq(Caret) => (BinOp(Caret), Eq),
282             BinOpEq(And) => (BinOp(And), Eq),
283             BinOpEq(Or) => (BinOp(Or), Eq),
284             BinOpEq(Shl) => (Lt, Le),
285             BinOpEq(Shr) => (Gt, Ge),
286             DotDot => (Dot, Dot),
287             DotDotDot => (Dot, DotDot),
288             ModSep => (Colon, Colon),
289             RArrow => (BinOp(Minus), Gt),
290             LArrow => (Lt, BinOp(Minus)),
291             FatArrow => (Eq, Gt),
292             _ => return None,
293         })
294     }
295
296     /// Returns tokens that are likely to be typed accidentally instead of the current token.
297     /// Enables better error recovery when the wrong token is found.
298     pub fn similar_tokens(&self) -> Option<Vec<TokenKind>> {
299         match *self {
300             Comma => Some(vec![Dot, Lt, Semi]),
301             Semi => Some(vec![Colon, Comma]),
302             _ => None,
303         }
304     }
305 }
306
307 impl Token {
308     pub fn new(kind: TokenKind, span: Span) -> Self {
309         Token { kind, span }
310     }
311
312     /// Some token that will be thrown away later.
313     pub fn dummy() -> Self {
314         Token::new(TokenKind::Question, DUMMY_SP)
315     }
316
317     /// Recovers a `Token` from an `Ident`. This creates a raw identifier if necessary.
318     pub fn from_ast_ident(ident: Ident) -> Self {
319         Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span)
320     }
321
322     /// Return this token by value and leave a dummy token in its place.
323     pub fn take(&mut self) -> Self {
324         mem::replace(self, Token::dummy())
325     }
326
327     /// For interpolated tokens, returns a span of the fragment to which the interpolated
328     /// token refers. For all other tokens this is just a regular span.
329     /// It is particularly important to use this for identifiers and lifetimes
330     /// for which spans affect name resolution and edition checks.
331     /// Note that keywords are also identifiers, so they should use this
332     /// if they keep spans or perform edition checks.
333     pub fn uninterpolated_span(&self) -> Span {
334         match &self.kind {
335             Interpolated(nt) => nt.span(),
336             _ => self.span,
337         }
338     }
339
340     pub fn is_op(&self) -> bool {
341         match self.kind {
342             OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
343             | Lifetime(..) | Interpolated(..) | Eof => false,
344             _ => true,
345         }
346     }
347
348     pub fn is_like_plus(&self) -> bool {
349         match self.kind {
350             BinOp(Plus) | BinOpEq(Plus) => true,
351             _ => false,
352         }
353     }
354
355     /// Returns `true` if the token can appear at the start of an expression.
356     pub fn can_begin_expr(&self) -> bool {
357         match self.uninterpolate().kind {
358             Ident(name, is_raw)              =>
359                 ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
360             OpenDelim(..)                     | // tuple, array or block
361             Literal(..)                       | // literal
362             Not                               | // operator not
363             BinOp(Minus)                      | // unary minus
364             BinOp(Star)                       | // dereference
365             BinOp(Or) | OrOr                  | // closure
366             BinOp(And)                        | // reference
367             AndAnd                            | // double reference
368             // DotDotDot is no longer supported, but we need some way to display the error
369             DotDot | DotDotDot | DotDotEq     | // range notation
370             Lt | BinOp(Shl)                   | // associated path
371             ModSep                            | // global path
372             Lifetime(..)                      | // labeled loop
373             Pound                             => true, // expression attributes
374             Interpolated(ref nt) => match **nt {
375                 NtLiteral(..) |
376                 NtExpr(..)    |
377                 NtBlock(..)   |
378                 NtPath(..) => true,
379                 _ => false,
380             },
381             _ => false,
382         }
383     }
384
385     /// Returns `true` if the token can appear at the start of a type.
386     pub fn can_begin_type(&self) -> bool {
387         match self.uninterpolate().kind {
388             Ident(name, is_raw)        =>
389                 ident_can_begin_type(name, self.span, is_raw), // type name or keyword
390             OpenDelim(Paren)            | // tuple
391             OpenDelim(Bracket)          | // array
392             Not                         | // never
393             BinOp(Star)                 | // raw pointer
394             BinOp(And)                  | // reference
395             AndAnd                      | // double reference
396             Question                    | // maybe bound in trait object
397             Lifetime(..)                | // lifetime bound in trait object
398             Lt | BinOp(Shl)             | // associated path
399             ModSep                      => true, // global path
400             Interpolated(ref nt) => match **nt {
401                 NtTy(..) | NtPath(..) => true,
402                 _ => false,
403             },
404             _ => false,
405         }
406     }
407
408     /// Returns `true` if the token can appear at the start of a const param.
409     pub fn can_begin_const_arg(&self) -> bool {
410         match self.kind {
411             OpenDelim(Brace) => true,
412             Interpolated(ref nt) => match **nt {
413                 NtExpr(..) | NtBlock(..) | NtLiteral(..) => true,
414                 _ => false,
415             },
416             _ => self.can_begin_literal_maybe_minus(),
417         }
418     }
419
420     /// Returns `true` if the token can appear at the start of a generic bound.
421     pub fn can_begin_bound(&self) -> bool {
422         self.is_path_start()
423             || self.is_lifetime()
424             || self.is_keyword(kw::For)
425             || self == &Question
426             || self == &OpenDelim(Paren)
427     }
428
429     /// Returns `true` if the token is any literal
430     pub fn is_lit(&self) -> bool {
431         match self.kind {
432             Literal(..) => true,
433             _ => false,
434         }
435     }
436
437     /// Returns `true` if the token is any literal, a minus (which can prefix a literal,
438     /// for example a '-42', or one of the boolean idents).
439     ///
440     /// In other words, would this token be a valid start of `parse_literal_maybe_minus`?
441     ///
442     /// Keep this in sync with and `Lit::from_token`, excluding unary negation.
443     pub fn can_begin_literal_maybe_minus(&self) -> bool {
444         match self.uninterpolate().kind {
445             Literal(..) | BinOp(Minus) => true,
446             Ident(name, false) if name.is_bool_lit() => true,
447             Interpolated(ref nt) => match &**nt {
448                 NtLiteral(_) => true,
449                 NtExpr(e) => match &e.kind {
450                     ast::ExprKind::Lit(_) => true,
451                     ast::ExprKind::Unary(ast::UnOp::Neg, e) => {
452                         matches!(&e.kind, ast::ExprKind::Lit(_))
453                     }
454                     _ => false,
455                 },
456                 _ => false,
457             },
458             _ => false,
459         }
460     }
461
462     // A convenience function for matching on identifiers during parsing.
463     // Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token
464     // into the regular identifier or lifetime token it refers to,
465     // otherwise returns the original token.
466     pub fn uninterpolate(&self) -> Cow<'_, Token> {
467         match &self.kind {
468             Interpolated(nt) => match **nt {
469                 NtIdent(ident, is_raw) => {
470                     Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
471                 }
472                 NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
473                 _ => Cow::Borrowed(self),
474             },
475             _ => Cow::Borrowed(self),
476         }
477     }
478
479     /// Returns an identifier if this token is an identifier.
480     pub fn ident(&self) -> Option<(Ident, /* is_raw */ bool)> {
481         let token = self.uninterpolate();
482         match token.kind {
483             Ident(name, is_raw) => Some((Ident::new(name, token.span), is_raw)),
484             _ => None,
485         }
486     }
487
488     /// Returns a lifetime identifier if this token is a lifetime.
489     pub fn lifetime(&self) -> Option<Ident> {
490         let token = self.uninterpolate();
491         match token.kind {
492             Lifetime(name) => Some(Ident::new(name, token.span)),
493             _ => None,
494         }
495     }
496
497     /// Returns `true` if the token is an identifier.
498     pub fn is_ident(&self) -> bool {
499         self.ident().is_some()
500     }
501
502     /// Returns `true` if the token is a lifetime.
503     pub fn is_lifetime(&self) -> bool {
504         self.lifetime().is_some()
505     }
506
507     /// Returns `true` if the token is a identifier whose name is the given
508     /// string slice.
509     pub fn is_ident_named(&self, name: Symbol) -> bool {
510         self.ident().map_or(false, |(ident, _)| ident.name == name)
511     }
512
513     /// Returns `true` if the token is an interpolated path.
514     fn is_path(&self) -> bool {
515         if let Interpolated(ref nt) = self.kind {
516             if let NtPath(..) = **nt {
517                 return true;
518             }
519         }
520         false
521     }
522
523     /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`?
524     /// That is, is this a pre-parsed expression dropped into the token stream
525     /// (which happens while parsing the result of macro expansion)?
526     pub fn is_whole_expr(&self) -> bool {
527         if let Interpolated(ref nt) = self.kind {
528             if let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt {
529                 return true;
530             }
531         }
532
533         false
534     }
535
536     // Is the token an interpolated block (`$b:block`)?
537     pub fn is_whole_block(&self) -> bool {
538         if let Interpolated(ref nt) = self.kind {
539             if let NtBlock(..) = **nt {
540                 return true;
541             }
542         }
543         false
544     }
545
546     /// Returns `true` if the token is either the `mut` or `const` keyword.
547     pub fn is_mutability(&self) -> bool {
548         self.is_keyword(kw::Mut) || self.is_keyword(kw::Const)
549     }
550
551     pub fn is_qpath_start(&self) -> bool {
552         self == &Lt || self == &BinOp(Shl)
553     }
554
555     pub fn is_path_start(&self) -> bool {
556         self == &ModSep
557             || self.is_qpath_start()
558             || self.is_path()
559             || self.is_path_segment_keyword()
560             || self.is_ident() && !self.is_reserved_ident()
561     }
562
563     /// Returns `true` if the token is a given keyword, `kw`.
564     pub fn is_keyword(&self, kw: Symbol) -> bool {
565         self.is_non_raw_ident_where(|id| id.name == kw)
566     }
567
568     pub fn is_path_segment_keyword(&self) -> bool {
569         self.is_non_raw_ident_where(Ident::is_path_segment_keyword)
570     }
571
572     // Returns true for reserved identifiers used internally for elided lifetimes,
573     // unnamed method parameters, crate root module, error recovery etc.
574     pub fn is_special_ident(&self) -> bool {
575         self.is_non_raw_ident_where(Ident::is_special)
576     }
577
578     /// Returns `true` if the token is a keyword used in the language.
579     pub fn is_used_keyword(&self) -> bool {
580         self.is_non_raw_ident_where(Ident::is_used_keyword)
581     }
582
583     /// Returns `true` if the token is a keyword reserved for possible future use.
584     pub fn is_unused_keyword(&self) -> bool {
585         self.is_non_raw_ident_where(Ident::is_unused_keyword)
586     }
587
588     /// Returns `true` if the token is either a special identifier or a keyword.
589     pub fn is_reserved_ident(&self) -> bool {
590         self.is_non_raw_ident_where(Ident::is_reserved)
591     }
592
593     /// Returns `true` if the token is the identifier `true` or `false`.
594     pub fn is_bool_lit(&self) -> bool {
595         self.is_non_raw_ident_where(|id| id.name.is_bool_lit())
596     }
597
598     /// Returns `true` if the token is a non-raw identifier for which `pred` holds.
599     pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool {
600         match self.ident() {
601             Some((id, false)) => pred(id),
602             _ => false,
603         }
604     }
605
606     pub fn glue(&self, joint: &Token) -> Option<Token> {
607         let kind = match self.kind {
608             Eq => match joint.kind {
609                 Eq => EqEq,
610                 Gt => FatArrow,
611                 _ => return None,
612             },
613             Lt => match joint.kind {
614                 Eq => Le,
615                 Lt => BinOp(Shl),
616                 Le => BinOpEq(Shl),
617                 BinOp(Minus) => LArrow,
618                 _ => return None,
619             },
620             Gt => match joint.kind {
621                 Eq => Ge,
622                 Gt => BinOp(Shr),
623                 Ge => BinOpEq(Shr),
624                 _ => return None,
625             },
626             Not => match joint.kind {
627                 Eq => Ne,
628                 _ => return None,
629             },
630             BinOp(op) => match joint.kind {
631                 Eq => BinOpEq(op),
632                 BinOp(And) if op == And => AndAnd,
633                 BinOp(Or) if op == Or => OrOr,
634                 Gt if op == Minus => RArrow,
635                 _ => return None,
636             },
637             Dot => match joint.kind {
638                 Dot => DotDot,
639                 DotDot => DotDotDot,
640                 _ => return None,
641             },
642             DotDot => match joint.kind {
643                 Dot => DotDotDot,
644                 Eq => DotDotEq,
645                 _ => return None,
646             },
647             Colon => match joint.kind {
648                 Colon => ModSep,
649                 _ => return None,
650             },
651             SingleQuote => match joint.kind {
652                 Ident(name, false) => Lifetime(Symbol::intern(&format!("'{}", name))),
653                 _ => return None,
654             },
655
656             Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
657             | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar
658             | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..)
659             | Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None,
660         };
661
662         Some(Token::new(kind, self.span.to(joint.span)))
663     }
664 }
665
666 impl PartialEq<TokenKind> for Token {
667     fn eq(&self, rhs: &TokenKind) -> bool {
668         self.kind == *rhs
669     }
670 }
671
672 #[derive(Clone, Encodable, Decodable)]
673 /// For interpolation during macro expansion.
674 pub enum Nonterminal {
675     NtItem(P<ast::Item>),
676     NtBlock(P<ast::Block>),
677     NtStmt(ast::Stmt),
678     NtPat(P<ast::Pat>),
679     NtExpr(P<ast::Expr>),
680     NtTy(P<ast::Ty>),
681     NtIdent(Ident, /* is_raw */ bool),
682     NtLifetime(Ident),
683     NtLiteral(P<ast::Expr>),
684     /// Stuff inside brackets for attributes
685     NtMeta(P<ast::AttrItem>),
686     NtPath(ast::Path),
687     NtVis(ast::Visibility),
688     NtTT(TokenTree),
689 }
690
691 // `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger.
692 #[cfg(target_arch = "x86_64")]
693 rustc_data_structures::static_assert_size!(Nonterminal, 48);
694
695 #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
696 pub enum NonterminalKind {
697     Item,
698     Block,
699     Stmt,
700     Pat,
701     Expr,
702     Ty,
703     Ident,
704     Lifetime,
705     Literal,
706     Meta,
707     Path,
708     Vis,
709     TT,
710 }
711
712 impl NonterminalKind {
713     pub fn from_symbol(symbol: Symbol) -> Option<NonterminalKind> {
714         Some(match symbol {
715             sym::item => NonterminalKind::Item,
716             sym::block => NonterminalKind::Block,
717             sym::stmt => NonterminalKind::Stmt,
718             sym::pat => NonterminalKind::Pat,
719             sym::expr => NonterminalKind::Expr,
720             sym::ty => NonterminalKind::Ty,
721             sym::ident => NonterminalKind::Ident,
722             sym::lifetime => NonterminalKind::Lifetime,
723             sym::literal => NonterminalKind::Literal,
724             sym::meta => NonterminalKind::Meta,
725             sym::path => NonterminalKind::Path,
726             sym::vis => NonterminalKind::Vis,
727             sym::tt => NonterminalKind::TT,
728             _ => return None,
729         })
730     }
731     fn symbol(self) -> Symbol {
732         match self {
733             NonterminalKind::Item => sym::item,
734             NonterminalKind::Block => sym::block,
735             NonterminalKind::Stmt => sym::stmt,
736             NonterminalKind::Pat => sym::pat,
737             NonterminalKind::Expr => sym::expr,
738             NonterminalKind::Ty => sym::ty,
739             NonterminalKind::Ident => sym::ident,
740             NonterminalKind::Lifetime => sym::lifetime,
741             NonterminalKind::Literal => sym::literal,
742             NonterminalKind::Meta => sym::meta,
743             NonterminalKind::Path => sym::path,
744             NonterminalKind::Vis => sym::vis,
745             NonterminalKind::TT => sym::tt,
746         }
747     }
748 }
749
750 impl fmt::Display for NonterminalKind {
751     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
752         write!(f, "{}", self.symbol())
753     }
754 }
755
756 impl Nonterminal {
757     fn span(&self) -> Span {
758         match self {
759             NtItem(item) => item.span,
760             NtBlock(block) => block.span,
761             NtStmt(stmt) => stmt.span,
762             NtPat(pat) => pat.span,
763             NtExpr(expr) | NtLiteral(expr) => expr.span,
764             NtTy(ty) => ty.span,
765             NtIdent(ident, _) | NtLifetime(ident) => ident.span,
766             NtMeta(attr_item) => attr_item.span(),
767             NtPath(path) => path.span,
768             NtVis(vis) => vis.span,
769             NtTT(tt) => tt.span(),
770         }
771     }
772
773     /// This nonterminal looks like some specific enums from
774     /// `proc-macro-hack` and `procedural-masquerade` crates.
775     /// We need to maintain some special pretty-printing behavior for them due to incorrect
776     /// asserts in old versions of those crates and their wide use in the ecosystem.
777     /// See issue #73345 for more details.
778     /// FIXME(#73933): Remove this eventually.
779     pub fn pretty_printing_compatibility_hack(&self) -> bool {
780         if let NtItem(item) = self {
781             let name = item.ident.name;
782             if name == sym::ProceduralMasqueradeDummyType || name == sym::ProcMacroHack {
783                 if let ast::ItemKind::Enum(enum_def, _) = &item.kind {
784                     if let [variant] = &*enum_def.variants {
785                         return variant.ident.name == sym::Input;
786                     }
787                 }
788             }
789         }
790         false
791     }
792
793     // See issue #74616 for details
794     pub fn ident_name_compatibility_hack(
795         &self,
796         orig_span: Span,
797         source_map: &SourceMap,
798     ) -> Option<(Ident, bool)> {
799         if let NtIdent(ident, is_raw) = self {
800             if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind {
801                 let filename = source_map.span_to_filename(orig_span);
802                 if let FileName::Real(RealFileName::Named(path)) = filename {
803                     let matches_prefix = |prefix, filename| {
804                         // Check for a path that ends with 'prefix*/src/<filename>'
805                         let mut iter = path.components().rev();
806                         iter.next().and_then(|p| p.as_os_str().to_str()) == Some(filename)
807                             && iter.next().and_then(|p| p.as_os_str().to_str()) == Some("src")
808                             && iter
809                                 .next()
810                                 .and_then(|p| p.as_os_str().to_str())
811                                 .map_or(false, |p| p.starts_with(prefix))
812                     };
813
814                     if (macro_name == sym::impl_macros
815                         && matches_prefix("time-macros-impl", "lib.rs"))
816                         || (macro_name == sym::arrays && matches_prefix("js-sys", "lib.rs"))
817                     {
818                         let snippet = source_map.span_to_snippet(orig_span);
819                         if snippet.as_deref() == Ok("$name") {
820                             return Some((*ident, *is_raw));
821                         }
822                     }
823
824                     if macro_name == sym::tuple_from_req
825                         && (matches_prefix("actix-web", "extract.rs")
826                             || matches_prefix("actori-web", "extract.rs"))
827                     {
828                         let snippet = source_map.span_to_snippet(orig_span);
829                         if snippet.as_deref() == Ok("$T") {
830                             return Some((*ident, *is_raw));
831                         }
832                     }
833                 }
834             }
835         }
836         None
837     }
838 }
839
840 impl PartialEq for Nonterminal {
841     fn eq(&self, rhs: &Self) -> bool {
842         match (self, rhs) {
843             (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => {
844                 ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
845             }
846             (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
847             (NtTT(tt_lhs), NtTT(tt_rhs)) => tt_lhs == tt_rhs,
848             // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
849             // correctly based on data from AST. This will prevent them from matching each other
850             // in macros. The comparison will become possible only when each nonterminal has an
851             // attached token stream from which it was parsed.
852             _ => false,
853         }
854     }
855 }
856
857 impl fmt::Debug for Nonterminal {
858     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
859         match *self {
860             NtItem(..) => f.pad("NtItem(..)"),
861             NtBlock(..) => f.pad("NtBlock(..)"),
862             NtStmt(..) => f.pad("NtStmt(..)"),
863             NtPat(..) => f.pad("NtPat(..)"),
864             NtExpr(..) => f.pad("NtExpr(..)"),
865             NtTy(..) => f.pad("NtTy(..)"),
866             NtIdent(..) => f.pad("NtIdent(..)"),
867             NtLiteral(..) => f.pad("NtLiteral(..)"),
868             NtMeta(..) => f.pad("NtMeta(..)"),
869             NtPath(..) => f.pad("NtPath(..)"),
870             NtTT(..) => f.pad("NtTT(..)"),
871             NtVis(..) => f.pad("NtVis(..)"),
872             NtLifetime(..) => f.pad("NtLifetime(..)"),
873         }
874     }
875 }
876
877 impl<CTX> HashStable<CTX> for Nonterminal
878 where
879     CTX: crate::HashStableContext,
880 {
881     fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
882         panic!("interpolated tokens should not be present in the HIR")
883     }
884 }