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