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