]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast/src/token.rs
Auto merge of #83587 - petrochenkov:asneeded, r=nagisa
[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             _ => None,
299         }
300     }
301
302     pub fn should_end_const_arg(&self) -> bool {
303         matches!(self, Gt | Ge | BinOp(Shr) | BinOpEq(Shr))
304     }
305 }
306
307 impl Token {
308     pub fn new(kind: TokenKind, span: Span) -> Self {
309         Token { kind, span }
310     }
311
312     /// Some token that will be thrown away later.
313     pub fn dummy() -> Self {
314         Token::new(TokenKind::Question, DUMMY_SP)
315     }
316
317     /// Recovers a `Token` from an `Ident`. This creates a raw identifier if necessary.
318     pub fn from_ast_ident(ident: Ident) -> Self {
319         Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span)
320     }
321
322     /// Return this token by value and leave a dummy token in its place.
323     pub fn take(&mut self) -> Self {
324         mem::replace(self, Token::dummy())
325     }
326
327     /// For interpolated tokens, returns a span of the fragment to which the interpolated
328     /// token refers. For all other tokens this is just a regular span.
329     /// It is particularly important to use this for identifiers and lifetimes
330     /// for which spans affect name resolution and edition checks.
331     /// Note that keywords are also identifiers, so they should use this
332     /// if they keep spans or perform edition checks.
333     pub fn uninterpolated_span(&self) -> Span {
334         match &self.kind {
335             Interpolated(nt) => nt.span(),
336             _ => self.span,
337         }
338     }
339
340     pub fn is_op(&self) -> bool {
341         !matches!(
342             self.kind,
343             OpenDelim(..)
344                 | CloseDelim(..)
345                 | Literal(..)
346                 | DocComment(..)
347                 | Ident(..)
348                 | Lifetime(..)
349                 | Interpolated(..)
350                 | Eof
351         )
352     }
353
354     pub fn is_like_plus(&self) -> bool {
355         matches!(self.kind, BinOp(Plus) | BinOpEq(Plus))
356     }
357
358     /// Returns `true` if the token can appear at the start of an expression.
359     pub fn can_begin_expr(&self) -> bool {
360         match self.uninterpolate().kind {
361             Ident(name, is_raw)              =>
362                 ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
363             OpenDelim(..)                     | // tuple, array or block
364             Literal(..)                       | // literal
365             Not                               | // operator not
366             BinOp(Minus)                      | // unary minus
367             BinOp(Star)                       | // dereference
368             BinOp(Or) | OrOr                  | // closure
369             BinOp(And)                        | // reference
370             AndAnd                            | // double reference
371             // DotDotDot is no longer supported, but we need some way to display the error
372             DotDot | DotDotDot | DotDotEq     | // range notation
373             Lt | BinOp(Shl)                   | // associated path
374             ModSep                            | // global path
375             Lifetime(..)                      | // labeled loop
376             Pound                             => true, // expression attributes
377             Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
378                 NtExpr(..)    |
379                 NtBlock(..)   |
380                 NtPath(..)),
381             _ => false,
382         }
383     }
384
385     /// Returns `true` if the token can appear at the start of a type.
386     pub fn can_begin_type(&self) -> bool {
387         match self.uninterpolate().kind {
388             Ident(name, is_raw)        =>
389                 ident_can_begin_type(name, self.span, is_raw), // type name or keyword
390             OpenDelim(Paren)            | // tuple
391             OpenDelim(Bracket)          | // array
392             Not                         | // never
393             BinOp(Star)                 | // raw pointer
394             BinOp(And)                  | // reference
395             AndAnd                      | // double reference
396             Question                    | // maybe bound in trait object
397             Lifetime(..)                | // lifetime bound in trait object
398             Lt | BinOp(Shl)             | // associated path
399             ModSep                      => true, // global path
400             Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)),
401             _ => false,
402         }
403     }
404
405     /// Returns `true` if the token can appear at the start of a const param.
406     pub fn can_begin_const_arg(&self) -> bool {
407         match self.kind {
408             OpenDelim(Brace) => true,
409             Interpolated(ref nt) => matches!(**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
410             _ => self.can_begin_literal_maybe_minus(),
411         }
412     }
413
414     /// Returns `true` if the token can appear at the start of a generic bound.
415     pub fn can_begin_bound(&self) -> bool {
416         self.is_path_start()
417             || self.is_lifetime()
418             || self.is_keyword(kw::For)
419             || self == &Question
420             || self == &OpenDelim(Paren)
421     }
422
423     /// Returns `true` if the token is any literal.
424     pub fn is_lit(&self) -> bool {
425         matches!(self.kind, Literal(..))
426     }
427
428     /// Returns `true` if the token is any literal, a minus (which can prefix a literal,
429     /// for example a '-42', or one of the boolean idents).
430     ///
431     /// In other words, would this token be a valid start of `parse_literal_maybe_minus`?
432     ///
433     /// Keep this in sync with and `Lit::from_token`, excluding unary negation.
434     pub fn can_begin_literal_maybe_minus(&self) -> bool {
435         match self.uninterpolate().kind {
436             Literal(..) | BinOp(Minus) => true,
437             Ident(name, false) if name.is_bool_lit() => true,
438             Interpolated(ref nt) => match &**nt {
439                 NtLiteral(_) => true,
440                 NtExpr(e) => match &e.kind {
441                     ast::ExprKind::Lit(_) => true,
442                     ast::ExprKind::Unary(ast::UnOp::Neg, e) => {
443                         matches!(&e.kind, ast::ExprKind::Lit(_))
444                     }
445                     _ => false,
446                 },
447                 _ => false,
448             },
449             _ => false,
450         }
451     }
452
453     // A convenience function for matching on identifiers during parsing.
454     // Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token
455     // into the regular identifier or lifetime token it refers to,
456     // otherwise returns the original token.
457     pub fn uninterpolate(&self) -> Cow<'_, Token> {
458         match &self.kind {
459             Interpolated(nt) => match **nt {
460                 NtIdent(ident, is_raw) => {
461                     Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
462                 }
463                 NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
464                 _ => Cow::Borrowed(self),
465             },
466             _ => Cow::Borrowed(self),
467         }
468     }
469
470     /// Returns an identifier if this token is an identifier.
471     pub fn ident(&self) -> Option<(Ident, /* is_raw */ bool)> {
472         let token = self.uninterpolate();
473         match token.kind {
474             Ident(name, is_raw) => Some((Ident::new(name, token.span), is_raw)),
475             _ => None,
476         }
477     }
478
479     /// Returns a lifetime identifier if this token is a lifetime.
480     pub fn lifetime(&self) -> Option<Ident> {
481         let token = self.uninterpolate();
482         match token.kind {
483             Lifetime(name) => Some(Ident::new(name, token.span)),
484             _ => None,
485         }
486     }
487
488     /// Returns `true` if the token is an identifier.
489     pub fn is_ident(&self) -> bool {
490         self.ident().is_some()
491     }
492
493     /// Returns `true` if the token is a lifetime.
494     pub fn is_lifetime(&self) -> bool {
495         self.lifetime().is_some()
496     }
497
498     /// Returns `true` if the token is a identifier whose name is the given
499     /// string slice.
500     pub fn is_ident_named(&self, name: Symbol) -> bool {
501         self.ident().map_or(false, |(ident, _)| ident.name == name)
502     }
503
504     /// Returns `true` if the token is an interpolated path.
505     fn is_path(&self) -> bool {
506         if let Interpolated(ref nt) = self.kind {
507             if let NtPath(..) = **nt {
508                 return true;
509             }
510         }
511         false
512     }
513
514     /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`?
515     /// That is, is this a pre-parsed expression dropped into the token stream
516     /// (which happens while parsing the result of macro expansion)?
517     pub fn is_whole_expr(&self) -> bool {
518         if let Interpolated(ref nt) = self.kind {
519             if let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt {
520                 return true;
521             }
522         }
523
524         false
525     }
526
527     // Is the token an interpolated block (`$b:block`)?
528     pub fn is_whole_block(&self) -> bool {
529         if let Interpolated(ref nt) = self.kind {
530             if let NtBlock(..) = **nt {
531                 return true;
532             }
533         }
534         false
535     }
536
537     /// Returns `true` if the token is either the `mut` or `const` keyword.
538     pub fn is_mutability(&self) -> bool {
539         self.is_keyword(kw::Mut) || self.is_keyword(kw::Const)
540     }
541
542     pub fn is_qpath_start(&self) -> bool {
543         self == &Lt || self == &BinOp(Shl)
544     }
545
546     pub fn is_path_start(&self) -> bool {
547         self == &ModSep
548             || self.is_qpath_start()
549             || self.is_path()
550             || self.is_path_segment_keyword()
551             || self.is_ident() && !self.is_reserved_ident()
552     }
553
554     /// Returns `true` if the token is a given keyword, `kw`.
555     pub fn is_keyword(&self, kw: Symbol) -> bool {
556         self.is_non_raw_ident_where(|id| id.name == kw)
557     }
558
559     pub fn is_path_segment_keyword(&self) -> bool {
560         self.is_non_raw_ident_where(Ident::is_path_segment_keyword)
561     }
562
563     // Returns true for reserved identifiers used internally for elided lifetimes,
564     // unnamed method parameters, crate root module, error recovery etc.
565     pub fn is_special_ident(&self) -> bool {
566         self.is_non_raw_ident_where(Ident::is_special)
567     }
568
569     /// Returns `true` if the token is a keyword used in the language.
570     pub fn is_used_keyword(&self) -> bool {
571         self.is_non_raw_ident_where(Ident::is_used_keyword)
572     }
573
574     /// Returns `true` if the token is a keyword reserved for possible future use.
575     pub fn is_unused_keyword(&self) -> bool {
576         self.is_non_raw_ident_where(Ident::is_unused_keyword)
577     }
578
579     /// Returns `true` if the token is either a special identifier or a keyword.
580     pub fn is_reserved_ident(&self) -> bool {
581         self.is_non_raw_ident_where(Ident::is_reserved)
582     }
583
584     /// Returns `true` if the token is the identifier `true` or `false`.
585     pub fn is_bool_lit(&self) -> bool {
586         self.is_non_raw_ident_where(|id| id.name.is_bool_lit())
587     }
588
589     /// Returns `true` if the token is a non-raw identifier for which `pred` holds.
590     pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool {
591         match self.ident() {
592             Some((id, false)) => pred(id),
593             _ => false,
594         }
595     }
596
597     pub fn glue(&self, joint: &Token) -> Option<Token> {
598         let kind = match self.kind {
599             Eq => match joint.kind {
600                 Eq => EqEq,
601                 Gt => FatArrow,
602                 _ => return None,
603             },
604             Lt => match joint.kind {
605                 Eq => Le,
606                 Lt => BinOp(Shl),
607                 Le => BinOpEq(Shl),
608                 BinOp(Minus) => LArrow,
609                 _ => return None,
610             },
611             Gt => match joint.kind {
612                 Eq => Ge,
613                 Gt => BinOp(Shr),
614                 Ge => BinOpEq(Shr),
615                 _ => return None,
616             },
617             Not => match joint.kind {
618                 Eq => Ne,
619                 _ => return None,
620             },
621             BinOp(op) => match joint.kind {
622                 Eq => BinOpEq(op),
623                 BinOp(And) if op == And => AndAnd,
624                 BinOp(Or) if op == Or => OrOr,
625                 Gt if op == Minus => RArrow,
626                 _ => return None,
627             },
628             Dot => match joint.kind {
629                 Dot => DotDot,
630                 DotDot => DotDotDot,
631                 _ => return None,
632             },
633             DotDot => match joint.kind {
634                 Dot => DotDotDot,
635                 Eq => DotDotEq,
636                 _ => return None,
637             },
638             Colon => match joint.kind {
639                 Colon => ModSep,
640                 _ => return None,
641             },
642             SingleQuote => match joint.kind {
643                 Ident(name, false) => Lifetime(Symbol::intern(&format!("'{}", name))),
644                 _ => return None,
645             },
646
647             Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
648             | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar
649             | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..)
650             | Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None,
651         };
652
653         Some(Token::new(kind, self.span.to(joint.span)))
654     }
655 }
656
657 impl PartialEq<TokenKind> for Token {
658     fn eq(&self, rhs: &TokenKind) -> bool {
659         self.kind == *rhs
660     }
661 }
662
663 #[derive(Clone, Encodable, Decodable)]
664 /// For interpolation during macro expansion.
665 pub enum Nonterminal {
666     NtItem(P<ast::Item>),
667     NtBlock(P<ast::Block>),
668     NtStmt(ast::Stmt),
669     NtPat(P<ast::Pat>),
670     NtExpr(P<ast::Expr>),
671     NtTy(P<ast::Ty>),
672     NtIdent(Ident, /* is_raw */ bool),
673     NtLifetime(Ident),
674     NtLiteral(P<ast::Expr>),
675     /// Stuff inside brackets for attributes
676     NtMeta(P<ast::AttrItem>),
677     NtPath(ast::Path),
678     NtVis(ast::Visibility),
679     NtTT(TokenTree),
680 }
681
682 // `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger.
683 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
684 rustc_data_structures::static_assert_size!(Nonterminal, 48);
685
686 #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
687 pub enum NonterminalKind {
688     Item,
689     Block,
690     Stmt,
691     Pat2015 {
692         /// Keep track of whether the user used `:pat2015` or `:pat` and we inferred it from the
693         /// edition of the span. This is used for diagnostics.
694         inferred: bool,
695     },
696     Pat2021 {
697         /// Keep track of whether the user used `:pat2015` or `:pat` and we inferred it from the
698         /// edition of the span. This is used for diagnostics.
699         inferred: bool,
700     },
701     Expr,
702     Ty,
703     Ident,
704     Lifetime,
705     Literal,
706     Meta,
707     Path,
708     Vis,
709     TT,
710 }
711
712 impl NonterminalKind {
713     /// The `edition` closure is used to get the edition for the given symbol. Doing
714     /// `span.edition()` is expensive, so we do it lazily.
715     pub fn from_symbol(
716         symbol: Symbol,
717         edition: impl FnOnce() -> Edition,
718     ) -> Option<NonterminalKind> {
719         Some(match symbol {
720             sym::item => NonterminalKind::Item,
721             sym::block => NonterminalKind::Block,
722             sym::stmt => NonterminalKind::Stmt,
723             sym::pat => match edition() {
724                 Edition::Edition2015 | Edition::Edition2018 => {
725                     NonterminalKind::Pat2015 { inferred: true }
726                 }
727                 Edition::Edition2021 => NonterminalKind::Pat2021 { inferred: true },
728             },
729             sym::pat2015 => NonterminalKind::Pat2015 { inferred: false },
730             sym::pat2021 => NonterminalKind::Pat2021 { inferred: false },
731             sym::expr => NonterminalKind::Expr,
732             sym::ty => NonterminalKind::Ty,
733             sym::ident => NonterminalKind::Ident,
734             sym::lifetime => NonterminalKind::Lifetime,
735             sym::literal => NonterminalKind::Literal,
736             sym::meta => NonterminalKind::Meta,
737             sym::path => NonterminalKind::Path,
738             sym::vis => NonterminalKind::Vis,
739             sym::tt => NonterminalKind::TT,
740             _ => return None,
741         })
742     }
743     fn symbol(self) -> Symbol {
744         match self {
745             NonterminalKind::Item => sym::item,
746             NonterminalKind::Block => sym::block,
747             NonterminalKind::Stmt => sym::stmt,
748             NonterminalKind::Pat2015 { inferred: false } => sym::pat2015,
749             NonterminalKind::Pat2021 { inferred: false } => sym::pat2021,
750             NonterminalKind::Pat2015 { inferred: true }
751             | NonterminalKind::Pat2021 { inferred: true } => sym::pat,
752             NonterminalKind::Expr => sym::expr,
753             NonterminalKind::Ty => sym::ty,
754             NonterminalKind::Ident => sym::ident,
755             NonterminalKind::Lifetime => sym::lifetime,
756             NonterminalKind::Literal => sym::literal,
757             NonterminalKind::Meta => sym::meta,
758             NonterminalKind::Path => sym::path,
759             NonterminalKind::Vis => sym::vis,
760             NonterminalKind::TT => sym::tt,
761         }
762     }
763 }
764
765 impl fmt::Display for NonterminalKind {
766     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
767         write!(f, "{}", self.symbol())
768     }
769 }
770
771 impl Nonterminal {
772     pub fn span(&self) -> Span {
773         match self {
774             NtItem(item) => item.span,
775             NtBlock(block) => block.span,
776             NtStmt(stmt) => stmt.span,
777             NtPat(pat) => pat.span,
778             NtExpr(expr) | NtLiteral(expr) => expr.span,
779             NtTy(ty) => ty.span,
780             NtIdent(ident, _) | NtLifetime(ident) => ident.span,
781             NtMeta(attr_item) => attr_item.span(),
782             NtPath(path) => path.span,
783             NtVis(vis) => vis.span,
784             NtTT(tt) => tt.span(),
785         }
786     }
787 }
788
789 impl PartialEq for Nonterminal {
790     fn eq(&self, rhs: &Self) -> bool {
791         match (self, rhs) {
792             (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => {
793                 ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
794             }
795             (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
796             (NtTT(tt_lhs), NtTT(tt_rhs)) => tt_lhs == tt_rhs,
797             // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
798             // correctly based on data from AST. This will prevent them from matching each other
799             // in macros. The comparison will become possible only when each nonterminal has an
800             // attached token stream from which it was parsed.
801             _ => false,
802         }
803     }
804 }
805
806 impl fmt::Debug for Nonterminal {
807     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
808         match *self {
809             NtItem(..) => f.pad("NtItem(..)"),
810             NtBlock(..) => f.pad("NtBlock(..)"),
811             NtStmt(..) => f.pad("NtStmt(..)"),
812             NtPat(..) => f.pad("NtPat(..)"),
813             NtExpr(..) => f.pad("NtExpr(..)"),
814             NtTy(..) => f.pad("NtTy(..)"),
815             NtIdent(..) => f.pad("NtIdent(..)"),
816             NtLiteral(..) => f.pad("NtLiteral(..)"),
817             NtMeta(..) => f.pad("NtMeta(..)"),
818             NtPath(..) => f.pad("NtPath(..)"),
819             NtTT(..) => f.pad("NtTT(..)"),
820             NtVis(..) => f.pad("NtVis(..)"),
821             NtLifetime(..) => f.pad("NtLifetime(..)"),
822         }
823     }
824 }
825
826 impl<CTX> HashStable<CTX> for Nonterminal
827 where
828     CTX: crate::HashStableContext,
829 {
830     fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
831         panic!("interpolated tokens should not be present in the HIR")
832     }
833 }