]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast/src/token.rs
Auto merge of #103092 - petrochenkov:weaklto, 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;
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 #[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
260 pub struct Token {
261     pub kind: TokenKind,
262     pub span: Span,
263 }
264
265 impl TokenKind {
266     pub fn lit(kind: LitKind, symbol: Symbol, suffix: Option<Symbol>) -> TokenKind {
267         Literal(Lit::new(kind, symbol, suffix))
268     }
269
270     // An approximation to proc-macro-style single-character operators used by rustc parser.
271     // If the operator token can be broken into two tokens, the first of which is single-character,
272     // then this function performs that operation, otherwise it returns `None`.
273     pub fn break_two_token_op(&self) -> Option<(TokenKind, TokenKind)> {
274         Some(match *self {
275             Le => (Lt, Eq),
276             EqEq => (Eq, Eq),
277             Ne => (Not, Eq),
278             Ge => (Gt, Eq),
279             AndAnd => (BinOp(And), BinOp(And)),
280             OrOr => (BinOp(Or), BinOp(Or)),
281             BinOp(Shl) => (Lt, Lt),
282             BinOp(Shr) => (Gt, Gt),
283             BinOpEq(Plus) => (BinOp(Plus), Eq),
284             BinOpEq(Minus) => (BinOp(Minus), Eq),
285             BinOpEq(Star) => (BinOp(Star), Eq),
286             BinOpEq(Slash) => (BinOp(Slash), Eq),
287             BinOpEq(Percent) => (BinOp(Percent), Eq),
288             BinOpEq(Caret) => (BinOp(Caret), Eq),
289             BinOpEq(And) => (BinOp(And), Eq),
290             BinOpEq(Or) => (BinOp(Or), Eq),
291             BinOpEq(Shl) => (Lt, Le),
292             BinOpEq(Shr) => (Gt, Ge),
293             DotDot => (Dot, Dot),
294             DotDotDot => (Dot, DotDot),
295             ModSep => (Colon, Colon),
296             RArrow => (BinOp(Minus), Gt),
297             LArrow => (Lt, BinOp(Minus)),
298             FatArrow => (Eq, Gt),
299             _ => return None,
300         })
301     }
302
303     /// Returns tokens that are likely to be typed accidentally instead of the current token.
304     /// Enables better error recovery when the wrong token is found.
305     pub fn similar_tokens(&self) -> Option<Vec<TokenKind>> {
306         match *self {
307             Comma => Some(vec![Dot, Lt, Semi]),
308             Semi => Some(vec![Colon, Comma]),
309             FatArrow => Some(vec![Eq, RArrow]),
310             _ => None,
311         }
312     }
313
314     pub fn should_end_const_arg(&self) -> bool {
315         matches!(self, Gt | Ge | BinOp(Shr) | BinOpEq(Shr))
316     }
317 }
318
319 impl Token {
320     pub fn new(kind: TokenKind, span: Span) -> Self {
321         Token { kind, span }
322     }
323
324     /// Some token that will be thrown away later.
325     pub fn dummy() -> Self {
326         Token::new(TokenKind::Question, DUMMY_SP)
327     }
328
329     /// Recovers a `Token` from an `Ident`. This creates a raw identifier if necessary.
330     pub fn from_ast_ident(ident: Ident) -> Self {
331         Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span)
332     }
333
334     /// For interpolated tokens, returns a span of the fragment to which the interpolated
335     /// token refers. For all other tokens this is just a regular span.
336     /// It is particularly important to use this for identifiers and lifetimes
337     /// for which spans affect name resolution and edition checks.
338     /// Note that keywords are also identifiers, so they should use this
339     /// if they keep spans or perform edition checks.
340     pub fn uninterpolated_span(&self) -> Span {
341         match &self.kind {
342             Interpolated(nt) => nt.span(),
343             _ => self.span,
344         }
345     }
346
347     pub fn is_op(&self) -> bool {
348         match self.kind {
349             Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Not | Tilde | BinOp(_)
350             | BinOpEq(_) | At | Dot | DotDot | DotDotDot | DotDotEq | Comma | Semi | Colon
351             | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | SingleQuote => true,
352
353             OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
354             | Lifetime(..) | Interpolated(..) | Eof => false,
355         }
356     }
357
358     pub fn is_like_plus(&self) -> bool {
359         matches!(self.kind, BinOp(Plus) | BinOpEq(Plus))
360     }
361
362     /// Returns `true` if the token can appear at the start of an expression.
363     pub fn can_begin_expr(&self) -> bool {
364         match self.uninterpolate().kind {
365             Ident(name, is_raw)              =>
366                 ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
367             OpenDelim(..)                     | // tuple, array or block
368             Literal(..)                       | // literal
369             Not                               | // operator not
370             BinOp(Minus)                      | // unary minus
371             BinOp(Star)                       | // dereference
372             BinOp(Or) | OrOr                  | // closure
373             BinOp(And)                        | // reference
374             AndAnd                            | // double reference
375             // DotDotDot is no longer supported, but we need some way to display the error
376             DotDot | DotDotDot | DotDotEq     | // range notation
377             Lt | BinOp(Shl)                   | // associated path
378             ModSep                            | // global path
379             Lifetime(..)                      | // labeled loop
380             Pound                             => true, // expression attributes
381             Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
382                 NtExpr(..)    |
383                 NtBlock(..)   |
384                 NtPath(..)),
385             _ => false,
386         }
387     }
388
389     /// Returns `true` if the token can appear at the start of an pattern.
390     ///
391     /// Shamelessly borrowed from `can_begin_expr`, only used for diagnostics right now.
392     pub fn can_begin_pattern(&self) -> bool {
393         match self.uninterpolate().kind {
394             Ident(name, is_raw)              =>
395                 ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
396             | OpenDelim(Delimiter::Bracket | Delimiter::Parenthesis)  // tuple or array
397             | Literal(..)                        // literal
398             | BinOp(Minus)                       // unary minus
399             | BinOp(And)                         // reference
400             | AndAnd                             // double reference
401             // DotDotDot is no longer supported
402             | DotDot | DotDotDot | DotDotEq      // ranges
403             | Lt | BinOp(Shl)                    // associated path
404             | ModSep                    => true, // global path
405             Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
406                 NtPat(..)     |
407                 NtBlock(..)   |
408                 NtPath(..)),
409             _ => false,
410         }
411     }
412
413     /// Returns `true` if the token can appear at the start of a type.
414     pub fn can_begin_type(&self) -> bool {
415         match self.uninterpolate().kind {
416             Ident(name, is_raw)        =>
417                 ident_can_begin_type(name, self.span, is_raw), // type name or keyword
418             OpenDelim(Delimiter::Parenthesis) | // tuple
419             OpenDelim(Delimiter::Bracket)     | // array
420             Not                         | // never
421             BinOp(Star)                 | // raw pointer
422             BinOp(And)                  | // reference
423             AndAnd                      | // double reference
424             Question                    | // maybe bound in trait object
425             Lifetime(..)                | // lifetime bound in trait object
426             Lt | BinOp(Shl)             | // associated path
427             ModSep                      => true, // global path
428             Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)),
429             _ => false,
430         }
431     }
432
433     /// Returns `true` if the token can appear at the start of a const param.
434     pub fn can_begin_const_arg(&self) -> bool {
435         match self.kind {
436             OpenDelim(Delimiter::Brace) => true,
437             Interpolated(ref nt) => matches!(**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
438             _ => self.can_begin_literal_maybe_minus(),
439         }
440     }
441
442     /// Returns `true` if the token can appear at the start of a generic bound.
443     pub fn can_begin_bound(&self) -> bool {
444         self.is_path_start()
445             || self.is_lifetime()
446             || self.is_keyword(kw::For)
447             || self == &Question
448             || self == &OpenDelim(Delimiter::Parenthesis)
449     }
450
451     /// Returns `true` if the token can appear at the start of an item.
452     pub fn can_begin_item(&self) -> bool {
453         match self.kind {
454             Ident(name, _) => [
455                 kw::Fn,
456                 kw::Use,
457                 kw::Struct,
458                 kw::Enum,
459                 kw::Pub,
460                 kw::Trait,
461                 kw::Extern,
462                 kw::Impl,
463                 kw::Unsafe,
464                 kw::Const,
465                 kw::Static,
466                 kw::Union,
467                 kw::Macro,
468                 kw::Mod,
469                 kw::Type,
470             ]
471             .contains(&name),
472             _ => false,
473         }
474     }
475
476     /// Returns `true` if the token is any literal.
477     pub fn is_lit(&self) -> bool {
478         matches!(self.kind, Literal(..))
479     }
480
481     /// Returns `true` if the token is any literal, a minus (which can prefix a literal,
482     /// for example a '-42', or one of the boolean idents).
483     ///
484     /// In other words, would this token be a valid start of `parse_literal_maybe_minus`?
485     ///
486     /// Keep this in sync with and `Lit::from_token`, excluding unary negation.
487     pub fn can_begin_literal_maybe_minus(&self) -> bool {
488         match self.uninterpolate().kind {
489             Literal(..) | BinOp(Minus) => true,
490             Ident(name, false) if name.is_bool_lit() => true,
491             Interpolated(ref nt) => match &**nt {
492                 NtLiteral(_) => true,
493                 NtExpr(e) => match &e.kind {
494                     ast::ExprKind::Lit(_) => true,
495                     ast::ExprKind::Unary(ast::UnOp::Neg, e) => {
496                         matches!(&e.kind, ast::ExprKind::Lit(_))
497                     }
498                     _ => false,
499                 },
500                 _ => false,
501             },
502             _ => false,
503         }
504     }
505
506     // A convenience function for matching on identifiers during parsing.
507     // Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token
508     // into the regular identifier or lifetime token it refers to,
509     // otherwise returns the original token.
510     pub fn uninterpolate(&self) -> Cow<'_, Token> {
511         match &self.kind {
512             Interpolated(nt) => match **nt {
513                 NtIdent(ident, is_raw) => {
514                     Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
515                 }
516                 NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
517                 _ => Cow::Borrowed(self),
518             },
519             _ => Cow::Borrowed(self),
520         }
521     }
522
523     /// Returns an identifier if this token is an identifier.
524     #[inline]
525     pub fn ident(&self) -> Option<(Ident, /* is_raw */ bool)> {
526         // We avoid using `Token::uninterpolate` here because it's slow.
527         match &self.kind {
528             &Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
529             Interpolated(nt) => match **nt {
530                 NtIdent(ident, is_raw) => Some((ident, is_raw)),
531                 _ => None,
532             },
533             _ => None,
534         }
535     }
536
537     /// Returns a lifetime identifier if this token is a lifetime.
538     #[inline]
539     pub fn lifetime(&self) -> Option<Ident> {
540         // We avoid using `Token::uninterpolate` here because it's slow.
541         match &self.kind {
542             &Lifetime(name) => Some(Ident::new(name, self.span)),
543             Interpolated(nt) => match **nt {
544                 NtLifetime(ident) => Some(ident),
545                 _ => None,
546             },
547             _ => None,
548         }
549     }
550
551     /// Returns `true` if the token is an identifier.
552     pub fn is_ident(&self) -> bool {
553         self.ident().is_some()
554     }
555
556     /// Returns `true` if the token is a lifetime.
557     pub fn is_lifetime(&self) -> bool {
558         self.lifetime().is_some()
559     }
560
561     /// Returns `true` if the token is an identifier whose name is the given
562     /// string slice.
563     pub fn is_ident_named(&self, name: Symbol) -> bool {
564         self.ident().map_or(false, |(ident, _)| ident.name == name)
565     }
566
567     /// Returns `true` if the token is an interpolated path.
568     fn is_path(&self) -> bool {
569         if let Interpolated(ref nt) = self.kind && let NtPath(..) = **nt {
570             return true;
571         }
572         false
573     }
574
575     /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`?
576     /// That is, is this a pre-parsed expression dropped into the token stream
577     /// (which happens while parsing the result of macro expansion)?
578     pub fn is_whole_expr(&self) -> bool {
579         if let Interpolated(ref nt) = self.kind
580             && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = **nt
581         {
582             return true;
583         }
584
585         false
586     }
587
588     // Is the token an interpolated block (`$b:block`)?
589     pub fn is_whole_block(&self) -> bool {
590         if let Interpolated(ref nt) = self.kind && let NtBlock(..) = **nt {
591             return true;
592         }
593         false
594     }
595
596     /// Returns `true` if the token is either the `mut` or `const` keyword.
597     pub fn is_mutability(&self) -> bool {
598         self.is_keyword(kw::Mut) || self.is_keyword(kw::Const)
599     }
600
601     pub fn is_qpath_start(&self) -> bool {
602         self == &Lt || self == &BinOp(Shl)
603     }
604
605     pub fn is_path_start(&self) -> bool {
606         self == &ModSep
607             || self.is_qpath_start()
608             || self.is_path()
609             || self.is_path_segment_keyword()
610             || self.is_ident() && !self.is_reserved_ident()
611     }
612
613     /// Returns `true` if the token is a given keyword, `kw`.
614     pub fn is_keyword(&self, kw: Symbol) -> bool {
615         self.is_non_raw_ident_where(|id| id.name == kw)
616     }
617
618     pub fn is_path_segment_keyword(&self) -> bool {
619         self.is_non_raw_ident_where(Ident::is_path_segment_keyword)
620     }
621
622     // Returns true for reserved identifiers used internally for elided lifetimes,
623     // unnamed method parameters, crate root module, error recovery etc.
624     pub fn is_special_ident(&self) -> bool {
625         self.is_non_raw_ident_where(Ident::is_special)
626     }
627
628     /// Returns `true` if the token is a keyword used in the language.
629     pub fn is_used_keyword(&self) -> bool {
630         self.is_non_raw_ident_where(Ident::is_used_keyword)
631     }
632
633     /// Returns `true` if the token is a keyword reserved for possible future use.
634     pub fn is_unused_keyword(&self) -> bool {
635         self.is_non_raw_ident_where(Ident::is_unused_keyword)
636     }
637
638     /// Returns `true` if the token is either a special identifier or a keyword.
639     pub fn is_reserved_ident(&self) -> bool {
640         self.is_non_raw_ident_where(Ident::is_reserved)
641     }
642
643     /// Returns `true` if the token is the identifier `true` or `false`.
644     pub fn is_bool_lit(&self) -> bool {
645         self.is_non_raw_ident_where(|id| id.name.is_bool_lit())
646     }
647
648     pub fn is_numeric_lit(&self) -> bool {
649         matches!(
650             self.kind,
651             Literal(Lit { kind: LitKind::Integer, .. }) | Literal(Lit { kind: LitKind::Float, .. })
652         )
653     }
654
655     /// Returns `true` if the token is a non-raw identifier for which `pred` holds.
656     pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool {
657         match self.ident() {
658             Some((id, false)) => pred(id),
659             _ => false,
660         }
661     }
662
663     pub fn glue(&self, joint: &Token) -> Option<Token> {
664         let kind = match self.kind {
665             Eq => match joint.kind {
666                 Eq => EqEq,
667                 Gt => FatArrow,
668                 _ => return None,
669             },
670             Lt => match joint.kind {
671                 Eq => Le,
672                 Lt => BinOp(Shl),
673                 Le => BinOpEq(Shl),
674                 BinOp(Minus) => LArrow,
675                 _ => return None,
676             },
677             Gt => match joint.kind {
678                 Eq => Ge,
679                 Gt => BinOp(Shr),
680                 Ge => BinOpEq(Shr),
681                 _ => return None,
682             },
683             Not => match joint.kind {
684                 Eq => Ne,
685                 _ => return None,
686             },
687             BinOp(op) => match joint.kind {
688                 Eq => BinOpEq(op),
689                 BinOp(And) if op == And => AndAnd,
690                 BinOp(Or) if op == Or => OrOr,
691                 Gt if op == Minus => RArrow,
692                 _ => return None,
693             },
694             Dot => match joint.kind {
695                 Dot => DotDot,
696                 DotDot => DotDotDot,
697                 _ => return None,
698             },
699             DotDot => match joint.kind {
700                 Dot => DotDotDot,
701                 Eq => DotDotEq,
702                 _ => return None,
703             },
704             Colon => match joint.kind {
705                 Colon => ModSep,
706                 _ => return None,
707             },
708             SingleQuote => match joint.kind {
709                 Ident(name, false) => Lifetime(Symbol::intern(&format!("'{}", name))),
710                 _ => return None,
711             },
712
713             Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
714             | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar
715             | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..)
716             | Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None,
717         };
718
719         Some(Token::new(kind, self.span.to(joint.span)))
720     }
721 }
722
723 impl PartialEq<TokenKind> for Token {
724     #[inline]
725     fn eq(&self, rhs: &TokenKind) -> bool {
726         self.kind == *rhs
727     }
728 }
729
730 #[derive(Clone, Encodable, Decodable)]
731 /// For interpolation during macro expansion.
732 pub enum Nonterminal {
733     NtItem(P<ast::Item>),
734     NtBlock(P<ast::Block>),
735     NtStmt(P<ast::Stmt>),
736     NtPat(P<ast::Pat>),
737     NtExpr(P<ast::Expr>),
738     NtTy(P<ast::Ty>),
739     NtIdent(Ident, /* is_raw */ bool),
740     NtLifetime(Ident),
741     NtLiteral(P<ast::Expr>),
742     /// Stuff inside brackets for attributes
743     NtMeta(P<ast::AttrItem>),
744     NtPath(P<ast::Path>),
745     NtVis(P<ast::Visibility>),
746 }
747
748 #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
749 pub enum NonterminalKind {
750     Item,
751     Block,
752     Stmt,
753     PatParam {
754         /// Keep track of whether the user used `:pat_param` or `:pat` and we inferred it from the
755         /// edition of the span. This is used for diagnostics.
756         inferred: bool,
757     },
758     PatWithOr,
759     Expr,
760     Ty,
761     Ident,
762     Lifetime,
763     Literal,
764     Meta,
765     Path,
766     Vis,
767     TT,
768 }
769
770 impl NonterminalKind {
771     /// The `edition` closure is used to get the edition for the given symbol. Doing
772     /// `span.edition()` is expensive, so we do it lazily.
773     pub fn from_symbol(
774         symbol: Symbol,
775         edition: impl FnOnce() -> Edition,
776     ) -> Option<NonterminalKind> {
777         Some(match symbol {
778             sym::item => NonterminalKind::Item,
779             sym::block => NonterminalKind::Block,
780             sym::stmt => NonterminalKind::Stmt,
781             sym::pat => match edition() {
782                 Edition::Edition2015 | Edition::Edition2018 => {
783                     NonterminalKind::PatParam { inferred: true }
784                 }
785                 Edition::Edition2021 | Edition::Edition2024 => NonterminalKind::PatWithOr,
786             },
787             sym::pat_param => NonterminalKind::PatParam { inferred: false },
788             sym::expr => NonterminalKind::Expr,
789             sym::ty => NonterminalKind::Ty,
790             sym::ident => NonterminalKind::Ident,
791             sym::lifetime => NonterminalKind::Lifetime,
792             sym::literal => NonterminalKind::Literal,
793             sym::meta => NonterminalKind::Meta,
794             sym::path => NonterminalKind::Path,
795             sym::vis => NonterminalKind::Vis,
796             sym::tt => NonterminalKind::TT,
797             _ => return None,
798         })
799     }
800     fn symbol(self) -> Symbol {
801         match self {
802             NonterminalKind::Item => sym::item,
803             NonterminalKind::Block => sym::block,
804             NonterminalKind::Stmt => sym::stmt,
805             NonterminalKind::PatParam { inferred: false } => sym::pat_param,
806             NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat,
807             NonterminalKind::Expr => sym::expr,
808             NonterminalKind::Ty => sym::ty,
809             NonterminalKind::Ident => sym::ident,
810             NonterminalKind::Lifetime => sym::lifetime,
811             NonterminalKind::Literal => sym::literal,
812             NonterminalKind::Meta => sym::meta,
813             NonterminalKind::Path => sym::path,
814             NonterminalKind::Vis => sym::vis,
815             NonterminalKind::TT => sym::tt,
816         }
817     }
818 }
819
820 impl fmt::Display for NonterminalKind {
821     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
822         write!(f, "{}", self.symbol())
823     }
824 }
825
826 impl Nonterminal {
827     pub fn span(&self) -> Span {
828         match self {
829             NtItem(item) => item.span,
830             NtBlock(block) => block.span,
831             NtStmt(stmt) => stmt.span,
832             NtPat(pat) => pat.span,
833             NtExpr(expr) | NtLiteral(expr) => expr.span,
834             NtTy(ty) => ty.span,
835             NtIdent(ident, _) | NtLifetime(ident) => ident.span,
836             NtMeta(attr_item) => attr_item.span(),
837             NtPath(path) => path.span,
838             NtVis(vis) => vis.span,
839         }
840     }
841 }
842
843 impl PartialEq for Nonterminal {
844     fn eq(&self, rhs: &Self) -> bool {
845         match (self, rhs) {
846             (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => {
847                 ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
848             }
849             (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
850             // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
851             // correctly based on data from AST. This will prevent them from matching each other
852             // in macros. The comparison will become possible only when each nonterminal has an
853             // attached token stream from which it was parsed.
854             _ => false,
855         }
856     }
857 }
858
859 impl fmt::Debug for Nonterminal {
860     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
861         match *self {
862             NtItem(..) => f.pad("NtItem(..)"),
863             NtBlock(..) => f.pad("NtBlock(..)"),
864             NtStmt(..) => f.pad("NtStmt(..)"),
865             NtPat(..) => f.pad("NtPat(..)"),
866             NtExpr(..) => f.pad("NtExpr(..)"),
867             NtTy(..) => f.pad("NtTy(..)"),
868             NtIdent(..) => f.pad("NtIdent(..)"),
869             NtLiteral(..) => f.pad("NtLiteral(..)"),
870             NtMeta(..) => f.pad("NtMeta(..)"),
871             NtPath(..) => f.pad("NtPath(..)"),
872             NtVis(..) => f.pad("NtVis(..)"),
873             NtLifetime(..) => f.pad("NtLifetime(..)"),
874         }
875     }
876 }
877
878 impl<CTX> HashStable<CTX> for Nonterminal
879 where
880     CTX: crate::HashStableContext,
881 {
882     fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
883         panic!("interpolated tokens should not be present in the HIR")
884     }
885 }
886
887 // Some types are used a lot. Make sure they don't unintentionally get bigger.
888 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
889 mod size_asserts {
890     use super::*;
891     use rustc_data_structures::static_assert_size;
892     // tidy-alphabetical-start
893     static_assert_size!(Lit, 12);
894     static_assert_size!(LitKind, 2);
895     static_assert_size!(Nonterminal, 16);
896     static_assert_size!(Token, 24);
897     static_assert_size!(TokenKind, 16);
898     // tidy-alphabetical-end
899 }