33use base_db:: { salsa, CrateId , Edition , SourceDatabase } ;
44use either:: Either ;
55use limit:: Limit ;
6- use mbe:: syntax_node_to_token_tree;
6+ use mbe:: { syntax_node_to_token_tree, ValueResult } ;
77use rustc_hash:: FxHashSet ;
88use syntax:: {
99 ast:: { self , HasAttrs , HasDocComments } ,
@@ -124,16 +124,21 @@ pub trait ExpandDatabase: SourceDatabase {
124124 fn macro_arg (
125125 & self ,
126126 id : MacroCallId ,
127- ) -> Option < Arc < ( tt:: Subtree , mbe:: TokenMap , fixup:: SyntaxFixupUndoInfo ) > > ;
127+ ) -> ValueResult <
128+ Option < Arc < ( tt:: Subtree , mbe:: TokenMap , fixup:: SyntaxFixupUndoInfo ) > > ,
129+ Arc < Box < [ SyntaxError ] > > ,
130+ > ;
128131 /// Extracts syntax node, corresponding to a macro call. That's a firewall
129132 /// query, only typing in the macro call itself changes the returned
130133 /// subtree.
131- fn macro_arg_text ( & self , id : MacroCallId ) -> Option < GreenNode > ;
132- /// Gets the expander for this macro. This compiles declarative macros, and
133- /// just fetches procedural ones.
134- // FIXME: Rename this
134+ fn macro_arg_node (
135+ & self ,
136+ id : MacroCallId ,
137+ ) -> ValueResult < Option < GreenNode > , Arc < Box < [ SyntaxError ] > > > ;
138+ /// Fetches the expander for this macro.
135139 #[ salsa:: transparent]
136- fn macro_def ( & self , id : MacroDefId ) -> TokenExpander ;
140+ fn macro_expander ( & self , id : MacroDefId ) -> TokenExpander ;
141+ /// Fetches (and compiles) the expander of this decl macro.
137142 fn decl_macro_expander (
138143 & self ,
139144 def_crate : CrateId ,
@@ -335,14 +340,20 @@ fn parse_macro_expansion_error(
335340fn macro_arg (
336341 db : & dyn ExpandDatabase ,
337342 id : MacroCallId ,
338- ) -> Option < Arc < ( tt:: Subtree , mbe:: TokenMap , fixup:: SyntaxFixupUndoInfo ) > > {
343+ ) -> ValueResult <
344+ Option < Arc < ( tt:: Subtree , mbe:: TokenMap , fixup:: SyntaxFixupUndoInfo ) > > ,
345+ Arc < Box < [ SyntaxError ] > > ,
346+ > {
339347 let loc = db. lookup_intern_macro_call ( id) ;
340348
341349 if let Some ( EagerCallInfo { arg, arg_id : _, error : _ } ) = loc. eager . as_deref ( ) {
342- return Some ( Arc :: new ( ( arg. 0 . clone ( ) , arg. 1 . clone ( ) , Default :: default ( ) ) ) ) ;
350+ return ValueResult :: ok ( Some ( Arc :: new ( ( arg. 0 . clone ( ) , arg. 1 . clone ( ) , Default :: default ( ) ) ) ) ) ;
343351 }
344352
345- let arg = db. macro_arg_text ( id) ?;
353+ let ValueResult { value, err } = db. macro_arg_node ( id) ;
354+ let Some ( arg) = value else {
355+ return ValueResult { value : None , err } ;
356+ } ;
346357
347358 let node = SyntaxNode :: new_root ( arg) ;
348359 let censor = censor_for_macro_input ( & loc, & node) ;
@@ -360,7 +371,11 @@ fn macro_arg(
360371 // proc macros expect their inputs without parentheses, MBEs expect it with them included
361372 tt. delimiter = tt:: Delimiter :: unspecified ( ) ;
362373 }
363- Some ( Arc :: new ( ( tt, tmap, fixups. undo_info ) ) )
374+ let val = Some ( Arc :: new ( ( tt, tmap, fixups. undo_info ) ) ) ;
375+ match err {
376+ Some ( err) => ValueResult :: new ( val, err) ,
377+ None => ValueResult :: ok ( val) ,
378+ }
364379}
365380
366381/// Certain macro calls expect some nodes in the input to be preprocessed away, namely:
@@ -402,9 +417,44 @@ fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet<Sy
402417 . unwrap_or_default ( )
403418}
404419
405- fn macro_arg_text ( db : & dyn ExpandDatabase , id : MacroCallId ) -> Option < GreenNode > {
420+ fn macro_arg_node (
421+ db : & dyn ExpandDatabase ,
422+ id : MacroCallId ,
423+ ) -> ValueResult < Option < GreenNode > , Arc < Box < [ SyntaxError ] > > > {
424+ let err = || -> Arc < Box < [ _ ] > > {
425+ Arc :: new ( Box :: new ( [ SyntaxError :: new_at_offset (
426+ "invalid macro call" . to_owned ( ) ,
427+ syntax:: TextSize :: from ( 0 ) ,
428+ ) ] ) )
429+ } ;
406430 let loc = db. lookup_intern_macro_call ( id) ;
407- let arg = loc. kind . arg ( db) ?. value ;
431+ let arg = if let MacroDefKind :: BuiltInEager ( ..) = loc. def . kind {
432+ let res = if let Some ( EagerCallInfo { arg, .. } ) = loc. eager . as_deref ( ) {
433+ Some ( mbe:: token_tree_to_syntax_node ( & arg. 0 , mbe:: TopEntryPoint :: Expr ) . 0 )
434+ } else {
435+ loc. kind
436+ . arg ( db)
437+ . and_then ( |arg| ast:: TokenTree :: cast ( arg. value ) )
438+ . map ( |tt| tt. reparse_as_expr ( ) . to_syntax ( ) )
439+ } ;
440+
441+ match res {
442+ Some ( res) if res. errors ( ) . is_empty ( ) => res. syntax_node ( ) ,
443+ Some ( res) => {
444+ return ValueResult :: new (
445+ Some ( res. syntax_node ( ) . green ( ) . into ( ) ) ,
446+ // Box::<[_]>::from(res.errors()), not stable yet
447+ Arc :: new ( res. errors ( ) . to_vec ( ) . into_boxed_slice ( ) ) ,
448+ ) ;
449+ }
450+ None => return ValueResult :: only_err ( err ( ) ) ,
451+ }
452+ } else {
453+ match loc. kind . arg ( db) {
454+ Some ( res) => res. value ,
455+ None => return ValueResult :: only_err ( err ( ) ) ,
456+ }
457+ } ;
408458 if matches ! ( loc. kind, MacroCallKind :: FnLike { .. } ) {
409459 let first = arg. first_child_or_token ( ) . map_or ( T ! [ . ] , |it| it. kind ( ) ) ;
410460 let last = arg. last_child_or_token ( ) . map_or ( T ! [ . ] , |it| it. kind ( ) ) ;
@@ -419,20 +469,13 @@ fn macro_arg_text(db: &dyn ExpandDatabase, id: MacroCallId) -> Option<GreenNode>
419469 // Some day, we'll have explicit recursion counters for all
420470 // recursive things, at which point this code might be removed.
421471 cov_mark:: hit!( issue9358_bad_macro_stack_overflow) ;
422- return None ;
472+ return ValueResult :: only_err ( Arc :: new ( Box :: new ( [ SyntaxError :: new (
473+ "unbalanced token tree" . to_owned ( ) ,
474+ arg. text_range ( ) ,
475+ ) ] ) ) ) ;
423476 }
424477 }
425- if let Some ( EagerCallInfo { arg, .. } ) = loc. eager . as_deref ( ) {
426- Some (
427- mbe:: token_tree_to_syntax_node ( & arg. 0 , mbe:: TopEntryPoint :: Expr )
428- . 0
429- . syntax_node ( )
430- . green ( )
431- . into ( ) ,
432- )
433- } else {
434- Some ( arg. green ( ) . into ( ) )
435- }
478+ ValueResult :: ok ( Some ( arg. green ( ) . into ( ) ) )
436479}
437480
438481fn decl_macro_expander (
@@ -474,7 +517,7 @@ fn decl_macro_expander(
474517 Arc :: new ( DeclarativeMacroExpander { mac, def_site_token_map } )
475518}
476519
477- fn macro_def ( db : & dyn ExpandDatabase , id : MacroDefId ) -> TokenExpander {
520+ fn macro_expander ( db : & dyn ExpandDatabase , id : MacroDefId ) -> TokenExpander {
478521 match id. kind {
479522 MacroDefKind :: Declarative ( ast_id) => {
480523 TokenExpander :: DeclarativeMacro ( db. decl_macro_expander ( id. krate , ast_id) )
@@ -491,20 +534,10 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
491534 let _p = profile:: span ( "macro_expand" ) ;
492535 let loc = db. lookup_intern_macro_call ( id) ;
493536
494- // This might look a bit odd, but we do not expand the inputs to eager macros here.
495- // Eager macros inputs are expanded, well, eagerly when we collect the macro calls.
496- // That kind of expansion uses the ast id map of an eager macros input though which goes through
497- // the HirFileId machinery. As eager macro inputs are assigned a macro file id that query
498- // will end up going through here again, whereas we want to just want to inspect the raw input.
499- // As such we just return the input subtree here.
500- if let Some ( EagerCallInfo { arg, arg_id : None , error } ) = loc. eager . as_deref ( ) {
501- return ExpandResult { value : Arc :: new ( arg. 0 . clone ( ) ) , err : error. clone ( ) } ;
502- }
503-
504- let ( ExpandResult { value : mut tt, mut err } , tmap) = match loc. def . kind {
537+ let ExpandResult { value : tt, mut err } = match loc. def . kind {
505538 MacroDefKind :: ProcMacro ( ..) => return db. expand_proc_macro ( id) ,
506539 MacroDefKind :: BuiltInDerive ( expander, ..) => {
507- let arg = db. macro_arg_text ( id) . unwrap ( ) ;
540+ let arg = db. macro_arg_node ( id) . value . unwrap ( ) ;
508541
509542 let node = SyntaxNode :: new_root ( arg) ;
510543 let censor = censor_for_macro_input ( & loc, & node) ;
@@ -520,10 +553,13 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
520553
521554 // this cast is a bit sus, can we avoid losing the typedness here?
522555 let adt = ast:: Adt :: cast ( node) . unwrap ( ) ;
523- ( expander. expand ( db, id, & adt, & tmap) , Some ( ( tmap, fixups. undo_info ) ) )
556+ let mut res = expander. expand ( db, id, & adt, & tmap) ;
557+ fixup:: reverse_fixups ( & mut res. value , & tmap, & fixups. undo_info ) ;
558+ res
524559 }
525560 _ => {
526- let Some ( macro_arg) = db. macro_arg ( id) else {
561+ let ValueResult { value, err } = db. macro_arg ( id) ;
562+ let Some ( macro_arg) = value else {
527563 return ExpandResult {
528564 value : Arc :: new ( tt:: Subtree {
529565 delimiter : tt:: Delimiter :: UNSPECIFIED ,
@@ -534,18 +570,43 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
534570 err : Some ( ExpandError :: other ( "invalid token tree" ) ) ,
535571 } ;
536572 } ;
573+
537574 let ( arg, arg_tm, undo_info) = & * macro_arg;
538575 let mut res = match loc. def . kind {
539576 MacroDefKind :: Declarative ( id) => {
540577 db. decl_macro_expander ( loc. def . krate , id) . expand ( arg. clone ( ) )
541578 }
542579 MacroDefKind :: BuiltIn ( it, _) => it. expand ( db, id, & arg) . map_err ( Into :: into) ,
580+ // This might look a bit odd, but we do not expand the inputs to eager macros here.
581+ // Eager macros inputs are expanded, well, eagerly when we collect the macro calls.
582+ // That kind of expansion uses the ast id map of an eager macros input though which goes through
583+ // the HirFileId machinery. As eager macro inputs are assigned a macro file id that query
584+ // will end up going through here again, whereas we want to just want to inspect the raw input.
585+ // As such we just return the input subtree here.
586+ MacroDefKind :: BuiltInEager ( ..) if loc. eager . is_none ( ) => {
587+ let mut arg = arg. clone ( ) ;
588+ fixup:: reverse_fixups ( & mut arg, arg_tm, undo_info) ;
589+
590+ return ExpandResult {
591+ value : Arc :: new ( arg) ,
592+ err : err. map ( |err| {
593+ let mut buf = String :: new ( ) ;
594+ for err in & * * err {
595+ use std:: fmt:: Write ;
596+ _ = write ! ( buf, "{}, " , err) ;
597+ }
598+ buf. pop ( ) ;
599+ buf. pop ( ) ;
600+ ExpandError :: other ( buf)
601+ } ) ,
602+ } ;
603+ }
543604 MacroDefKind :: BuiltInEager ( it, _) => it. expand ( db, id, & arg) . map_err ( Into :: into) ,
544605 MacroDefKind :: BuiltInAttr ( it, _) => it. expand ( db, id, & arg) ,
545606 _ => unreachable ! ( ) ,
546607 } ;
547608 fixup:: reverse_fixups ( & mut res. value , arg_tm, undo_info) ;
548- ( res, None )
609+ res
549610 }
550611 } ;
551612
@@ -559,24 +620,23 @@ fn macro_expand(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt
559620 return value;
560621 }
561622
562- if let Some ( ( arg_tm, undo_info) ) = & tmap {
563- fixup:: reverse_fixups ( & mut tt, arg_tm, undo_info) ;
564- }
565-
566623 ExpandResult { value : Arc :: new ( tt) , err }
567624}
568625
569626fn expand_proc_macro ( db : & dyn ExpandDatabase , id : MacroCallId ) -> ExpandResult < Arc < tt:: Subtree > > {
570627 let loc = db. lookup_intern_macro_call ( id) ;
571- let Some ( macro_arg) = db. macro_arg ( id) else {
628+ let Some ( macro_arg) = db. macro_arg ( id) . value else {
572629 return ExpandResult {
573630 value : Arc :: new ( tt:: Subtree {
574631 delimiter : tt:: Delimiter :: UNSPECIFIED ,
575632 token_trees : Vec :: new ( ) ,
576633 } ) ,
634+ // FIXME: We should make sure to enforce an invariant that invalid macro
635+ // calls do not reach this call path!
577636 err : Some ( ExpandError :: other ( "invalid token tree" ) ) ,
578637 } ;
579638 } ;
639+
580640 let ( arg_tt, arg_tm, undo_info) = & * macro_arg;
581641
582642 let expander = match loc. def . kind {
0 commit comments