2020-03-02 06:05:15 +00:00
//! Eager expansion related utils
2020-03-02 16:10:20 +00:00
//!
//! Here is a dump of a discussion from Vadim Petrochenkov about Eager Expansion and
//! Its name resolution :
//!
//! > Eagerly expanded macros (and also macros eagerly expanded by eagerly expanded macros,
//! > which actually happens in practice too!) are resolved at the location of the "root" macro
//! > that performs the eager expansion on its arguments.
//! > If some name cannot be resolved at the eager expansion time it's considered unresolved,
//! > even if becomes available later (e.g. from a glob import or other macro).
//!
//! > Eagerly expanded macros don't add anything to the module structure of the crate and
//! > don't build any speculative module structures, i.e. they are expanded in a "flat"
//! > way even if tokens in them look like modules.
//!
//! > In other words, it kinda works for simple cases for which it was originally intended,
//! > and we need to live with it because it's available on stable and widely relied upon.
//!
//!
2021-06-14 04:57:10 +00:00
//! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
2023-12-18 12:30:41 +00:00
use base_db ::CrateId ;
2023-12-20 11:53:46 +00:00
use span ::Span ;
2023-12-11 09:16:01 +00:00
use syntax ::{ ted , Parse , SyntaxElement , SyntaxNode , TextSize , WalkEvent } ;
2023-06-05 09:04:23 +00:00
use triomphe ::Arc ;
2020-03-02 06:05:15 +00:00
use crate ::{
ast ::{ self , AstNode } ,
2023-03-20 06:31:01 +00:00
db ::ExpandDatabase ,
2022-01-26 17:31:07 +00:00
mod_path ::ModPath ,
2023-12-18 12:30:41 +00:00
span_map ::SpanMapRef ,
2023-12-11 09:16:01 +00:00
EagerCallInfo , ExpandError , ExpandResult , ExpandTo , ExpansionSpanMap , InFile , MacroCallId ,
MacroCallKind , MacroCallLoc , MacroDefId , MacroDefKind ,
2020-03-02 06:05:15 +00:00
} ;
2023-06-19 06:14:04 +00:00
pub fn expand_eager_macro_input (
2023-03-20 06:31:01 +00:00
db : & dyn ExpandDatabase ,
2020-06-11 10:08:24 +00:00
krate : CrateId ,
2020-03-03 17:13:20 +00:00
macro_call : InFile < ast ::MacroCall > ,
def : MacroDefId ,
2023-12-20 11:53:46 +00:00
call_site : Span ,
2022-01-26 17:31:07 +00:00
resolver : & dyn Fn ( ModPath ) -> Option < MacroDefId > ,
2023-08-07 09:03:15 +00:00
) -> ExpandResult < Option < MacroCallId > > {
2020-12-22 13:42:28 +00:00
let ast_map = db . ast_id_map ( macro_call . file_id ) ;
2023-07-17 13:49:15 +00:00
// the expansion which the ast id map is built upon has no whitespace, so the offsets are wrong as macro_call is from the token tree that has whitespace!
2020-12-22 13:42:28 +00:00
let call_id = InFile ::new ( macro_call . file_id , ast_map . ast_id ( & macro_call . value ) ) ;
2021-09-05 19:30:06 +00:00
let expand_to = ExpandTo ::from_call_site ( & macro_call . value ) ;
2020-12-22 13:42:28 +00:00
2020-03-03 18:41:33 +00:00
// Note:
2023-06-05 09:04:23 +00:00
// When `lazy_expand` is called, its *parent* file must already exist.
// Here we store an eager macro id for the argument expanded subtree
2020-03-03 18:41:33 +00:00
// for that purpose.
2021-11-14 15:25:40 +00:00
let arg_id = db . intern_macro_call ( MacroCallLoc {
2021-05-19 18:19:08 +00:00
def ,
krate ,
2023-07-17 13:49:15 +00:00
eager : None ,
2021-09-05 19:30:06 +00:00
kind : MacroCallKind ::FnLike { ast_id : call_id , expand_to : ExpandTo ::Expr } ,
2023-12-11 09:16:01 +00:00
call_site ,
2020-03-06 14:58:45 +00:00
} ) ;
2023-07-17 13:49:15 +00:00
let ExpandResult { value : ( arg_exp , arg_exp_map ) , err : parse_err } =
db . parse_macro_expansion ( arg_id . as_macro_file ( ) ) ;
2023-12-11 09:16:01 +00:00
let mut arg_map = ExpansionSpanMap ::empty ( ) ;
2023-07-17 13:49:15 +00:00
let ExpandResult { value : expanded_eager_input , err } = {
eager_macro_recur (
db ,
2023-12-11 09:16:01 +00:00
& arg_exp_map ,
& mut arg_map ,
TextSize ::new ( 0 ) ,
2023-07-17 13:49:15 +00:00
InFile ::new ( arg_id . as_file ( ) , arg_exp . syntax_node ( ) ) ,
krate ,
2023-12-11 09:16:01 +00:00
call_site ,
2023-07-17 13:49:15 +00:00
resolver ,
2023-08-07 09:03:15 +00:00
)
2023-06-19 06:14:04 +00:00
} ;
2023-07-17 13:49:15 +00:00
let err = parse_err . or ( err ) ;
2023-12-11 09:55:43 +00:00
if cfg! ( debug_assertions ) {
2023-12-11 09:16:01 +00:00
arg_map . finish ( ) ;
}
2023-07-17 13:49:15 +00:00
2023-12-11 09:16:01 +00:00
let Some ( ( expanded_eager_input , _mapping ) ) = expanded_eager_input else {
2023-08-07 09:03:15 +00:00
return ExpandResult { value : None , err } ;
2023-06-05 09:04:23 +00:00
} ;
2023-07-17 13:49:15 +00:00
2023-12-11 09:16:01 +00:00
let mut subtree = mbe ::syntax_node_to_token_tree ( & expanded_eager_input , arg_map ) ;
2023-07-17 13:49:15 +00:00
2023-12-11 09:16:01 +00:00
subtree . delimiter = crate ::tt ::Delimiter ::DUMMY_INVISIBLE ;
2020-03-03 17:13:20 +00:00
2023-06-05 09:04:23 +00:00
let loc = MacroCallLoc {
def ,
krate ,
2023-12-14 13:11:12 +00:00
eager : Some ( Arc ::new ( EagerCallInfo { arg : Arc ::new ( subtree ) , arg_id , error : err . clone ( ) } ) ) ,
2023-06-05 09:04:23 +00:00
kind : MacroCallKind ::FnLike { ast_id : call_id , expand_to } ,
2023-12-11 09:16:01 +00:00
call_site ,
2023-06-05 09:04:23 +00:00
} ;
2023-08-07 09:03:15 +00:00
ExpandResult { value : Some ( db . intern_macro_call ( loc ) ) , err }
2020-03-02 06:05:15 +00:00
}
fn lazy_expand (
2023-03-20 06:31:01 +00:00
db : & dyn ExpandDatabase ,
2020-03-02 06:05:15 +00:00
def : & MacroDefId ,
macro_call : InFile < ast ::MacroCall > ,
2020-06-11 10:08:24 +00:00
krate : CrateId ,
2023-12-20 11:53:46 +00:00
call_site : Span ,
2023-12-11 09:16:01 +00:00
) -> ExpandResult < ( InFile < Parse < SyntaxNode > > , Arc < ExpansionSpanMap > ) > {
2020-03-02 06:05:15 +00:00
let ast_id = db . ast_id_map ( macro_call . file_id ) . ast_id ( & macro_call . value ) ;
2021-09-05 19:30:06 +00:00
let expand_to = ExpandTo ::from_call_site ( & macro_call . value ) ;
2023-07-17 13:49:15 +00:00
let ast_id = macro_call . with_value ( ast_id ) ;
2023-12-11 09:16:01 +00:00
let id = def . as_lazy_macro ( db , krate , MacroCallKind ::FnLike { ast_id , expand_to } , call_site ) ;
2023-06-19 06:14:04 +00:00
let macro_file = id . as_macro_file ( ) ;
2023-07-17 13:49:15 +00:00
db . parse_macro_expansion ( macro_file )
. map ( | parse | ( InFile ::new ( macro_file . into ( ) , parse . 0 ) , parse . 1 ) )
2020-03-02 06:05:15 +00:00
}
fn eager_macro_recur (
2023-03-20 06:31:01 +00:00
db : & dyn ExpandDatabase ,
2023-12-11 09:16:01 +00:00
span_map : & ExpansionSpanMap ,
expanded_map : & mut ExpansionSpanMap ,
mut offset : TextSize ,
2020-03-02 06:05:15 +00:00
curr : InFile < SyntaxNode > ,
2020-06-11 10:08:24 +00:00
krate : CrateId ,
2023-12-20 11:53:46 +00:00
call_site : Span ,
2022-01-26 17:31:07 +00:00
macro_resolver : & dyn Fn ( ModPath ) -> Option < MacroDefId > ,
2023-12-11 09:16:01 +00:00
) -> ExpandResult < Option < ( SyntaxNode , TextSize ) > > {
2021-05-26 15:34:50 +00:00
let original = curr . value . clone_for_update ( ) ;
2020-03-02 06:05:15 +00:00
2021-04-19 17:28:41 +00:00
let mut replacements = Vec ::new ( ) ;
2020-03-02 06:05:15 +00:00
2023-08-07 09:03:15 +00:00
// FIXME: We only report a single error inside of eager expansions
2023-06-05 09:04:23 +00:00
let mut error = None ;
2023-07-17 13:49:15 +00:00
let mut children = original . preorder_with_tokens ( ) ;
2023-06-05 09:04:23 +00:00
2020-03-02 06:05:15 +00:00
// Collect replacement
2023-07-17 13:49:15 +00:00
while let Some ( child ) = children . next ( ) {
let call = match child {
2023-12-11 09:16:01 +00:00
WalkEvent ::Enter ( SyntaxElement ::Node ( child ) ) = > match ast ::MacroCall ::cast ( child ) {
2023-07-17 13:49:15 +00:00
Some ( it ) = > {
children . skip_subtree ( ) ;
it
}
2023-12-11 09:16:01 +00:00
_ = > continue ,
2023-07-17 13:49:15 +00:00
} ,
2023-12-11 09:16:01 +00:00
WalkEvent ::Enter ( _ ) = > continue ,
WalkEvent ::Leave ( child ) = > {
if let SyntaxElement ::Token ( t ) = child {
let start = t . text_range ( ) . start ( ) ;
offset + = t . text_range ( ) . len ( ) ;
expanded_map . push ( offset , span_map . span_at ( start ) ) ;
}
2023-07-17 13:49:15 +00:00
continue ;
}
} ;
2023-12-11 09:16:01 +00:00
let def = match call
. path ( )
. and_then ( | path | ModPath ::from_src ( db , path , SpanMapRef ::ExpansionSpanMap ( span_map ) ) )
{
2023-08-07 09:03:15 +00:00
Some ( path ) = > match macro_resolver ( path . clone ( ) ) {
Some ( def ) = > def ,
None = > {
error =
Some ( ExpandError ::other ( format! ( " unresolved macro {} " , path . display ( db ) ) ) ) ;
2023-12-11 09:16:01 +00:00
offset + = call . syntax ( ) . text_range ( ) . len ( ) ;
2023-08-07 09:03:15 +00:00
continue ;
}
} ,
2022-01-26 17:31:07 +00:00
None = > {
2023-06-19 06:14:04 +00:00
error = Some ( ExpandError ::other ( " malformed macro invocation " ) ) ;
2023-12-11 09:16:01 +00:00
offset + = call . syntax ( ) . text_range ( ) . len ( ) ;
2022-01-26 17:31:07 +00:00
continue ;
}
} ;
2023-06-05 09:04:23 +00:00
let ExpandResult { value , err } = match def . kind {
2021-03-18 14:37:14 +00:00
MacroDefKind ::BuiltInEager ( .. ) = > {
2023-08-07 09:03:15 +00:00
let ExpandResult { value , err } = expand_eager_macro_input (
2020-06-11 10:08:24 +00:00
db ,
krate ,
2023-07-17 13:49:15 +00:00
curr . with_value ( call . clone ( ) ) ,
2020-06-11 10:08:24 +00:00
def ,
2023-12-11 09:16:01 +00:00
call_site ,
2020-06-11 10:08:24 +00:00
macro_resolver ,
2023-08-07 09:03:15 +00:00
) ;
2023-06-19 06:14:04 +00:00
match value {
2023-07-17 13:49:15 +00:00
Some ( call_id ) = > {
2023-12-11 09:16:01 +00:00
let ExpandResult { value : ( parse , map ) , err : err2 } =
2023-07-17 13:49:15 +00:00
db . parse_macro_expansion ( call_id . as_macro_file ( ) ) ;
2023-12-11 09:16:01 +00:00
map . iter ( ) . for_each ( | ( o , span ) | expanded_map . push ( o + offset , span ) ) ;
2023-07-17 13:49:15 +00:00
2023-12-11 09:16:01 +00:00
let syntax_node = parse . syntax_node ( ) ;
2023-06-19 06:14:04 +00:00
ExpandResult {
2023-12-11 09:16:01 +00:00
value : Some ( (
syntax_node . clone_for_update ( ) ,
offset + syntax_node . text_range ( ) . len ( ) ,
) ) ,
2023-06-19 06:14:04 +00:00
err : err . or ( err2 ) ,
}
}
None = > ExpandResult { value : None , err } ,
}
2020-03-02 06:05:15 +00:00
}
2021-03-18 14:37:14 +00:00
MacroDefKind ::Declarative ( _ )
| MacroDefKind ::BuiltIn ( .. )
2021-06-09 16:02:31 +00:00
| MacroDefKind ::BuiltInAttr ( .. )
2021-03-18 14:37:14 +00:00
| MacroDefKind ::BuiltInDerive ( .. )
2021-03-18 15:11:18 +00:00
| MacroDefKind ::ProcMacro ( .. ) = > {
2023-07-17 13:49:15 +00:00
let ExpandResult { value : ( parse , tm ) , err } =
2023-12-11 09:16:01 +00:00
lazy_expand ( db , & def , curr . with_value ( call . clone ( ) ) , krate , call_site ) ;
2020-12-02 15:52:14 +00:00
2020-03-02 06:05:15 +00:00
// replace macro inside
2023-06-05 09:04:23 +00:00
let ExpandResult { value , err : error } = eager_macro_recur (
db ,
2023-12-11 09:16:01 +00:00
& tm ,
expanded_map ,
offset ,
2023-06-05 09:04:23 +00:00
// FIXME: We discard parse errors here
2023-07-17 13:49:15 +00:00
parse . as_ref ( ) . map ( | it | it . syntax_node ( ) ) ,
2023-06-05 09:04:23 +00:00
krate ,
2023-12-11 09:16:01 +00:00
call_site ,
2023-06-05 09:04:23 +00:00
macro_resolver ,
2023-08-07 09:03:15 +00:00
) ;
2023-06-19 06:14:04 +00:00
let err = err . or ( error ) ;
2023-07-17 13:49:15 +00:00
2023-12-11 09:16:01 +00:00
ExpandResult { value , err }
2020-03-02 06:05:15 +00:00
}
} ;
2023-06-05 09:04:23 +00:00
if err . is_some ( ) {
error = err ;
}
2021-04-19 17:28:41 +00:00
// check if the whole original syntax is replaced
2023-07-17 13:49:15 +00:00
if call . syntax ( ) = = & original {
2023-12-11 09:16:01 +00:00
return ExpandResult { value , err : error } ;
2021-01-03 09:56:59 +00:00
}
2023-12-11 09:16:01 +00:00
match value {
Some ( ( insert , new_offset ) ) = > {
replacements . push ( ( call , insert ) ) ;
offset = new_offset ;
}
None = > offset + = call . syntax ( ) . text_range ( ) . len ( ) ,
2023-06-05 09:04:23 +00:00
}
2020-03-02 06:05:15 +00:00
}
2021-04-19 17:28:41 +00:00
replacements . into_iter ( ) . rev ( ) . for_each ( | ( old , new ) | ted ::replace ( old . syntax ( ) , new ) ) ;
2023-12-11 09:16:01 +00:00
ExpandResult { value : Some ( ( original , offset ) ) , err : error }
2020-03-02 06:05:15 +00:00
}