1818//!
1919//!
2020//! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
21- use base_db:: { span:: SyntaxContextId , CrateId , FileId } ;
22- use rustc_hash:: FxHashMap ;
23- use syntax:: { ted, Parse , SyntaxNode , TextRange , TextSize , WalkEvent } ;
21+ use base_db:: { span:: SyntaxContextId , CrateId } ;
22+ use syntax:: { ted, Parse , SyntaxElement , SyntaxNode , TextSize , WalkEvent } ;
2423use triomphe:: Arc ;
2524
2625use crate :: {
2726 ast:: { self , AstNode } ,
2827 db:: ExpandDatabase ,
2928 mod_path:: ModPath ,
30- span:: { RealSpanMap , SpanMapRef } ,
29+ span:: SpanMapRef ,
3130 EagerCallInfo , ExpandError , ExpandResult , ExpandTo , ExpansionSpanMap , InFile , MacroCallId ,
3231 MacroCallKind , MacroCallLoc , MacroDefId , MacroDefKind ,
3332} ;
@@ -59,25 +58,30 @@ pub fn expand_eager_macro_input(
5958 let ExpandResult { value : ( arg_exp, arg_exp_map) , err : parse_err } =
6059 db. parse_macro_expansion ( arg_id. as_macro_file ( ) ) ;
6160
61+ let mut arg_map = ExpansionSpanMap :: empty ( ) ;
62+
6263 let ExpandResult { value : expanded_eager_input, err } = {
6364 eager_macro_recur (
6465 db,
6566 & arg_exp_map,
67+ & mut arg_map,
68+ TextSize :: new ( 0 ) ,
6669 InFile :: new ( arg_id. as_file ( ) , arg_exp. syntax_node ( ) ) ,
6770 krate,
6871 call_site,
6972 resolver,
7073 )
7174 } ;
7275 let err = parse_err. or ( err) ;
76+ if cfg ! ( debug) {
77+ arg_map. finish ( ) ;
78+ }
7379
7480 let Some ( ( expanded_eager_input, _mapping) ) = expanded_eager_input else {
7581 return ExpandResult { value : None , err } ;
7682 } ;
7783
78- // FIXME: Spans!
79- let mut subtree =
80- mbe:: syntax_node_to_token_tree ( & expanded_eager_input, RealSpanMap :: absolute ( FileId :: BOGUS ) ) ;
84+ let mut subtree = mbe:: syntax_node_to_token_tree ( & expanded_eager_input, arg_map) ;
8185
8286 subtree. delimiter = crate :: tt:: Delimiter :: DUMMY_INVISIBLE ;
8387
@@ -103,13 +107,7 @@ fn lazy_expand(
103107
104108 let expand_to = ExpandTo :: from_call_site ( & macro_call. value ) ;
105109 let ast_id = macro_call. with_value ( ast_id) ;
106- let id = def. as_lazy_macro (
107- db,
108- krate,
109- MacroCallKind :: FnLike { ast_id, expand_to } ,
110- // FIXME: This is wrong
111- call_site,
112- ) ;
110+ let id = def. as_lazy_macro ( db, krate, MacroCallKind :: FnLike { ast_id, expand_to } , call_site) ;
113111 let macro_file = id. as_macro_file ( ) ;
114112
115113 db. parse_macro_expansion ( macro_file)
@@ -119,46 +117,42 @@ fn lazy_expand(
119117fn eager_macro_recur (
120118 db : & dyn ExpandDatabase ,
121119 span_map : & ExpansionSpanMap ,
120+ expanded_map : & mut ExpansionSpanMap ,
121+ mut offset : TextSize ,
122122 curr : InFile < SyntaxNode > ,
123123 krate : CrateId ,
124124 call_site : SyntaxContextId ,
125125 macro_resolver : & dyn Fn ( ModPath ) -> Option < MacroDefId > ,
126- ) -> ExpandResult < Option < ( SyntaxNode , FxHashMap < TextRange , TextRange > ) > > {
126+ ) -> ExpandResult < Option < ( SyntaxNode , TextSize ) > > {
127127 let original = curr. value . clone_for_update ( ) ;
128- let mut mapping = FxHashMap :: default ( ) ;
129128
130129 let mut replacements = Vec :: new ( ) ;
131130
132131 // FIXME: We only report a single error inside of eager expansions
133132 let mut error = None ;
134- let mut offset = 0i32 ;
135- let apply_offset = |it : TextSize , offset : i32 | {
136- TextSize :: from ( u32:: try_from ( offset + u32:: from ( it) as i32 ) . unwrap_or_default ( ) )
137- } ;
138133 let mut children = original. preorder_with_tokens ( ) ;
139134
140135 // Collect replacement
141136 while let Some ( child) = children. next ( ) {
142- let WalkEvent :: Enter ( child) = child else { continue } ;
143137 let call = match child {
144- syntax :: NodeOrToken :: Node ( node ) => match ast:: MacroCall :: cast ( node ) {
138+ WalkEvent :: Enter ( SyntaxElement :: Node ( child ) ) => match ast:: MacroCall :: cast ( child ) {
145139 Some ( it) => {
146140 children. skip_subtree ( ) ;
147141 it
148142 }
149- None => continue ,
143+ _ => continue ,
150144 } ,
151- syntax:: NodeOrToken :: Token ( t) => {
152- mapping. insert (
153- TextRange :: new (
154- apply_offset ( t. text_range ( ) . start ( ) , offset) ,
155- apply_offset ( t. text_range ( ) . end ( ) , offset) ,
156- ) ,
157- t. text_range ( ) ,
158- ) ;
145+ WalkEvent :: Enter ( _) => continue ,
146+ WalkEvent :: Leave ( child) => {
147+ if let SyntaxElement :: Token ( t) = child {
148+ let start = t. text_range ( ) . start ( ) ;
149+ offset += t. text_range ( ) . len ( ) ;
150+ expanded_map. push ( offset, span_map. span_at ( start) ) ;
151+ }
159152 continue ;
160153 }
161154 } ;
155+
162156 let def = match call
163157 . path ( )
164158 . and_then ( |path| ModPath :: from_src ( db, path, SpanMapRef :: ExpansionSpanMap ( span_map) ) )
@@ -168,11 +162,13 @@ fn eager_macro_recur(
168162 None => {
169163 error =
170164 Some ( ExpandError :: other ( format ! ( "unresolved macro {}" , path. display( db) ) ) ) ;
165+ offset += call. syntax ( ) . text_range ( ) . len ( ) ;
171166 continue ;
172167 }
173168 } ,
174169 None => {
175170 error = Some ( ExpandError :: other ( "malformed macro invocation" ) ) ;
171+ offset += call. syntax ( ) . text_range ( ) . len ( ) ;
176172 continue ;
177173 }
178174 } ;
@@ -183,31 +179,22 @@ fn eager_macro_recur(
183179 krate,
184180 curr. with_value ( call. clone ( ) ) ,
185181 def,
186- // FIXME: This call site is not quite right I think? We probably need to mark it?
187182 call_site,
188183 macro_resolver,
189184 ) ;
190185 match value {
191186 Some ( call_id) => {
192- let ExpandResult { value, err : err2 } =
187+ let ExpandResult { value : ( parse , map ) , err : err2 } =
193188 db. parse_macro_expansion ( call_id. as_macro_file ( ) ) ;
194189
195- // if let Some(tt) = call.token_tree() {
196- // let call_tt_start = tt.syntax().text_range().start();
197- // let call_start =
198- // apply_offset(call.syntax().text_range().start(), offset);
199- // if let Some((_, arg_map, _)) = db.macro_arg(call_id).value.as_deref() {
200- // mapping.extend(arg_map.entries().filter_map(|(tid, range)| {
201- // value
202- // .1
203- // .first_range_by_token(tid, syntax::SyntaxKind::TOMBSTONE)
204- // .map(|r| (r + call_start, range + call_tt_start))
205- // }));
206- // }
207- // }
190+ map. iter ( ) . for_each ( |( o, span) | expanded_map. push ( o + offset, span) ) ;
208191
192+ let syntax_node = parse. syntax_node ( ) ;
209193 ExpandResult {
210- value : Some ( value. 0 . syntax_node ( ) . clone_for_update ( ) ) ,
194+ value : Some ( (
195+ syntax_node. clone_for_update ( ) ,
196+ offset + syntax_node. text_range ( ) . len ( ) ,
197+ ) ) ,
211198 err : err. or ( err2) ,
212199 }
213200 }
@@ -226,6 +213,8 @@ fn eager_macro_recur(
226213 let ExpandResult { value, err : error } = eager_macro_recur (
227214 db,
228215 & tm,
216+ expanded_map,
217+ offset,
229218 // FIXME: We discard parse errors here
230219 parse. as_ref ( ) . map ( |it| it. syntax_node ( ) ) ,
231220 krate,
@@ -234,48 +223,26 @@ fn eager_macro_recur(
234223 ) ;
235224 let err = err. or ( error) ;
236225
237- // if let Some(tt) = call.token_tree() {
238- // let decl_mac = if let MacroDefKind::Declarative(ast_id) = def.kind {
239- // Some(db.decl_macro_expander(def.krate, ast_id))
240- // } else {
241- // None
242- // };
243- // let call_tt_start = tt.syntax().text_range().start();
244- // let call_start = apply_offset(call.syntax().text_range().start(), offset);
245- // if let Some((_tt, arg_map, _)) = parse
246- // .file_id
247- // .macro_file()
248- // .and_then(|id| db.macro_arg(id.macro_call_id).value)
249- // .as_deref()
250- // {
251- // mapping.extend(arg_map.entries().filter_map(|(tid, range)| {
252- // tm.first_range_by_token(
253- // decl_mac.as_ref().map(|it| it.map_id_down(tid)).unwrap_or(tid),
254- // syntax::SyntaxKind::TOMBSTONE,
255- // )
256- // .map(|r| (r + call_start, range + call_tt_start))
257- // }));
258- // }
259- // }
260- // FIXME: Do we need to re-use _m here?
261- ExpandResult { value : value. map ( |( n, _m) | n) , err }
226+ ExpandResult { value, err }
262227 }
263228 } ;
264229 if err. is_some ( ) {
265230 error = err;
266231 }
267232 // check if the whole original syntax is replaced
268233 if call. syntax ( ) == & original {
269- return ExpandResult { value : value . zip ( Some ( mapping ) ) , err : error } ;
234+ return ExpandResult { value, err : error } ;
270235 }
271236
272- if let Some ( insert) = value {
273- offset += u32:: from ( insert. text_range ( ) . len ( ) ) as i32
274- - u32:: from ( call. syntax ( ) . text_range ( ) . len ( ) ) as i32 ;
275- replacements. push ( ( call, insert) ) ;
237+ match value {
238+ Some ( ( insert, new_offset) ) => {
239+ replacements. push ( ( call, insert) ) ;
240+ offset = new_offset;
241+ }
242+ None => offset += call. syntax ( ) . text_range ( ) . len ( ) ,
276243 }
277244 }
278245
279246 replacements. into_iter ( ) . rev ( ) . for_each ( |( old, new) | ted:: replace ( old. syntax ( ) , new) ) ;
280- ExpandResult { value : Some ( ( original, mapping ) ) , err : error }
247+ ExpandResult { value : Some ( ( original, offset ) ) , err : error }
281248}
0 commit comments