@@ -19,14 +19,14 @@ use crate::{
1919} ;
2020
2121macro_rules! register_builtin {
22- ( LAZY : $( ( $name: ident, $kind: ident) => $expand: ident) ,* , EAGER : $( ( $e_name: ident, $e_kind: ident) => $e_expand: ident) ,* ) => {
22+ ( $ LAZY: ident : $( ( $name: ident, $kind: ident) => $expand: ident) ,* , $ EAGER: ident : $( ( $e_name: ident, $e_kind: ident) => $e_expand: ident) ,* ) => {
2323 #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
24- pub enum BuiltinFnLikeExpander {
24+ pub enum $LAZY {
2525 $( $kind) ,*
2626 }
2727
2828 #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
29- pub enum EagerExpander {
29+ pub enum $EAGER {
3030 $( $e_kind) ,*
3131 }
3232
@@ -84,6 +84,17 @@ impl EagerExpander {
8484 pub fn is_include ( & self ) -> bool {
8585 matches ! ( self , EagerExpander :: Include )
8686 }
87+
88+ pub fn is_include_like ( & self ) -> bool {
89+ matches ! (
90+ self ,
91+ EagerExpander :: Include | EagerExpander :: IncludeStr | EagerExpander :: IncludeBytes
92+ )
93+ }
94+
95+ pub fn is_env_or_option_env ( & self ) -> bool {
96+ matches ! ( self , EagerExpander :: Env | EagerExpander :: OptionEnv )
97+ }
8798}
8899
89100pub fn find_builtin_macro (
@@ -93,7 +104,7 @@ pub fn find_builtin_macro(
93104}
94105
95106register_builtin ! {
96- LAZY :
107+ BuiltinFnLikeExpander :
97108 ( column, Column ) => line_expand,
98109 ( file, File ) => file_expand,
99110 ( line, Line ) => line_expand,
@@ -114,7 +125,7 @@ register_builtin! {
114125 ( format_args_nl, FormatArgsNl ) => format_args_nl_expand,
115126 ( quote, Quote ) => quote_expand,
116127
117- EAGER :
128+ EagerExpander :
118129 ( compile_error, CompileError ) => compile_error_expand,
119130 ( concat, Concat ) => concat_expand,
120131 ( concat_idents, ConcatIdents ) => concat_idents_expand,
@@ -426,22 +437,25 @@ fn use_panic_2021(db: &dyn ExpandDatabase, span: Span) -> bool {
426437 }
427438}
428439
429- fn unquote_str ( lit : & tt:: Literal ) -> Option < String > {
440+ fn unquote_str ( lit : & tt:: Literal ) -> Option < ( String , Span ) > {
441+ let span = lit. span ;
430442 let lit = ast:: make:: tokens:: literal ( & lit. to_string ( ) ) ;
431443 let token = ast:: String :: cast ( lit) ?;
432- token. value ( ) . map ( |it| it. into_owned ( ) )
444+ token. value ( ) . map ( |it| ( it. into_owned ( ) , span ) )
433445}
434446
435- fn unquote_char ( lit : & tt:: Literal ) -> Option < char > {
447+ fn unquote_char ( lit : & tt:: Literal ) -> Option < ( char , Span ) > {
448+ let span = lit. span ;
436449 let lit = ast:: make:: tokens:: literal ( & lit. to_string ( ) ) ;
437450 let token = ast:: Char :: cast ( lit) ?;
438- token. value ( )
451+ token. value ( ) . zip ( Some ( span ) )
439452}
440453
441- fn unquote_byte_string ( lit : & tt:: Literal ) -> Option < Vec < u8 > > {
454+ fn unquote_byte_string ( lit : & tt:: Literal ) -> Option < ( Vec < u8 > , Span ) > {
455+ let span = lit. span ;
442456 let lit = ast:: make:: tokens:: literal ( & lit. to_string ( ) ) ;
443457 let token = ast:: ByteString :: cast ( lit) ?;
444- token. value ( ) . map ( |it| it. into_owned ( ) )
458+ token. value ( ) . map ( |it| ( it. into_owned ( ) , span ) )
445459}
446460
447461fn compile_error_expand (
@@ -452,7 +466,7 @@ fn compile_error_expand(
452466) -> ExpandResult < tt:: Subtree > {
453467 let err = match & * tt. token_trees {
454468 [ tt:: TokenTree :: Leaf ( tt:: Leaf :: Literal ( it) ) ] => match unquote_str ( it) {
455- Some ( unquoted) => ExpandError :: other ( unquoted. into_boxed_str ( ) ) ,
469+ Some ( ( unquoted, _ ) ) => ExpandError :: other ( unquoted. into_boxed_str ( ) ) ,
456470 None => ExpandError :: other ( "`compile_error!` argument must be a string" ) ,
457471 } ,
458472 _ => ExpandError :: other ( "`compile_error!` argument must be a string" ) ,
@@ -465,10 +479,16 @@ fn concat_expand(
465479 _db : & dyn ExpandDatabase ,
466480 _arg_id : MacroCallId ,
467481 tt : & tt:: Subtree ,
468- span : Span ,
482+ _ : Span ,
469483) -> ExpandResult < tt:: Subtree > {
470484 let mut err = None ;
471485 let mut text = String :: new ( ) ;
486+ let mut span: Option < Span > = None ;
487+ let mut record_span = |s : Span | match & mut span {
488+ Some ( span) if span. anchor == s. anchor => span. range = span. range . cover ( s. range ) ,
489+ Some ( _) => ( ) ,
490+ None => span = Some ( s) ,
491+ } ;
472492 for ( i, mut t) in tt. token_trees . iter ( ) . enumerate ( ) {
473493 // FIXME: hack on top of a hack: `$e:expr` captures get surrounded in parentheses
474494 // to ensure the right parsing order, so skip the parentheses here. Ideally we'd
@@ -486,44 +506,56 @@ fn concat_expand(
486506 // concat works with string and char literals, so remove any quotes.
487507 // It also works with integer, float and boolean literals, so just use the rest
488508 // as-is.
489- if let Some ( c ) = unquote_char ( it) {
509+ if let Some ( ( c , span ) ) = unquote_char ( it) {
490510 text. push ( c) ;
511+ record_span ( span) ;
491512 } else {
492- let component = unquote_str ( it) . unwrap_or_else ( || it. text . to_string ( ) ) ;
513+ let ( component, span) =
514+ unquote_str ( it) . unwrap_or_else ( || ( it. text . to_string ( ) , it. span ) ) ;
493515 text. push_str ( & component) ;
516+ record_span ( span) ;
494517 }
495518 }
496519 // handle boolean literals
497520 tt:: TokenTree :: Leaf ( tt:: Leaf :: Ident ( id) )
498521 if i % 2 == 0 && ( id. text == "true" || id. text == "false" ) =>
499522 {
500523 text. push_str ( id. text . as_str ( ) ) ;
524+ record_span ( id. span ) ;
501525 }
502526 tt:: TokenTree :: Leaf ( tt:: Leaf :: Punct ( punct) ) if i % 2 == 1 && punct. char == ',' => ( ) ,
503527 _ => {
504528 err. get_or_insert ( mbe:: ExpandError :: UnexpectedToken . into ( ) ) ;
505529 }
506530 }
507531 }
532+ let span = span. unwrap_or ( tt. delimiter . open ) ;
508533 ExpandResult { value : quote ! ( span =>#text) , err }
509534}
510535
511536fn concat_bytes_expand (
512537 _db : & dyn ExpandDatabase ,
513538 _arg_id : MacroCallId ,
514539 tt : & tt:: Subtree ,
515- span : Span ,
540+ call_site : Span ,
516541) -> ExpandResult < tt:: Subtree > {
517542 let mut bytes = Vec :: new ( ) ;
518543 let mut err = None ;
544+ let mut span: Option < Span > = None ;
545+ let mut record_span = |s : Span | match & mut span {
546+ Some ( span) if span. anchor == s. anchor => span. range = span. range . cover ( s. range ) ,
547+ Some ( _) => ( ) ,
548+ None => span = Some ( s) ,
549+ } ;
519550 for ( i, t) in tt. token_trees . iter ( ) . enumerate ( ) {
520551 match t {
521552 tt:: TokenTree :: Leaf ( tt:: Leaf :: Literal ( lit) ) => {
522553 let token = ast:: make:: tokens:: literal ( & lit. to_string ( ) ) ;
554+ record_span ( lit. span ) ;
523555 match token. kind ( ) {
524556 syntax:: SyntaxKind :: BYTE => bytes. push ( token. text ( ) . to_owned ( ) ) ,
525557 syntax:: SyntaxKind :: BYTE_STRING => {
526- let components = unquote_byte_string ( lit) . unwrap_or_default ( ) ;
558+ let components = unquote_byte_string ( lit) . map_or ( vec ! [ ] , | ( it , _ ) | it ) ;
527559 components. into_iter ( ) . for_each ( |it| bytes. push ( it. to_string ( ) ) ) ;
528560 }
529561 _ => {
@@ -534,7 +566,7 @@ fn concat_bytes_expand(
534566 }
535567 tt:: TokenTree :: Leaf ( tt:: Leaf :: Punct ( punct) ) if i % 2 == 1 && punct. char == ',' => ( ) ,
536568 tt:: TokenTree :: Subtree ( tree) if tree. delimiter . kind == tt:: DelimiterKind :: Bracket => {
537- if let Err ( e) = concat_bytes_expand_subtree ( tree, & mut bytes) {
569+ if let Err ( e) = concat_bytes_expand_subtree ( tree, & mut bytes, & mut record_span ) {
538570 err. get_or_insert ( e) ;
539571 break ;
540572 }
@@ -546,17 +578,24 @@ fn concat_bytes_expand(
546578 }
547579 }
548580 let value = tt:: Subtree {
549- delimiter : tt:: Delimiter { open : span, close : span, kind : tt:: DelimiterKind :: Bracket } ,
581+ delimiter : tt:: Delimiter {
582+ open : call_site,
583+ close : call_site,
584+ kind : tt:: DelimiterKind :: Bracket ,
585+ } ,
550586 token_trees : {
551587 Itertools :: intersperse_with (
552588 bytes. into_iter ( ) . map ( |it| {
553- tt:: TokenTree :: Leaf ( tt:: Leaf :: Literal ( tt:: Literal { text : it. into ( ) , span } ) )
589+ tt:: TokenTree :: Leaf ( tt:: Leaf :: Literal ( tt:: Literal {
590+ text : it. into ( ) ,
591+ span : span. unwrap_or ( call_site) ,
592+ } ) )
554593 } ) ,
555594 || {
556595 tt:: TokenTree :: Leaf ( tt:: Leaf :: Punct ( tt:: Punct {
557596 char : ',' ,
558597 spacing : tt:: Spacing :: Alone ,
559- span,
598+ span : call_site ,
560599 } ) )
561600 } ,
562601 )
@@ -569,13 +608,15 @@ fn concat_bytes_expand(
569608fn concat_bytes_expand_subtree (
570609 tree : & tt:: Subtree ,
571610 bytes : & mut Vec < String > ,
611+ mut record_span : impl FnMut ( Span ) ,
572612) -> Result < ( ) , ExpandError > {
573613 for ( ti, tt) in tree. token_trees . iter ( ) . enumerate ( ) {
574614 match tt {
575- tt:: TokenTree :: Leaf ( tt:: Leaf :: Literal ( lit ) ) => {
576- let lit = ast:: make:: tokens:: literal ( & lit . to_string ( ) ) ;
615+ tt:: TokenTree :: Leaf ( tt:: Leaf :: Literal ( it ) ) => {
616+ let lit = ast:: make:: tokens:: literal ( & it . to_string ( ) ) ;
577617 match lit. kind ( ) {
578618 syntax:: SyntaxKind :: BYTE | syntax:: SyntaxKind :: INT_NUMBER => {
619+ record_span ( it. span ) ;
579620 bytes. push ( lit. text ( ) . to_owned ( ) )
580621 }
581622 _ => {
@@ -635,7 +676,7 @@ fn relative_file(
635676 }
636677}
637678
638- fn parse_string ( tt : & tt:: Subtree ) -> Result < String , ExpandError > {
679+ fn parse_string ( tt : & tt:: Subtree ) -> Result < ( String , Span ) , ExpandError > {
639680 tt. token_trees
640681 . first ( )
641682 . and_then ( |tt| match tt {
@@ -675,7 +716,7 @@ pub fn include_input_to_file_id(
675716 arg_id : MacroCallId ,
676717 arg : & tt:: Subtree ,
677718) -> Result < FileId , ExpandError > {
678- relative_file ( db, arg_id, & parse_string ( arg) ?, false )
719+ relative_file ( db, arg_id, & parse_string ( arg) ?. 0 , false )
679720}
680721
681722fn include_bytes_expand (
@@ -701,7 +742,7 @@ fn include_str_expand(
701742 tt : & tt:: Subtree ,
702743 span : Span ,
703744) -> ExpandResult < tt:: Subtree > {
704- let path = match parse_string ( tt) {
745+ let ( path, span ) = match parse_string ( tt) {
705746 Ok ( it) => it,
706747 Err ( e) => {
707748 return ExpandResult :: new ( tt:: Subtree :: empty ( DelimSpan { open : span, close : span } ) , e)
@@ -736,7 +777,7 @@ fn env_expand(
736777 tt : & tt:: Subtree ,
737778 span : Span ,
738779) -> ExpandResult < tt:: Subtree > {
739- let key = match parse_string ( tt) {
780+ let ( key, span ) = match parse_string ( tt) {
740781 Ok ( it) => it,
741782 Err ( e) => {
742783 return ExpandResult :: new ( tt:: Subtree :: empty ( DelimSpan { open : span, close : span } ) , e)
@@ -766,18 +807,24 @@ fn option_env_expand(
766807 db : & dyn ExpandDatabase ,
767808 arg_id : MacroCallId ,
768809 tt : & tt:: Subtree ,
769- span : Span ,
810+ call_site : Span ,
770811) -> ExpandResult < tt:: Subtree > {
771- let key = match parse_string ( tt) {
812+ let ( key, span ) = match parse_string ( tt) {
772813 Ok ( it) => it,
773814 Err ( e) => {
774- return ExpandResult :: new ( tt:: Subtree :: empty ( DelimSpan { open : span, close : span } ) , e)
815+ return ExpandResult :: new (
816+ tt:: Subtree :: empty ( DelimSpan { open : call_site, close : call_site } ) ,
817+ e,
818+ )
775819 }
776820 } ;
777- let dollar_crate = dollar_crate ( span ) ;
821+ let dollar_crate = dollar_crate ( call_site ) ;
778822 let expanded = match get_env_inner ( db, arg_id, & key) {
779- None => quote ! { span => #dollar_crate:: option:: Option :: None :: <& str > } ,
780- Some ( s) => quote ! { span => #dollar_crate:: option:: Option :: Some ( #s) } ,
823+ None => quote ! { call_site => #dollar_crate:: option:: Option :: None :: <& str > } ,
824+ Some ( s) => {
825+ let s = quote ! ( span => #s) ;
826+ quote ! { call_site => #dollar_crate:: option:: Option :: Some ( #s) }
827+ }
781828 } ;
782829
783830 ExpandResult :: ok ( expanded)
0 commit comments