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