@@ -14,8 +14,8 @@ use cfg::CfgOptions;
14
14
use drop_bomb:: DropBomb ;
15
15
use either:: Either ;
16
16
use hir_expand:: {
17
- ast_id_map:: AstIdMap , diagnostics:: DiagnosticSink , hygiene:: Hygiene , AstId , HirFileId , InFile ,
18
- MacroDefId ,
17
+ ast_id_map:: AstIdMap , diagnostics:: DiagnosticSink , hygiene:: Hygiene , AstId , ExpandResult ,
18
+ HirFileId , InFile , MacroDefId ,
19
19
} ;
20
20
use rustc_hash:: FxHashMap ;
21
21
use syntax:: { ast, AstNode , AstPtr } ;
@@ -102,11 +102,11 @@ impl Expander {
102
102
db : & dyn DefDatabase ,
103
103
local_scope : Option < & ItemScope > ,
104
104
macro_call : ast:: MacroCall ,
105
- ) -> Option < ( Mark , T ) > {
105
+ ) -> ExpandResult < Option < ( Mark , T ) > > {
106
106
self . recursion_limit += 1 ;
107
107
if self . recursion_limit > EXPANSION_RECURSION_LIMIT {
108
108
mark:: hit!( your_stack_belongs_to_me) ;
109
- return None ;
109
+ return ExpandResult :: str_err ( "reached recursion limit during macro expansion" . into ( ) ) ;
110
110
}
111
111
112
112
let macro_call = InFile :: new ( self . current_file_id , & macro_call) ;
@@ -120,28 +120,55 @@ impl Expander {
120
120
self . resolve_path_as_macro ( db, & path)
121
121
} ;
122
122
123
- if let Some ( call_id) = macro_call. as_call_id ( db, self . crate_def_map . krate , resolver) {
124
- let file_id = call_id. as_file ( ) ;
125
- if let Some ( node) = db. parse_or_expand ( file_id) {
126
- if let Some ( expr) = T :: cast ( node) {
127
- log:: debug!( "macro expansion {:#?}" , expr. syntax( ) ) ;
128
-
129
- let mark = Mark {
130
- file_id : self . current_file_id ,
131
- ast_id_map : mem:: take ( & mut self . ast_id_map ) ,
132
- bomb : DropBomb :: new ( "expansion mark dropped" ) ,
133
- } ;
134
- self . cfg_expander . hygiene = Hygiene :: new ( db. upcast ( ) , file_id) ;
135
- self . current_file_id = file_id;
136
- self . ast_id_map = db. ast_id_map ( file_id) ;
137
- return Some ( ( mark, expr) ) ;
123
+ let call_id = match macro_call. as_call_id ( db, self . crate_def_map . krate , resolver) {
124
+ Some ( it) => it,
125
+ None => {
126
+ // FIXME: this can mean other things too, but `as_call_id` doesn't provide enough
127
+ // info.
128
+ return ExpandResult :: only_err ( mbe:: ExpandError :: Other (
129
+ "failed to parse or resolve macro invocation" . into ( ) ,
130
+ ) ) ;
131
+ }
132
+ } ;
133
+
134
+ let err = db. macro_expand_error ( call_id) ;
135
+
136
+ let file_id = call_id. as_file ( ) ;
137
+
138
+ let raw_node = match db. parse_or_expand ( file_id) {
139
+ Some ( it) => it,
140
+ None => {
141
+ // Only `None` if the macro expansion produced no usable AST.
142
+ if err. is_none ( ) {
143
+ log:: warn!( "no error despite `parse_or_expand` failing" ) ;
138
144
}
145
+
146
+ return ExpandResult :: only_err ( err. unwrap_or_else ( || {
147
+ mbe:: ExpandError :: Other ( "failed to parse macro invocation" . into ( ) )
148
+ } ) ) ;
139
149
}
140
- }
150
+ } ;
151
+
152
+ let node = match T :: cast ( raw_node) {
153
+ Some ( it) => it,
154
+ None => {
155
+ // This can happen without being an error, so only forward previous errors.
156
+ return ExpandResult { value : None , err } ;
157
+ }
158
+ } ;
159
+
160
+ log:: debug!( "macro expansion {:#?}" , node. syntax( ) ) ;
161
+
162
+ let mark = Mark {
163
+ file_id : self . current_file_id ,
164
+ ast_id_map : mem:: take ( & mut self . ast_id_map ) ,
165
+ bomb : DropBomb :: new ( "expansion mark dropped" ) ,
166
+ } ;
167
+ self . cfg_expander . hygiene = Hygiene :: new ( db. upcast ( ) , file_id) ;
168
+ self . current_file_id = file_id;
169
+ self . ast_id_map = db. ast_id_map ( file_id) ;
141
170
142
- // FIXME: Instead of just dropping the error from expansion
143
- // report it
144
- None
171
+ ExpandResult { value : Some ( ( mark, node) ) , err }
145
172
}
146
173
147
174
pub ( crate ) fn exit ( & mut self , db : & dyn DefDatabase , mut mark : Mark ) {
0 commit comments