]> git.lizzy.rs Git - rust.git/blob - src/librustc_ast/token.rs
Auto merge of #69482 - lqd:poloniusup, r=nikomatsakis
[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;
15 use rustc_span::symbol::Symbol;
16 use rustc_span::{self, Span, DUMMY_SP};
17 use std::fmt;
18 use std::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: ast::Name, 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: ast::Name, 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     /* Name components */
229     Ident(ast::Name, /* is_raw */ bool),
230     Lifetime(ast::Name),
231
232     Interpolated(Lrc<Nonterminal>),
233
234     // Can be expanded into several tokens.
235     /// A doc comment.
236     DocComment(ast::Name),
237
238     // Junk. These carry no data because we don't really care about the data
239     // they *would* carry, and don't really want to allocate a new ident for
240     // them. Instead, users could extract that from the associated span.
241     /// Whitespace.
242     Whitespace,
243     /// A comment.
244     Comment,
245     Shebang(ast::Name),
246     /// A completely invalid token which should be skipped.
247     Unknown(ast::Name),
248
249     Eof,
250 }
251
252 // `TokenKind` is used a lot. Make sure it doesn't unintentionally get bigger.
253 #[cfg(target_arch = "x86_64")]
254 rustc_data_structures::static_assert_size!(TokenKind, 16);
255
256 #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
257 pub struct Token {
258     pub kind: TokenKind,
259     pub span: Span,
260 }
261
262 impl TokenKind {
263     pub fn lit(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> TokenKind {
264         Literal(Lit::new(kind, symbol, suffix))
265     }
266
267     // An approximation to proc-macro-style single-character operators used by rustc parser.
268     // If the operator token can be broken into two tokens, the first of which is single-character,
269     // then this function performs that operation, otherwise it returns `None`.
270     pub fn break_two_token_op(&self) -> Option<(TokenKind, TokenKind)> {
271         Some(match *self {
272             Le => (Lt, Eq),
273             EqEq => (Eq, Eq),
274             Ne => (Not, Eq),
275             Ge => (Gt, Eq),
276             AndAnd => (BinOp(And), BinOp(And)),
277             OrOr => (BinOp(Or), BinOp(Or)),
278             BinOp(Shl) => (Lt, Lt),
279             BinOp(Shr) => (Gt, Gt),
280             BinOpEq(Plus) => (BinOp(Plus), Eq),
281             BinOpEq(Minus) => (BinOp(Minus), Eq),
282             BinOpEq(Star) => (BinOp(Star), Eq),
283             BinOpEq(Slash) => (BinOp(Slash), Eq),
284             BinOpEq(Percent) => (BinOp(Percent), Eq),
285             BinOpEq(Caret) => (BinOp(Caret), Eq),
286             BinOpEq(And) => (BinOp(And), Eq),
287             BinOpEq(Or) => (BinOp(Or), Eq),
288             BinOpEq(Shl) => (Lt, Le),
289             BinOpEq(Shr) => (Gt, Ge),
290             DotDot => (Dot, Dot),
291             DotDotDot => (Dot, DotDot),
292             ModSep => (Colon, Colon),
293             RArrow => (BinOp(Minus), Gt),
294             LArrow => (Lt, BinOp(Minus)),
295             FatArrow => (Eq, Gt),
296             _ => return None,
297         })
298     }
299
300     /// Returns tokens that are likely to be typed accidentally instead of the current token.
301     /// Enables better error recovery when the wrong token is found.
302     pub fn similar_tokens(&self) -> Option<Vec<TokenKind>> {
303         match *self {
304             Comma => Some(vec![Dot, Lt, Semi]),
305             Semi => Some(vec![Colon, Comma]),
306             _ => None,
307         }
308     }
309 }
310
311 impl Token {
312     pub fn new(kind: TokenKind, span: Span) -> Self {
313         Token { kind, span }
314     }
315
316     /// Some token that will be thrown away later.
317     pub fn dummy() -> Self {
318         Token::new(TokenKind::Whitespace, DUMMY_SP)
319     }
320
321     /// Recovers a `Token` from an `ast::Ident`. This creates a raw identifier if necessary.
322     pub fn from_ast_ident(ident: ast::Ident) -> Self {
323         Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span)
324     }
325
326     /// Return this token by value and leave a dummy token in its place.
327     pub fn take(&mut self) -> Self {
328         mem::replace(self, Token::dummy())
329     }
330
331     pub fn is_op(&self) -> bool {
332         match self.kind {
333             OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
334             | Lifetime(..) | Interpolated(..) | Whitespace | Comment | Shebang(..) | Eof => false,
335             _ => true,
336         }
337     }
338
339     pub fn is_like_plus(&self) -> bool {
340         match self.kind {
341             BinOp(Plus) | BinOpEq(Plus) => true,
342             _ => false,
343         }
344     }
345
346     /// Returns `true` if the token can appear at the start of an expression.
347     pub fn can_begin_expr(&self) -> bool {
348         match self.kind {
349             Ident(name, is_raw)              =>
350                 ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
351             OpenDelim(..)                     | // tuple, array or block
352             Literal(..)                       | // literal
353             Not                               | // operator not
354             BinOp(Minus)                      | // unary minus
355             BinOp(Star)                       | // dereference
356             BinOp(Or) | OrOr                  | // closure
357             BinOp(And)                        | // reference
358             AndAnd                            | // double reference
359             // DotDotDot is no longer supported, but we need some way to display the error
360             DotDot | DotDotDot | DotDotEq     | // range notation
361             Lt | BinOp(Shl)                   | // associated path
362             ModSep                            | // global path
363             Lifetime(..)                      | // labeled loop
364             Pound                             => true, // expression attributes
365             Interpolated(ref nt) => match **nt {
366                 NtIdent(ident, is_raw) => ident_can_begin_expr(ident.name, ident.span, is_raw),
367                 NtLiteral(..) |
368                 NtExpr(..)    |
369                 NtBlock(..)   |
370                 NtPath(..)    |
371                 NtLifetime(..) => true,
372                 _ => false,
373             },
374             _ => false,
375         }
376     }
377
378     /// Returns `true` if the token can appear at the start of a type.
379     pub fn can_begin_type(&self) -> bool {
380         match self.kind {
381             Ident(name, is_raw)        =>
382                 ident_can_begin_type(name, self.span, is_raw), // type name or keyword
383             OpenDelim(Paren)            | // tuple
384             OpenDelim(Bracket)          | // array
385             Not                         | // never
386             BinOp(Star)                 | // raw pointer
387             BinOp(And)                  | // reference
388             AndAnd                      | // double reference
389             Question                    | // maybe bound in trait object
390             Lifetime(..)                | // lifetime bound in trait object
391             Lt | BinOp(Shl)             | // associated path
392             ModSep                      => true, // global path
393             Interpolated(ref nt) => match **nt {
394                 NtIdent(ident, is_raw) => ident_can_begin_type(ident.name, ident.span, is_raw),
395                 NtTy(..) | NtPath(..) | NtLifetime(..) => true,
396                 _ => false,
397             },
398             _ => false,
399         }
400     }
401
402     /// Returns `true` if the token can appear at the start of a const param.
403     pub fn can_begin_const_arg(&self) -> bool {
404         match self.kind {
405             OpenDelim(Brace) => true,
406             Interpolated(ref nt) => match **nt {
407                 NtExpr(..) | NtBlock(..) | NtLiteral(..) => true,
408                 _ => false,
409             },
410             _ => self.can_begin_literal_or_bool(),
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         match self.kind {
426             Literal(..) => true,
427             _ => false,
428         }
429     }
430
431     /// Returns `true` if the token is any literal, a minus (which can prefix a literal,
432     /// for example a '-42', or one of the boolean idents).
433     ///
434     /// Keep this in sync with `Lit::from_token`.
435     pub fn can_begin_literal_or_bool(&self) -> bool {
436         match self.kind {
437             Literal(..) | BinOp(Minus) => true,
438             Ident(name, false) if name.is_bool_lit() => true,
439             Interpolated(ref nt) => match &**nt {
440                 NtIdent(ident, false) if ident.name.is_bool_lit() => true,
441                 NtExpr(e) | NtLiteral(e) => matches!(e.kind, ast::ExprKind::Lit(_)),
442                 _ => false,
443             },
444             _ => false,
445         }
446     }
447
448     /// Returns an identifier if this token is an identifier.
449     pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> {
450         match self.kind {
451             Ident(name, is_raw) => Some((ast::Ident::new(name, self.span), is_raw)),
452             Interpolated(ref nt) => match **nt {
453                 NtIdent(ident, is_raw) => Some((ident, is_raw)),
454                 _ => None,
455             },
456             _ => None,
457         }
458     }
459
460     /// Returns a lifetime identifier if this token is a lifetime.
461     pub fn lifetime(&self) -> Option<ast::Ident> {
462         match self.kind {
463             Lifetime(name) => Some(ast::Ident::new(name, self.span)),
464             Interpolated(ref nt) => match **nt {
465                 NtLifetime(ident) => Some(ident),
466                 _ => None,
467             },
468             _ => None,
469         }
470     }
471
472     /// Returns `true` if the token is an identifier.
473     pub fn is_ident(&self) -> bool {
474         self.ident().is_some()
475     }
476
477     /// Returns `true` if the token is a lifetime.
478     pub fn is_lifetime(&self) -> bool {
479         self.lifetime().is_some()
480     }
481
482     /// Returns `true` if the token is a identifier whose name is the given
483     /// string slice.
484     pub fn is_ident_named(&self, name: Symbol) -> bool {
485         self.ident().map_or(false, |(ident, _)| ident.name == name)
486     }
487
488     /// Returns `true` if the token is an interpolated path.
489     fn is_path(&self) -> bool {
490         if let Interpolated(ref nt) = self.kind {
491             if let NtPath(..) = **nt {
492                 return true;
493             }
494         }
495         false
496     }
497
498     /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`?
499     /// That is, is this a pre-parsed expression dropped into the token stream
500     /// (which happens while parsing the result of macro expansion)?
501     pub fn is_whole_expr(&self) -> bool {
502         if let Interpolated(ref nt) = self.kind {
503             if let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt {
504                 return true;
505             }
506         }
507
508         false
509     }
510
511     /// Returns `true` if the token is either the `mut` or `const` keyword.
512     pub fn is_mutability(&self) -> bool {
513         self.is_keyword(kw::Mut) || self.is_keyword(kw::Const)
514     }
515
516     pub fn is_qpath_start(&self) -> bool {
517         self == &Lt || self == &BinOp(Shl)
518     }
519
520     pub fn is_path_start(&self) -> bool {
521         self == &ModSep
522             || self.is_qpath_start()
523             || self.is_path()
524             || self.is_path_segment_keyword()
525             || self.is_ident() && !self.is_reserved_ident()
526     }
527
528     /// Returns `true` if the token is a given keyword, `kw`.
529     pub fn is_keyword(&self, kw: Symbol) -> bool {
530         self.is_non_raw_ident_where(|id| id.name == kw)
531     }
532
533     pub fn is_path_segment_keyword(&self) -> bool {
534         self.is_non_raw_ident_where(ast::Ident::is_path_segment_keyword)
535     }
536
537     // Returns true for reserved identifiers used internally for elided lifetimes,
538     // unnamed method parameters, crate root module, error recovery etc.
539     pub fn is_special_ident(&self) -> bool {
540         self.is_non_raw_ident_where(ast::Ident::is_special)
541     }
542
543     /// Returns `true` if the token is a keyword used in the language.
544     pub fn is_used_keyword(&self) -> bool {
545         self.is_non_raw_ident_where(ast::Ident::is_used_keyword)
546     }
547
548     /// Returns `true` if the token is a keyword reserved for possible future use.
549     pub fn is_unused_keyword(&self) -> bool {
550         self.is_non_raw_ident_where(ast::Ident::is_unused_keyword)
551     }
552
553     /// Returns `true` if the token is either a special identifier or a keyword.
554     pub fn is_reserved_ident(&self) -> bool {
555         self.is_non_raw_ident_where(ast::Ident::is_reserved)
556     }
557
558     /// Returns `true` if the token is the identifier `true` or `false`.
559     pub fn is_bool_lit(&self) -> bool {
560         self.is_non_raw_ident_where(|id| id.name.is_bool_lit())
561     }
562
563     /// Returns `true` if the token is a non-raw identifier for which `pred` holds.
564     pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(ast::Ident) -> bool) -> bool {
565         match self.ident() {
566             Some((id, false)) => pred(id),
567             _ => false,
568         }
569     }
570
571     pub fn glue(&self, joint: &Token) -> Option<Token> {
572         let kind = match self.kind {
573             Eq => match joint.kind {
574                 Eq => EqEq,
575                 Gt => FatArrow,
576                 _ => return None,
577             },
578             Lt => match joint.kind {
579                 Eq => Le,
580                 Lt => BinOp(Shl),
581                 Le => BinOpEq(Shl),
582                 BinOp(Minus) => LArrow,
583                 _ => return None,
584             },
585             Gt => match joint.kind {
586                 Eq => Ge,
587                 Gt => BinOp(Shr),
588                 Ge => BinOpEq(Shr),
589                 _ => return None,
590             },
591             Not => match joint.kind {
592                 Eq => Ne,
593                 _ => return None,
594             },
595             BinOp(op) => match joint.kind {
596                 Eq => BinOpEq(op),
597                 BinOp(And) if op == And => AndAnd,
598                 BinOp(Or) if op == Or => OrOr,
599                 Gt if op == Minus => RArrow,
600                 _ => return None,
601             },
602             Dot => match joint.kind {
603                 Dot => DotDot,
604                 DotDot => DotDotDot,
605                 _ => return None,
606             },
607             DotDot => match joint.kind {
608                 Dot => DotDotDot,
609                 Eq => DotDotEq,
610                 _ => return None,
611             },
612             Colon => match joint.kind {
613                 Colon => ModSep,
614                 _ => return None,
615             },
616             SingleQuote => match joint.kind {
617                 Ident(name, false) => Lifetime(Symbol::intern(&format!("'{}", name))),
618                 _ => return None,
619             },
620
621             Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
622             | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar
623             | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..)
624             | Lifetime(..) | Interpolated(..) | DocComment(..) | Whitespace | Comment
625             | Shebang(..) | Unknown(..) | Eof => return None,
626         };
627
628         Some(Token::new(kind, self.span.to(joint.span)))
629     }
630
631     // See comments in `Nonterminal::to_tokenstream` for why we care about
632     // *probably* equal here rather than actual equality
633     crate fn probably_equal_for_proc_macro(&self, other: &Token) -> bool {
634         if mem::discriminant(&self.kind) != mem::discriminant(&other.kind) {
635             return false;
636         }
637         match (&self.kind, &other.kind) {
638             (&Eq, &Eq)
639             | (&Lt, &Lt)
640             | (&Le, &Le)
641             | (&EqEq, &EqEq)
642             | (&Ne, &Ne)
643             | (&Ge, &Ge)
644             | (&Gt, &Gt)
645             | (&AndAnd, &AndAnd)
646             | (&OrOr, &OrOr)
647             | (&Not, &Not)
648             | (&Tilde, &Tilde)
649             | (&At, &At)
650             | (&Dot, &Dot)
651             | (&DotDot, &DotDot)
652             | (&DotDotDot, &DotDotDot)
653             | (&DotDotEq, &DotDotEq)
654             | (&Comma, &Comma)
655             | (&Semi, &Semi)
656             | (&Colon, &Colon)
657             | (&ModSep, &ModSep)
658             | (&RArrow, &RArrow)
659             | (&LArrow, &LArrow)
660             | (&FatArrow, &FatArrow)
661             | (&Pound, &Pound)
662             | (&Dollar, &Dollar)
663             | (&Question, &Question)
664             | (&Whitespace, &Whitespace)
665             | (&Comment, &Comment)
666             | (&Eof, &Eof) => true,
667
668             (&BinOp(a), &BinOp(b)) | (&BinOpEq(a), &BinOpEq(b)) => a == b,
669
670             (&OpenDelim(a), &OpenDelim(b)) | (&CloseDelim(a), &CloseDelim(b)) => a == b,
671
672             (&DocComment(a), &DocComment(b)) | (&Shebang(a), &Shebang(b)) => a == b,
673
674             (&Literal(a), &Literal(b)) => a == b,
675
676             (&Lifetime(a), &Lifetime(b)) => a == b,
677             (&Ident(a, b), &Ident(c, d)) => {
678                 b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate)
679             }
680
681             (&Interpolated(_), &Interpolated(_)) => false,
682
683             _ => panic!("forgot to add a token?"),
684         }
685     }
686 }
687
688 impl PartialEq<TokenKind> for Token {
689     fn eq(&self, rhs: &TokenKind) -> bool {
690         self.kind == *rhs
691     }
692 }
693
694 #[derive(Clone, RustcEncodable, RustcDecodable)]
695 /// For interpolation during macro expansion.
696 pub enum Nonterminal {
697     NtItem(P<ast::Item>),
698     NtBlock(P<ast::Block>),
699     NtStmt(ast::Stmt),
700     NtPat(P<ast::Pat>),
701     NtExpr(P<ast::Expr>),
702     NtTy(P<ast::Ty>),
703     NtIdent(ast::Ident, /* is_raw */ bool),
704     NtLifetime(ast::Ident),
705     NtLiteral(P<ast::Expr>),
706     /// Stuff inside brackets for attributes
707     NtMeta(P<ast::AttrItem>),
708     NtPath(ast::Path),
709     NtVis(ast::Visibility),
710     NtTT(TokenTree),
711 }
712
713 // `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger.
714 #[cfg(target_arch = "x86_64")]
715 rustc_data_structures::static_assert_size!(Nonterminal, 40);
716
717 impl PartialEq for Nonterminal {
718     fn eq(&self, rhs: &Self) -> bool {
719         match (self, rhs) {
720             (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => {
721                 ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
722             }
723             (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
724             (NtTT(tt_lhs), NtTT(tt_rhs)) => tt_lhs == tt_rhs,
725             // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
726             // correctly based on data from AST. This will prevent them from matching each other
727             // in macros. The comparison will become possible only when each nonterminal has an
728             // attached token stream from which it was parsed.
729             _ => false,
730         }
731     }
732 }
733
734 impl fmt::Debug for Nonterminal {
735     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
736         match *self {
737             NtItem(..) => f.pad("NtItem(..)"),
738             NtBlock(..) => f.pad("NtBlock(..)"),
739             NtStmt(..) => f.pad("NtStmt(..)"),
740             NtPat(..) => f.pad("NtPat(..)"),
741             NtExpr(..) => f.pad("NtExpr(..)"),
742             NtTy(..) => f.pad("NtTy(..)"),
743             NtIdent(..) => f.pad("NtIdent(..)"),
744             NtLiteral(..) => f.pad("NtLiteral(..)"),
745             NtMeta(..) => f.pad("NtMeta(..)"),
746             NtPath(..) => f.pad("NtPath(..)"),
747             NtTT(..) => f.pad("NtTT(..)"),
748             NtVis(..) => f.pad("NtVis(..)"),
749             NtLifetime(..) => f.pad("NtLifetime(..)"),
750         }
751     }
752 }
753
754 impl<CTX> HashStable<CTX> for Nonterminal
755 where
756     CTX: crate::HashStableContext,
757 {
758     fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
759         panic!("interpolated tokens should not be present in the HIR")
760     }
761 }