@@ -13,6 +13,19 @@ use crate::{
1313 MacroFile , ProcMacroExpander ,
1414} ;
1515
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+
1629#[ derive( Debug , Clone , Eq , PartialEq ) ]
1730pub enum TokenExpander {
1831 MacroRules ( mbe:: MacroRules ) ,
@@ -75,16 +88,32 @@ pub trait AstDatabase: SourceDatabase {
7588 #[ salsa:: transparent]
7689 fn macro_arg ( & self , id : MacroCallId ) -> Option < Arc < ( tt:: Subtree , mbe:: TokenMap ) > > ;
7790 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 > > ;
8196
8297 #[ salsa:: interned]
8398 fn intern_eager_expansion ( & self , eager : EagerCallLoc ) -> EagerMacroId ;
8499
85100 fn expand_proc_macro ( & self , call : MacroCallId ) -> Result < tt:: Subtree , mbe:: ExpandError > ;
86101}
87102
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+
88117/// This expands the given macro call, but with different arguments. This is
89118/// used for completion, where we want to see what 'would happen' if we insert a
90119/// token. The `token_to_map` mapped down into the expansion, with the mapped
@@ -102,7 +131,7 @@ pub fn expand_hypothetical(
102131 let token_id = tmap_1. token_by_range ( range) ?;
103132 let macro_def = expander ( db, actual_macro_call) ?;
104133 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 ?;
106135 let token_id = macro_def. 0 . map_id_down ( token_id) ;
107136 let range = tmap_2. range_by_token ( token_id) ?. by_kind ( token_to_map. kind ( ) ) ?;
108137 let token = syntax:: algo:: find_covering_element ( & node. syntax_node ( ) , range) . into_token ( ) ?;
@@ -171,10 +200,7 @@ pub(crate) fn macro_arg(
171200 Some ( Arc :: new ( ( tt, tmap) ) )
172201}
173202
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 > > {
178204 macro_expand_with_arg ( db, id, None )
179205}
180206
@@ -195,38 +221,41 @@ fn macro_expand_with_arg(
195221 db : & dyn AstDatabase ,
196222 id : MacroCallId ,
197223 arg : Option < Arc < ( tt:: Subtree , mbe:: TokenMap ) > > ,
198- ) -> ( Option < Arc < tt:: Subtree > > , Option < String > ) {
224+ ) -> MacroResult < Arc < tt:: Subtree > > {
199225 let lazy_id = match id {
200226 MacroCallId :: LazyMacro ( id) => id,
201227 MacroCallId :: EagerMacro ( id) => {
202228 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 ( ) ,
206231 ) ;
207232 } 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+ } ;
209237 }
210238 }
211239 } ;
212240
213241 let loc = db. lookup_intern_macro ( lazy_id) ;
214242 let macro_arg = match arg. or_else ( || db. macro_arg ( id) ) {
215243 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 ( ) ) ,
217245 } ;
218246
219247 let macro_rules = match db. macro_def ( loc. def ) {
220248 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 ( ) ) ,
222250 } ;
223251 let ExpandResult ( tt, err) = macro_rules. 0 . expand ( db, lazy_id, & macro_arg. 0 ) ;
224252 // Set a hard limit for the expanded tt
225253 let count = tt. count ( ) ;
226254 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) ) ;
228256 }
229- ( Some ( Arc :: new ( tt) ) , err. map ( |e| format ! ( "{:?}" , e) ) )
257+
258+ MacroResult { value : Some ( Arc :: new ( tt) ) , error : err. map ( |e| format ! ( "{:?}" , e) ) }
230259}
231260
232261pub ( crate ) fn expand_proc_macro (
@@ -260,32 +289,32 @@ pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Optio
260289 match file_id. 0 {
261290 HirFileIdRepr :: FileId ( file_id) => Some ( db. parse ( file_id) . tree ( ) . syntax ( ) . clone ( ) ) ,
262291 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
264293 }
265294 }
266295}
267296
268297pub ( crate ) fn parse_macro (
269298 db : & dyn AstDatabase ,
270299 macro_file : MacroFile ,
271- ) -> Option < ( Parse < SyntaxNode > , Arc < mbe:: TokenMap > ) > {
300+ ) -> MacroResult < ( Parse < SyntaxNode > , Arc < mbe:: TokenMap > ) > {
272301 parse_macro_with_arg ( db, macro_file, None )
273302}
274303
275304pub fn parse_macro_with_arg (
276305 db : & dyn AstDatabase ,
277306 macro_file : MacroFile ,
278307 arg : Option < Arc < ( tt:: Subtree , mbe:: TokenMap ) > > ,
279- ) -> Option < ( Parse < SyntaxNode > , Arc < mbe:: TokenMap > ) > {
308+ ) -> MacroResult < ( Parse < SyntaxNode > , Arc < mbe:: TokenMap > ) > {
280309 let _p = profile:: span ( "parse_macro_query" ) ;
281310
282311 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 {
284313 macro_expand_with_arg ( db, macro_call_id, Some ( arg) )
285314 } else {
286315 db. macro_expand ( macro_call_id)
287316 } ;
288- if let Some ( err) = & err {
317+ if let Some ( err) = & result . error {
289318 // Note:
290319 // The final goal we would like to make all parse_macro success,
291320 // such that the following log will not call anyway.
@@ -313,30 +342,44 @@ pub fn parse_macro_with_arg(
313342 log:: warn!( "fail on macro_parse: (reason: {})" , err) ;
314343 }
315344 }
345+ }
346+ let tt = match result. value {
347+ Some ( tt) => tt,
348+ None => return result. drop_value ( ) ,
316349 } ;
317- let tt = tt?;
318350
319351 let fragment_kind = to_fragment_kind ( db, macro_call_id) ;
320352
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+ } ;
322359
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+ }
339381 }
382+ None => MacroResult { value : Some ( ( parse, Arc :: new ( rev_token_map) ) ) , error : None } ,
340383 }
341384}
342385
0 commit comments