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