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