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