18
18
//!
19
19
//!
20
20
//! 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 } ;
24
23
use triomphe:: Arc ;
25
24
26
25
use crate :: {
27
26
ast:: { self , AstNode } ,
28
27
db:: ExpandDatabase ,
29
28
mod_path:: ModPath ,
30
- span:: { RealSpanMap , SpanMapRef } ,
29
+ span:: SpanMapRef ,
31
30
EagerCallInfo , ExpandError , ExpandResult , ExpandTo , ExpansionSpanMap , InFile , MacroCallId ,
32
31
MacroCallKind , MacroCallLoc , MacroDefId , MacroDefKind ,
33
32
} ;
@@ -59,25 +58,30 @@ pub fn expand_eager_macro_input(
59
58
let ExpandResult { value : ( arg_exp, arg_exp_map) , err : parse_err } =
60
59
db. parse_macro_expansion ( arg_id. as_macro_file ( ) ) ;
61
60
61
+ let mut arg_map = ExpansionSpanMap :: empty ( ) ;
62
+
62
63
let ExpandResult { value : expanded_eager_input, err } = {
63
64
eager_macro_recur (
64
65
db,
65
66
& arg_exp_map,
67
+ & mut arg_map,
68
+ TextSize :: new ( 0 ) ,
66
69
InFile :: new ( arg_id. as_file ( ) , arg_exp. syntax_node ( ) ) ,
67
70
krate,
68
71
call_site,
69
72
resolver,
70
73
)
71
74
} ;
72
75
let err = parse_err. or ( err) ;
76
+ if cfg ! ( debug) {
77
+ arg_map. finish ( ) ;
78
+ }
73
79
74
80
let Some ( ( expanded_eager_input, _mapping) ) = expanded_eager_input else {
75
81
return ExpandResult { value : None , err } ;
76
82
} ;
77
83
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) ;
81
85
82
86
subtree. delimiter = crate :: tt:: Delimiter :: DUMMY_INVISIBLE ;
83
87
@@ -103,13 +107,7 @@ fn lazy_expand(
103
107
104
108
let expand_to = ExpandTo :: from_call_site ( & macro_call. value ) ;
105
109
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) ;
113
111
let macro_file = id. as_macro_file ( ) ;
114
112
115
113
db. parse_macro_expansion ( macro_file)
@@ -119,46 +117,42 @@ fn lazy_expand(
119
117
fn eager_macro_recur (
120
118
db : & dyn ExpandDatabase ,
121
119
span_map : & ExpansionSpanMap ,
120
+ expanded_map : & mut ExpansionSpanMap ,
121
+ mut offset : TextSize ,
122
122
curr : InFile < SyntaxNode > ,
123
123
krate : CrateId ,
124
124
call_site : SyntaxContextId ,
125
125
macro_resolver : & dyn Fn ( ModPath ) -> Option < MacroDefId > ,
126
- ) -> ExpandResult < Option < ( SyntaxNode , FxHashMap < TextRange , TextRange > ) > > {
126
+ ) -> ExpandResult < Option < ( SyntaxNode , TextSize ) > > {
127
127
let original = curr. value . clone_for_update ( ) ;
128
- let mut mapping = FxHashMap :: default ( ) ;
129
128
130
129
let mut replacements = Vec :: new ( ) ;
131
130
132
131
// FIXME: We only report a single error inside of eager expansions
133
132
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
- } ;
138
133
let mut children = original. preorder_with_tokens ( ) ;
139
134
140
135
// Collect replacement
141
136
while let Some ( child) = children. next ( ) {
142
- let WalkEvent :: Enter ( child) = child else { continue } ;
143
137
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 ) {
145
139
Some ( it) => {
146
140
children. skip_subtree ( ) ;
147
141
it
148
142
}
149
- None => continue ,
143
+ _ => continue ,
150
144
} ,
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
+ }
159
152
continue ;
160
153
}
161
154
} ;
155
+
162
156
let def = match call
163
157
. path ( )
164
158
. and_then ( |path| ModPath :: from_src ( db, path, SpanMapRef :: ExpansionSpanMap ( span_map) ) )
@@ -168,11 +162,13 @@ fn eager_macro_recur(
168
162
None => {
169
163
error =
170
164
Some ( ExpandError :: other ( format ! ( "unresolved macro {}" , path. display( db) ) ) ) ;
165
+ offset += call. syntax ( ) . text_range ( ) . len ( ) ;
171
166
continue ;
172
167
}
173
168
} ,
174
169
None => {
175
170
error = Some ( ExpandError :: other ( "malformed macro invocation" ) ) ;
171
+ offset += call. syntax ( ) . text_range ( ) . len ( ) ;
176
172
continue ;
177
173
}
178
174
} ;
@@ -183,31 +179,22 @@ fn eager_macro_recur(
183
179
krate,
184
180
curr. with_value ( call. clone ( ) ) ,
185
181
def,
186
- // FIXME: This call site is not quite right I think? We probably need to mark it?
187
182
call_site,
188
183
macro_resolver,
189
184
) ;
190
185
match value {
191
186
Some ( call_id) => {
192
- let ExpandResult { value, err : err2 } =
187
+ let ExpandResult { value : ( parse , map ) , err : err2 } =
193
188
db. parse_macro_expansion ( call_id. as_macro_file ( ) ) ;
194
189
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) ) ;
208
191
192
+ let syntax_node = parse. syntax_node ( ) ;
209
193
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
+ ) ) ,
211
198
err : err. or ( err2) ,
212
199
}
213
200
}
@@ -226,6 +213,8 @@ fn eager_macro_recur(
226
213
let ExpandResult { value, err : error } = eager_macro_recur (
227
214
db,
228
215
& tm,
216
+ expanded_map,
217
+ offset,
229
218
// FIXME: We discard parse errors here
230
219
parse. as_ref ( ) . map ( |it| it. syntax_node ( ) ) ,
231
220
krate,
@@ -234,48 +223,26 @@ fn eager_macro_recur(
234
223
) ;
235
224
let err = err. or ( error) ;
236
225
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 }
262
227
}
263
228
} ;
264
229
if err. is_some ( ) {
265
230
error = err;
266
231
}
267
232
// check if the whole original syntax is replaced
268
233
if call. syntax ( ) == & original {
269
- return ExpandResult { value : value . zip ( Some ( mapping ) ) , err : error } ;
234
+ return ExpandResult { value, err : error } ;
270
235
}
271
236
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 ( ) ,
276
243
}
277
244
}
278
245
279
246
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 }
281
248
}
0 commit comments