]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast/src/token.rs
Rollup merge of #101772 - est31:replace_placeholder_diagnostics, r=jackh726
[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::Const,
477                 kw::Static,
478                 kw::Union,
479                 kw::Macro,
480                 kw::Mod,
481                 kw::Type,
482             ]
483             .contains(&name),
484             _ => false,
485         }
486     }
487
488     /// Returns `true` if the token is any literal.
489     pub fn is_lit(&self) -> bool {
490         matches!(self.kind, Literal(..))
491     }
492
493     /// Returns `true` if the token is any literal, a minus (which can prefix a literal,
494     /// for example a '-42', or one of the boolean idents).
495     ///
496     /// In other words, would this token be a valid start of `parse_literal_maybe_minus`?
497     ///
498     /// Keep this in sync with and `Lit::from_token`, excluding unary negation.
499     pub fn can_begin_literal_maybe_minus(&self) -> bool {
500         match self.uninterpolate().kind {
501             Literal(..) | BinOp(Minus) => true,
502             Ident(name, false) if name.is_bool_lit() => true,
503             Interpolated(ref nt) => match &**nt {
504                 NtLiteral(_) => true,
505                 NtExpr(e) => match &e.kind {
506                     ast::ExprKind::Lit(_) => true,
507                     ast::ExprKind::Unary(ast::UnOp::Neg, e) => {
508                         matches!(&e.kind, ast::ExprKind::Lit(_))
509                     }
510                     _ => false,
511                 },
512                 _ => false,
513             },
514             _ => false,
515         }
516     }
517
518     // A convenience function for matching on identifiers during parsing.
519     // Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token
520     // into the regular identifier or lifetime token it refers to,
521     // otherwise returns the original token.
522     pub fn uninterpolate(&self) -> Cow<'_, Token> {
523         match &self.kind {
524             Interpolated(nt) => match **nt {
525                 NtIdent(ident, is_raw) => {
526                     Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
527                 }
528                 NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
529                 _ => Cow::Borrowed(self),
530             },
531             _ => Cow::Borrowed(self),
532         }
533     }
534
535     /// Returns an identifier if this token is an identifier.
536     #[inline]
537     pub fn ident(&self) -> Option<(Ident, /* is_raw */ bool)> {
538         // We avoid using `Token::uninterpolate` here because it's slow.
539         match &self.kind {
540             &Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
541             Interpolated(nt) => match **nt {
542                 NtIdent(ident, is_raw) => Some((ident, is_raw)),
543                 _ => None,
544             },
545             _ => None,
546         }
547     }
548
549     /// Returns a lifetime identifier if this token is a lifetime.
550     #[inline]
551     pub fn lifetime(&self) -> Option<Ident> {
552         // We avoid using `Token::uninterpolate` here because it's slow.
553         match &self.kind {
554             &Lifetime(name) => Some(Ident::new(name, self.span)),
555             Interpolated(nt) => match **nt {
556                 NtLifetime(ident) => Some(ident),
557                 _ => None,
558             },
559             _ => None,
560         }
561     }
562
563     /// Returns `true` if the token is an identifier.
564     pub fn is_ident(&self) -> bool {
565         self.ident().is_some()
566     }
567
568     /// Returns `true` if the token is a lifetime.
569     pub fn is_lifetime(&self) -> bool {
570         self.lifetime().is_some()
571     }
572
573     /// Returns `true` if the token is an identifier whose name is the given
574     /// string slice.
575     pub fn is_ident_named(&self, name: Symbol) -> bool {
576         self.ident().map_or(false, |(ident, _)| ident.name == name)
577     }
578
579     /// Returns `true` if the token is an interpolated path.
580     fn is_path(&self) -> bool {
581         if let Interpolated(ref nt) = self.kind && let NtPath(..) = **nt {
582             return true;
583         }
584         false
585     }
586
587     /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`?
588     /// That is, is this a pre-parsed expression dropped into the token stream
589     /// (which happens while parsing the result of macro expansion)?
590     pub fn is_whole_expr(&self) -> bool {
591         if let Interpolated(ref nt) = self.kind
592             && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = **nt
593         {
594             return true;
595         }
596
597         false
598     }
599
600     // Is the token an interpolated block (`$b:block`)?
601     pub fn is_whole_block(&self) -> bool {
602         if let Interpolated(ref nt) = self.kind && let NtBlock(..) = **nt {
603             return true;
604         }
605         false
606     }
607
608     /// Returns `true` if the token is either the `mut` or `const` keyword.
609     pub fn is_mutability(&self) -> bool {
610         self.is_keyword(kw::Mut) || self.is_keyword(kw::Const)
611     }
612
613     pub fn is_qpath_start(&self) -> bool {
614         self == &Lt || self == &BinOp(Shl)
615     }
616
617     pub fn is_path_start(&self) -> bool {
618         self == &ModSep
619             || self.is_qpath_start()
620             || self.is_path()
621             || self.is_path_segment_keyword()
622             || self.is_ident() && !self.is_reserved_ident()
623     }
624
625     /// Returns `true` if the token is a given keyword, `kw`.
626     pub fn is_keyword(&self, kw: Symbol) -> bool {
627         self.is_non_raw_ident_where(|id| id.name == kw)
628     }
629
630     pub fn is_path_segment_keyword(&self) -> bool {
631         self.is_non_raw_ident_where(Ident::is_path_segment_keyword)
632     }
633
634     // Returns true for reserved identifiers used internally for elided lifetimes,
635     // unnamed method parameters, crate root module, error recovery etc.
636     pub fn is_special_ident(&self) -> bool {
637         self.is_non_raw_ident_where(Ident::is_special)
638     }
639
640     /// Returns `true` if the token is a keyword used in the language.
641     pub fn is_used_keyword(&self) -> bool {
642         self.is_non_raw_ident_where(Ident::is_used_keyword)
643     }
644
645     /// Returns `true` if the token is a keyword reserved for possible future use.
646     pub fn is_unused_keyword(&self) -> bool {
647         self.is_non_raw_ident_where(Ident::is_unused_keyword)
648     }
649
650     /// Returns `true` if the token is either a special identifier or a keyword.
651     pub fn is_reserved_ident(&self) -> bool {
652         self.is_non_raw_ident_where(Ident::is_reserved)
653     }
654
655     /// Returns `true` if the token is the identifier `true` or `false`.
656     pub fn is_bool_lit(&self) -> bool {
657         self.is_non_raw_ident_where(|id| id.name.is_bool_lit())
658     }
659
660     pub fn is_numeric_lit(&self) -> bool {
661         matches!(
662             self.kind,
663             Literal(Lit { kind: LitKind::Integer, .. }) | Literal(Lit { kind: LitKind::Float, .. })
664         )
665     }
666
667     /// Returns `true` if the token is a non-raw identifier for which `pred` holds.
668     pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool {
669         match self.ident() {
670             Some((id, false)) => pred(id),
671             _ => false,
672         }
673     }
674
675     pub fn glue(&self, joint: &Token) -> Option<Token> {
676         let kind = match self.kind {
677             Eq => match joint.kind {
678                 Eq => EqEq,
679                 Gt => FatArrow,
680                 _ => return None,
681             },
682             Lt => match joint.kind {
683                 Eq => Le,
684                 Lt => BinOp(Shl),
685                 Le => BinOpEq(Shl),
686                 BinOp(Minus) => LArrow,
687                 _ => return None,
688             },
689             Gt => match joint.kind {
690                 Eq => Ge,
691                 Gt => BinOp(Shr),
692                 Ge => BinOpEq(Shr),
693                 _ => return None,
694             },
695             Not => match joint.kind {
696                 Eq => Ne,
697                 _ => return None,
698             },
699             BinOp(op) => match joint.kind {
700                 Eq => BinOpEq(op),
701                 BinOp(And) if op == And => AndAnd,
702                 BinOp(Or) if op == Or => OrOr,
703                 Gt if op == Minus => RArrow,
704                 _ => return None,
705             },
706             Dot => match joint.kind {
707                 Dot => DotDot,
708                 DotDot => DotDotDot,
709                 _ => return None,
710             },
711             DotDot => match joint.kind {
712                 Dot => DotDotDot,
713                 Eq => DotDotEq,
714                 _ => return None,
715             },
716             Colon => match joint.kind {
717                 Colon => ModSep,
718                 _ => return None,
719             },
720             SingleQuote => match joint.kind {
721                 Ident(name, false) => Lifetime(Symbol::intern(&format!("'{}", name))),
722                 _ => return None,
723             },
724
725             Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
726             | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar
727             | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..)
728             | Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None,
729         };
730
731         Some(Token::new(kind, self.span.to(joint.span)))
732     }
733 }
734
735 impl PartialEq<TokenKind> for Token {
736     fn eq(&self, rhs: &TokenKind) -> bool {
737         self.kind == *rhs
738     }
739 }
740
741 #[derive(Clone, Encodable, Decodable)]
742 /// For interpolation during macro expansion.
743 pub enum Nonterminal {
744     NtItem(P<ast::Item>),
745     NtBlock(P<ast::Block>),
746     NtStmt(P<ast::Stmt>),
747     NtPat(P<ast::Pat>),
748     NtExpr(P<ast::Expr>),
749     NtTy(P<ast::Ty>),
750     NtIdent(Ident, /* is_raw */ bool),
751     NtLifetime(Ident),
752     NtLiteral(P<ast::Expr>),
753     /// Stuff inside brackets for attributes
754     NtMeta(P<ast::AttrItem>),
755     NtPath(P<ast::Path>),
756     NtVis(P<ast::Visibility>),
757 }
758
759 // `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger.
760 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
761 rustc_data_structures::static_assert_size!(Nonterminal, 16);
762
763 #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
764 pub enum NonterminalKind {
765     Item,
766     Block,
767     Stmt,
768     PatParam {
769         /// Keep track of whether the user used `:pat_param` or `:pat` and we inferred it from the
770         /// edition of the span. This is used for diagnostics.
771         inferred: bool,
772     },
773     PatWithOr,
774     Expr,
775     Ty,
776     Ident,
777     Lifetime,
778     Literal,
779     Meta,
780     Path,
781     Vis,
782     TT,
783 }
784
785 impl NonterminalKind {
786     /// The `edition` closure is used to get the edition for the given symbol. Doing
787     /// `span.edition()` is expensive, so we do it lazily.
788     pub fn from_symbol(
789         symbol: Symbol,
790         edition: impl FnOnce() -> Edition,
791     ) -> Option<NonterminalKind> {
792         Some(match symbol {
793             sym::item => NonterminalKind::Item,
794             sym::block => NonterminalKind::Block,
795             sym::stmt => NonterminalKind::Stmt,
796             sym::pat => match edition() {
797                 Edition::Edition2015 | Edition::Edition2018 => {
798                     NonterminalKind::PatParam { inferred: true }
799                 }
800                 Edition::Edition2021 | Edition::Edition2024 => NonterminalKind::PatWithOr,
801             },
802             sym::pat_param => NonterminalKind::PatParam { inferred: false },
803             sym::expr => NonterminalKind::Expr,
804             sym::ty => NonterminalKind::Ty,
805             sym::ident => NonterminalKind::Ident,
806             sym::lifetime => NonterminalKind::Lifetime,
807             sym::literal => NonterminalKind::Literal,
808             sym::meta => NonterminalKind::Meta,
809             sym::path => NonterminalKind::Path,
810             sym::vis => NonterminalKind::Vis,
811             sym::tt => NonterminalKind::TT,
812             _ => return None,
813         })
814     }
815     fn symbol(self) -> Symbol {
816         match self {
817             NonterminalKind::Item => sym::item,
818             NonterminalKind::Block => sym::block,
819             NonterminalKind::Stmt => sym::stmt,
820             NonterminalKind::PatParam { inferred: false } => sym::pat_param,
821             NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat,
822             NonterminalKind::Expr => sym::expr,
823             NonterminalKind::Ty => sym::ty,
824             NonterminalKind::Ident => sym::ident,
825             NonterminalKind::Lifetime => sym::lifetime,
826             NonterminalKind::Literal => sym::literal,
827             NonterminalKind::Meta => sym::meta,
828             NonterminalKind::Path => sym::path,
829             NonterminalKind::Vis => sym::vis,
830             NonterminalKind::TT => sym::tt,
831         }
832     }
833 }
834
835 impl fmt::Display for NonterminalKind {
836     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
837         write!(f, "{}", self.symbol())
838     }
839 }
840
841 impl Nonterminal {
842     pub fn span(&self) -> Span {
843         match self {
844             NtItem(item) => item.span,
845             NtBlock(block) => block.span,
846             NtStmt(stmt) => stmt.span,
847             NtPat(pat) => pat.span,
848             NtExpr(expr) | NtLiteral(expr) => expr.span,
849             NtTy(ty) => ty.span,
850             NtIdent(ident, _) | NtLifetime(ident) => ident.span,
851             NtMeta(attr_item) => attr_item.span(),
852             NtPath(path) => path.span,
853             NtVis(vis) => vis.span,
854         }
855     }
856 }
857
858 impl PartialEq for Nonterminal {
859     fn eq(&self, rhs: &Self) -> bool {
860         match (self, rhs) {
861             (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => {
862                 ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
863             }
864             (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
865             // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
866             // correctly based on data from AST. This will prevent them from matching each other
867             // in macros. The comparison will become possible only when each nonterminal has an
868             // attached token stream from which it was parsed.
869             _ => false,
870         }
871     }
872 }
873
874 impl fmt::Debug for Nonterminal {
875     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
876         match *self {
877             NtItem(..) => f.pad("NtItem(..)"),
878             NtBlock(..) => f.pad("NtBlock(..)"),
879             NtStmt(..) => f.pad("NtStmt(..)"),
880             NtPat(..) => f.pad("NtPat(..)"),
881             NtExpr(..) => f.pad("NtExpr(..)"),
882             NtTy(..) => f.pad("NtTy(..)"),
883             NtIdent(..) => f.pad("NtIdent(..)"),
884             NtLiteral(..) => f.pad("NtLiteral(..)"),
885             NtMeta(..) => f.pad("NtMeta(..)"),
886             NtPath(..) => f.pad("NtPath(..)"),
887             NtVis(..) => f.pad("NtVis(..)"),
888             NtLifetime(..) => f.pad("NtLifetime(..)"),
889         }
890     }
891 }
892
893 impl<CTX> HashStable<CTX> for Nonterminal
894 where
895     CTX: crate::HashStableContext,
896 {
897     fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
898         panic!("interpolated tokens should not be present in the HIR")
899     }
900 }