@@ -13,6 +13,19 @@ use crate::{
13
13
MacroFile , ProcMacroExpander ,
14
14
} ;
15
15
16
+ /// A result of some macro expansion.
17
+ #[ derive( Debug , Clone , Eq , PartialEq ) ]
18
+ pub struct MacroResult < T > {
19
+ /// The result of the expansion. Might be `None` when error recovery was impossible and no
20
+ /// usable result was produced.
21
+ pub value : Option < T > ,
22
+
23
+ /// The error that occurred during expansion or processing.
24
+ ///
25
+ /// Since we do error recovery, getting an error here does not mean that `value` will be absent.
26
+ pub error : Option < String > ,
27
+ }
28
+
16
29
#[ derive( Debug , Clone , Eq , PartialEq ) ]
17
30
pub enum TokenExpander {
18
31
MacroRules ( mbe:: MacroRules ) ,
@@ -75,16 +88,32 @@ pub trait AstDatabase: SourceDatabase {
75
88
#[ salsa:: transparent]
76
89
fn macro_arg ( & self , id : MacroCallId ) -> Option < Arc < ( tt:: Subtree , mbe:: TokenMap ) > > ;
77
90
fn macro_def ( & self , id : MacroDefId ) -> Option < Arc < ( TokenExpander , mbe:: TokenMap ) > > ;
78
- fn parse_macro ( & self , macro_file : MacroFile )
79
- -> Option < ( Parse < SyntaxNode > , Arc < mbe:: TokenMap > ) > ;
80
- fn macro_expand ( & self , macro_call : MacroCallId ) -> ( Option < Arc < tt:: Subtree > > , Option < String > ) ;
91
+ fn parse_macro (
92
+ & self ,
93
+ macro_file : MacroFile ,
94
+ ) -> MacroResult < ( Parse < SyntaxNode > , Arc < mbe:: TokenMap > ) > ;
95
+ fn macro_expand ( & self , macro_call : MacroCallId ) -> MacroResult < Arc < tt:: Subtree > > ;
81
96
82
97
#[ salsa:: interned]
83
98
fn intern_eager_expansion ( & self , eager : EagerCallLoc ) -> EagerMacroId ;
84
99
85
100
fn expand_proc_macro ( & self , call : MacroCallId ) -> Result < tt:: Subtree , mbe:: ExpandError > ;
86
101
}
87
102
103
+ impl < T > MacroResult < T > {
104
+ fn error ( message : String ) -> Self {
105
+ Self { value : None , error : Some ( message) }
106
+ }
107
+
108
+ fn map < U > ( self , f : impl FnOnce ( T ) -> U ) -> MacroResult < U > {
109
+ MacroResult { value : self . value . map ( f) , error : self . error }
110
+ }
111
+
112
+ fn drop_value < U > ( self ) -> MacroResult < U > {
113
+ MacroResult { value : None , error : self . error }
114
+ }
115
+ }
116
+
88
117
/// This expands the given macro call, but with different arguments. This is
89
118
/// used for completion, where we want to see what 'would happen' if we insert a
90
119
/// token. The `token_to_map` mapped down into the expansion, with the mapped
@@ -102,7 +131,7 @@ pub fn expand_hypothetical(
102
131
let token_id = tmap_1. token_by_range ( range) ?;
103
132
let macro_def = expander ( db, actual_macro_call) ?;
104
133
let ( node, tmap_2) =
105
- parse_macro_with_arg ( db, macro_file, Some ( std:: sync:: Arc :: new ( ( tt, tmap_1) ) ) ) ?;
134
+ parse_macro_with_arg ( db, macro_file, Some ( std:: sync:: Arc :: new ( ( tt, tmap_1) ) ) ) . value ?;
106
135
let token_id = macro_def. 0 . map_id_down ( token_id) ;
107
136
let range = tmap_2. range_by_token ( token_id) ?. by_kind ( token_to_map. kind ( ) ) ?;
108
137
let token = syntax:: algo:: find_covering_element ( & node. syntax_node ( ) , range) . into_token ( ) ?;
@@ -171,10 +200,7 @@ pub(crate) fn macro_arg(
171
200
Some ( Arc :: new ( ( tt, tmap) ) )
172
201
}
173
202
174
- pub ( crate ) fn macro_expand (
175
- db : & dyn AstDatabase ,
176
- id : MacroCallId ,
177
- ) -> ( Option < Arc < tt:: Subtree > > , Option < String > ) {
203
+ pub ( crate ) fn macro_expand ( db : & dyn AstDatabase , id : MacroCallId ) -> MacroResult < Arc < tt:: Subtree > > {
178
204
macro_expand_with_arg ( db, id, None )
179
205
}
180
206
@@ -195,38 +221,41 @@ fn macro_expand_with_arg(
195
221
db : & dyn AstDatabase ,
196
222
id : MacroCallId ,
197
223
arg : Option < Arc < ( tt:: Subtree , mbe:: TokenMap ) > > ,
198
- ) -> ( Option < Arc < tt:: Subtree > > , Option < String > ) {
224
+ ) -> MacroResult < Arc < tt:: Subtree > > {
199
225
let lazy_id = match id {
200
226
MacroCallId :: LazyMacro ( id) => id,
201
227
MacroCallId :: EagerMacro ( id) => {
202
228
if arg. is_some ( ) {
203
- return (
204
- None ,
205
- Some ( "hypothetical macro expansion not implemented for eager macro" . to_owned ( ) ) ,
229
+ return MacroResult :: error (
230
+ "hypothetical macro expansion not implemented for eager macro" . to_owned ( ) ,
206
231
) ;
207
232
} else {
208
- return ( Some ( db. lookup_intern_eager_expansion ( id) . subtree ) , None ) ;
233
+ return MacroResult {
234
+ value : Some ( db. lookup_intern_eager_expansion ( id) . subtree ) ,
235
+ error : None ,
236
+ } ;
209
237
}
210
238
}
211
239
} ;
212
240
213
241
let loc = db. lookup_intern_macro ( lazy_id) ;
214
242
let macro_arg = match arg. or_else ( || db. macro_arg ( id) ) {
215
243
Some ( it) => it,
216
- None => return ( None , Some ( "Fail to args in to tt::TokenTree" . into ( ) ) ) ,
244
+ None => return MacroResult :: error ( "Fail to args in to tt::TokenTree" . into ( ) ) ,
217
245
} ;
218
246
219
247
let macro_rules = match db. macro_def ( loc. def ) {
220
248
Some ( it) => it,
221
- None => return ( None , Some ( "Fail to find macro definition" . into ( ) ) ) ,
249
+ None => return MacroResult :: error ( "Fail to find macro definition" . into ( ) ) ,
222
250
} ;
223
251
let ExpandResult ( tt, err) = macro_rules. 0 . expand ( db, lazy_id, & macro_arg. 0 ) ;
224
252
// Set a hard limit for the expanded tt
225
253
let count = tt. count ( ) ;
226
254
if count > 262144 {
227
- return ( None , Some ( format ! ( "Total tokens count exceed limit : count = {}" , count) ) ) ;
255
+ return MacroResult :: error ( format ! ( "Total tokens count exceed limit : count = {}" , count) ) ;
228
256
}
229
- ( Some ( Arc :: new ( tt) ) , err. map ( |e| format ! ( "{:?}" , e) ) )
257
+
258
+ MacroResult { value : Some ( Arc :: new ( tt) ) , error : err. map ( |e| format ! ( "{:?}" , e) ) }
230
259
}
231
260
232
261
pub ( crate ) fn expand_proc_macro (
@@ -260,32 +289,32 @@ pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Optio
260
289
match file_id. 0 {
261
290
HirFileIdRepr :: FileId ( file_id) => Some ( db. parse ( file_id) . tree ( ) . syntax ( ) . clone ( ) ) ,
262
291
HirFileIdRepr :: MacroFile ( macro_file) => {
263
- db. parse_macro ( macro_file) . map ( |( it, _) | it. syntax_node ( ) )
292
+ db. parse_macro ( macro_file) . map ( |( it, _) | it. syntax_node ( ) ) . value
264
293
}
265
294
}
266
295
}
267
296
268
297
pub ( crate ) fn parse_macro (
269
298
db : & dyn AstDatabase ,
270
299
macro_file : MacroFile ,
271
- ) -> Option < ( Parse < SyntaxNode > , Arc < mbe:: TokenMap > ) > {
300
+ ) -> MacroResult < ( Parse < SyntaxNode > , Arc < mbe:: TokenMap > ) > {
272
301
parse_macro_with_arg ( db, macro_file, None )
273
302
}
274
303
275
304
pub fn parse_macro_with_arg (
276
305
db : & dyn AstDatabase ,
277
306
macro_file : MacroFile ,
278
307
arg : Option < Arc < ( tt:: Subtree , mbe:: TokenMap ) > > ,
279
- ) -> Option < ( Parse < SyntaxNode > , Arc < mbe:: TokenMap > ) > {
308
+ ) -> MacroResult < ( Parse < SyntaxNode > , Arc < mbe:: TokenMap > ) > {
280
309
let _p = profile:: span ( "parse_macro_query" ) ;
281
310
282
311
let macro_call_id = macro_file. macro_call_id ;
283
- let ( tt , err ) = if let Some ( arg) = arg {
312
+ let result = if let Some ( arg) = arg {
284
313
macro_expand_with_arg ( db, macro_call_id, Some ( arg) )
285
314
} else {
286
315
db. macro_expand ( macro_call_id)
287
316
} ;
288
- if let Some ( err) = & err {
317
+ if let Some ( err) = & result . error {
289
318
// Note:
290
319
// The final goal we would like to make all parse_macro success,
291
320
// such that the following log will not call anyway.
@@ -313,30 +342,44 @@ pub fn parse_macro_with_arg(
313
342
log:: warn!( "fail on macro_parse: (reason: {})" , err) ;
314
343
}
315
344
}
345
+ }
346
+ let tt = match result. value {
347
+ Some ( tt) => tt,
348
+ None => return result. drop_value ( ) ,
316
349
} ;
317
- let tt = tt?;
318
350
319
351
let fragment_kind = to_fragment_kind ( db, macro_call_id) ;
320
352
321
- let ( parse, rev_token_map) = mbe:: token_tree_to_syntax_node ( & tt, fragment_kind) . ok ( ) ?;
353
+ let ( parse, rev_token_map) = match mbe:: token_tree_to_syntax_node ( & tt, fragment_kind) {
354
+ Ok ( it) => it,
355
+ Err ( err) => {
356
+ return MacroResult :: error ( format ! ( "{:?}" , err) ) ;
357
+ }
358
+ } ;
322
359
323
- if err. is_none ( ) {
324
- Some ( ( parse, Arc :: new ( rev_token_map) ) )
325
- } else {
326
- // FIXME:
327
- // In future, we should propagate the actual error with recovery information
328
- // instead of ignore the error here.
329
-
330
- // Safe check for recurisve identity macro
331
- let node = parse. syntax_node ( ) ;
332
- let file: HirFileId = macro_file. into ( ) ;
333
- let call_node = file. call_node ( db) ?;
334
-
335
- if !diff ( & node, & call_node. value ) . is_empty ( ) {
336
- Some ( ( parse, Arc :: new ( rev_token_map) ) )
337
- } else {
338
- None
360
+ match result. error {
361
+ Some ( error) => {
362
+ // FIXME:
363
+ // In future, we should propagate the actual error with recovery information
364
+ // instead of ignore the error here.
365
+
366
+ // Safe check for recurisve identity macro
367
+ let node = parse. syntax_node ( ) ;
368
+ let file: HirFileId = macro_file. into ( ) ;
369
+ let call_node = match file. call_node ( db) {
370
+ Some ( it) => it,
371
+ None => {
372
+ return MacroResult :: error ( error) ;
373
+ }
374
+ } ;
375
+
376
+ if !diff ( & node, & call_node. value ) . is_empty ( ) {
377
+ MacroResult { value : Some ( ( parse, Arc :: new ( rev_token_map) ) ) , error : None }
378
+ } else {
379
+ return MacroResult :: error ( error) ;
380
+ }
339
381
}
382
+ None => MacroResult { value : Some ( ( parse, Arc :: new ( rev_token_map) ) ) , error : None } ,
340
383
}
341
384
}
342
385
0 commit comments