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