@@ -14,8 +14,8 @@ use rustc_macros::HashStable_Generic;
1414use rustc_span:: symbol:: kw;
1515use rustc_span:: symbol:: Symbol ;
1616use rustc_span:: { self , Span , DUMMY_SP } ;
17- use std:: fmt ;
18- use std:: mem;
17+ use std:: borrow :: Cow ;
18+ use std:: { fmt , mem} ;
1919
2020#[ derive( Clone , PartialEq , RustcEncodable , RustcDecodable , Hash , Debug , Copy ) ]
2121#[ derive( HashStable_Generic ) ]
@@ -225,8 +225,15 @@ pub enum TokenKind {
225225 /* Literals */
226226 Literal ( Lit ) ,
227227
228- /* Name components */
228+ /// Identifier token.
229+ /// Do not forget about `NtIdent` when you want to match on identifiers.
230+ /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
231+ /// treat regular and interpolated identifiers in the same way.
229232 Ident ( ast:: Name , /* is_raw */ bool ) ,
233+ /// Lifetime identifier token.
234+ /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
235+ /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
236+ /// treat regular and interpolated lifetime identifiers in the same way.
230237 Lifetime ( ast:: Name ) ,
231238
232239 Interpolated ( Lrc < Nonterminal > ) ,
@@ -328,6 +335,19 @@ impl Token {
328335 mem:: replace ( self , Token :: dummy ( ) )
329336 }
330337
338+ /// For interpolated tokens, returns a span of the fragment to which the interpolated
339+ /// token refers. For all other tokens this is just a regular span.
340+ /// It is particularly important to use this for identifiers and lifetimes
341+ /// for which spans affect name resolution and edition checks.
342+ /// Note that keywords are also identifiers, so they should use this
343+ /// if they keep spans or perform edition checks.
344+ pub fn uninterpolated_span ( & self ) -> Span {
345+ match & self . kind {
346+ Interpolated ( nt) => nt. span ( ) ,
347+ _ => self . span ,
348+ }
349+ }
350+
331351 pub fn is_op ( & self ) -> bool {
332352 match self . kind {
333353 OpenDelim ( ..) | CloseDelim ( ..) | Literal ( ..) | DocComment ( ..) | Ident ( ..)
@@ -345,7 +365,7 @@ impl Token {
345365
346366 /// Returns `true` if the token can appear at the start of an expression.
347367 pub fn can_begin_expr ( & self ) -> bool {
348- match self . kind {
368+ match self . uninterpolate ( ) . kind {
349369 Ident ( name, is_raw) =>
350370 ident_can_begin_expr ( name, self . span , is_raw) , // value name or keyword
351371 OpenDelim ( ..) | // tuple, array or block
@@ -363,12 +383,10 @@ impl Token {
363383 Lifetime ( ..) | // labeled loop
364384 Pound => true , // expression attributes
365385 Interpolated ( ref nt) => match * * nt {
366- NtIdent ( ident, is_raw) => ident_can_begin_expr ( ident. name , ident. span , is_raw) ,
367386 NtLiteral ( ..) |
368387 NtExpr ( ..) |
369388 NtBlock ( ..) |
370- NtPath ( ..) |
371- NtLifetime ( ..) => true ,
389+ NtPath ( ..) => true ,
372390 _ => false ,
373391 } ,
374392 _ => false ,
@@ -377,7 +395,7 @@ impl Token {
377395
378396 /// Returns `true` if the token can appear at the start of a type.
379397 pub fn can_begin_type ( & self ) -> bool {
380- match self . kind {
398+ match self . uninterpolate ( ) . kind {
381399 Ident ( name, is_raw) =>
382400 ident_can_begin_type ( name, self . span , is_raw) , // type name or keyword
383401 OpenDelim ( Paren ) | // tuple
@@ -391,8 +409,7 @@ impl Token {
391409 Lt | BinOp ( Shl ) | // associated path
392410 ModSep => true , // global path
393411 Interpolated ( ref nt) => match * * nt {
394- NtIdent ( ident, is_raw) => ident_can_begin_type ( ident. name , ident. span , is_raw) ,
395- NtTy ( ..) | NtPath ( ..) | NtLifetime ( ..) => true ,
412+ NtTy ( ..) | NtPath ( ..) => true ,
396413 _ => false ,
397414 } ,
398415 _ => false ,
@@ -433,38 +450,48 @@ impl Token {
433450 ///
434451 /// Keep this in sync with `Lit::from_token`.
435452 pub fn can_begin_literal_or_bool ( & self ) -> bool {
436- match self . kind {
453+ match self . uninterpolate ( ) . kind {
437454 Literal ( ..) | BinOp ( Minus ) => true ,
438455 Ident ( name, false ) if name. is_bool_lit ( ) => true ,
439456 Interpolated ( ref nt) => match & * * nt {
440- NtIdent ( ident, false ) if ident. name . is_bool_lit ( ) => true ,
441457 NtExpr ( e) | NtLiteral ( e) => matches ! ( e. kind, ast:: ExprKind :: Lit ( _) ) ,
442458 _ => false ,
443459 } ,
444460 _ => false ,
445461 }
446462 }
447463
464+ // A convenience function for matching on identifiers during parsing.
465+ // Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token
466+ // into the regular identifier or lifetime token it refers to,
467+ // otherwise returns the original token.
468+ pub fn uninterpolate ( & self ) -> Cow < ' _ , Token > {
469+ match & self . kind {
470+ Interpolated ( nt) => match * * nt {
471+ NtIdent ( ident, is_raw) => {
472+ Cow :: Owned ( Token :: new ( Ident ( ident. name , is_raw) , ident. span ) )
473+ }
474+ NtLifetime ( ident) => Cow :: Owned ( Token :: new ( Lifetime ( ident. name ) , ident. span ) ) ,
475+ _ => Cow :: Borrowed ( self ) ,
476+ } ,
477+ _ => Cow :: Borrowed ( self ) ,
478+ }
479+ }
480+
448481 /// Returns an identifier if this token is an identifier.
449482 pub fn ident ( & self ) -> Option < ( ast:: Ident , /* is_raw */ bool ) > {
450- match self . kind {
451- Ident ( name, is_raw) => Some ( ( ast:: Ident :: new ( name, self . span ) , is_raw) ) ,
452- Interpolated ( ref nt) => match * * nt {
453- NtIdent ( ident, is_raw) => Some ( ( ident, is_raw) ) ,
454- _ => None ,
455- } ,
483+ let token = self . uninterpolate ( ) ;
484+ match token. kind {
485+ Ident ( name, is_raw) => Some ( ( ast:: Ident :: new ( name, token. span ) , is_raw) ) ,
456486 _ => None ,
457487 }
458488 }
459489
460490 /// Returns a lifetime identifier if this token is a lifetime.
461491 pub fn lifetime ( & self ) -> Option < ast:: Ident > {
462- match self . kind {
463- Lifetime ( name) => Some ( ast:: Ident :: new ( name, self . span ) ) ,
464- Interpolated ( ref nt) => match * * nt {
465- NtLifetime ( ident) => Some ( ident) ,
466- _ => None ,
467- } ,
492+ let token = self . uninterpolate ( ) ;
493+ match token. kind {
494+ Lifetime ( name) => Some ( ast:: Ident :: new ( name, token. span ) ) ,
468495 _ => None ,
469496 }
470497 }
@@ -714,6 +741,24 @@ pub enum Nonterminal {
714741#[ cfg( target_arch = "x86_64" ) ]
715742rustc_data_structures:: static_assert_size!( Nonterminal , 40 ) ;
716743
744+ impl Nonterminal {
745+ fn span ( & self ) -> Span {
746+ match self {
747+ NtItem ( item) => item. span ,
748+ NtBlock ( block) => block. span ,
749+ NtStmt ( stmt) => stmt. span ,
750+ NtPat ( pat) => pat. span ,
751+ NtExpr ( expr) | NtLiteral ( expr) => expr. span ,
752+ NtTy ( ty) => ty. span ,
753+ NtIdent ( ident, _) | NtLifetime ( ident) => ident. span ,
754+ NtMeta ( attr_item) => attr_item. span ( ) ,
755+ NtPath ( path) => path. span ,
756+ NtVis ( vis) => vis. span ,
757+ NtTT ( tt) => tt. span ( ) ,
758+ }
759+ }
760+ }
761+
717762impl PartialEq for Nonterminal {
718763 fn eq ( & self , rhs : & Self ) -> bool {
719764 match ( self , rhs) {
0 commit comments