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