diff options
Diffstat (limited to 'crates/hir_expand/src')
-rw-r--r-- | crates/hir_expand/src/db.rs | 273 |
1 files changed, 134 insertions, 139 deletions
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 1389e30db..5ea41ba78 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -89,26 +89,25 @@ pub trait AstDatabase: SourceDatabase { | |||
89 | 89 | ||
90 | #[salsa::transparent] | 90 | #[salsa::transparent] |
91 | fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>; | 91 | fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>; |
92 | |||
93 | #[salsa::interned] | ||
94 | fn intern_macro(&self, macro_call: MacroCallLoc) -> LazyMacroId; | ||
95 | fn macro_arg_text(&self, id: MacroCallId) -> Option<GreenNode>; | ||
96 | #[salsa::transparent] | ||
97 | fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>; | ||
98 | fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>; | ||
99 | fn parse_macro_expansion( | 92 | fn parse_macro_expansion( |
100 | &self, | 93 | &self, |
101 | macro_file: MacroFile, | 94 | macro_file: MacroFile, |
102 | ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>>; | 95 | ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>>; |
103 | fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>>; | ||
104 | |||
105 | /// Firewall query that returns the error from the `macro_expand` query. | ||
106 | fn macro_expand_error(&self, macro_call: MacroCallId) -> Option<ExpandError>; | ||
107 | 96 | ||
108 | #[salsa::interned] | 97 | #[salsa::interned] |
98 | fn intern_macro(&self, macro_call: MacroCallLoc) -> LazyMacroId; | ||
99 | #[salsa::interned] | ||
109 | fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; | 100 | fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; |
110 | 101 | ||
102 | #[salsa::transparent] | ||
103 | fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>; | ||
104 | fn macro_arg_text(&self, id: MacroCallId) -> Option<GreenNode>; | ||
105 | fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>; | ||
106 | |||
107 | fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>>; | ||
111 | fn expand_proc_macro(&self, call: MacroCallId) -> Result<tt::Subtree, mbe::ExpandError>; | 108 | fn expand_proc_macro(&self, call: MacroCallId) -> Result<tt::Subtree, mbe::ExpandError>; |
109 | /// Firewall query that returns the error from the `macro_expand` query. | ||
110 | fn macro_expand_error(&self, macro_call: MacroCallId) -> Option<ExpandError>; | ||
112 | 111 | ||
113 | fn hygiene_frame(&self, file_id: HirFileId) -> Arc<HygieneFrame>; | 112 | fn hygiene_frame(&self, file_id: HirFileId) -> Arc<HygieneFrame>; |
114 | } | 113 | } |
@@ -129,8 +128,11 @@ pub fn expand_hypothetical( | |||
129 | token_to_map.text_range().checked_sub(hypothetical_args.syntax().text_range().start())?; | 128 | token_to_map.text_range().checked_sub(hypothetical_args.syntax().text_range().start())?; |
130 | let token_id = tmap_1.token_by_range(range)?; | 129 | let token_id = tmap_1.token_by_range(range)?; |
131 | let macro_def = expander(db, actual_macro_call)?; | 130 | let macro_def = expander(db, actual_macro_call)?; |
132 | let (node, tmap_2) = | 131 | |
133 | parse_macro_with_arg(db, macro_file, Some(std::sync::Arc::new((tt, tmap_1)))).value?; | 132 | let hypothetical_expansion = |
133 | macro_expand_with_arg(db, macro_file.macro_call_id, Some(Arc::new((tt, tmap_1)))); | ||
134 | let (node, tmap_2) = expansion_to_syntax(db, macro_file, hypothetical_expansion).value?; | ||
135 | |||
134 | let token_id = macro_def.0.map_id_down(token_id); | 136 | let token_id = macro_def.0.map_id_down(token_id); |
135 | let range = tmap_2.range_by_token(token_id)?.by_kind(token_to_map.kind())?; | 137 | let range = tmap_2.range_by_token(token_id)?.by_kind(token_to_map.kind())?; |
136 | let token = node.syntax_node().covering_element(range).into_token()?; | 138 | let token = node.syntax_node().covering_element(range).into_token()?; |
@@ -138,11 +140,128 @@ pub fn expand_hypothetical( | |||
138 | } | 140 | } |
139 | 141 | ||
140 | fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { | 142 | fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { |
141 | let map = | 143 | let map = db.parse_or_expand(file_id).map(|it| AstIdMap::from_source(&it)).unwrap_or_default(); |
142 | db.parse_or_expand(file_id).map_or_else(AstIdMap::default, |it| AstIdMap::from_source(&it)); | ||
143 | Arc::new(map) | 144 | Arc::new(map) |
144 | } | 145 | } |
145 | 146 | ||
147 | fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> { | ||
148 | match file_id.0 { | ||
149 | HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), | ||
150 | HirFileIdRepr::MacroFile(macro_file) => { | ||
151 | db.parse_macro_expansion(macro_file).value.map(|(it, _)| it.syntax_node()) | ||
152 | } | ||
153 | } | ||
154 | } | ||
155 | |||
156 | fn parse_macro_expansion( | ||
157 | db: &dyn AstDatabase, | ||
158 | macro_file: MacroFile, | ||
159 | ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> { | ||
160 | let result = db.macro_expand(macro_file.macro_call_id); | ||
161 | expansion_to_syntax(db, macro_file, result) | ||
162 | } | ||
163 | |||
164 | fn expansion_to_syntax( | ||
165 | db: &dyn AstDatabase, | ||
166 | macro_file: MacroFile, | ||
167 | result: ExpandResult<Option<Arc<tt::Subtree>>>, | ||
168 | ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> { | ||
169 | let _p = profile::span("parse_macro_expansion"); | ||
170 | |||
171 | if let Some(err) = &result.err { | ||
172 | // Note: | ||
173 | // The final goal we would like to make all parse_macro success, | ||
174 | // such that the following log will not call anyway. | ||
175 | match macro_file.macro_call_id { | ||
176 | MacroCallId::LazyMacro(id) => { | ||
177 | let loc: MacroCallLoc = db.lookup_intern_macro(id); | ||
178 | let node = loc.kind.node(db); | ||
179 | |||
180 | // collect parent information for warning log | ||
181 | let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| { | ||
182 | it.file_id.call_node(db) | ||
183 | }) | ||
184 | .map(|n| format!("{:#}", n.value)) | ||
185 | .collect::<Vec<_>>() | ||
186 | .join("\n"); | ||
187 | |||
188 | log::warn!( | ||
189 | "fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}", | ||
190 | err, | ||
191 | node.value, | ||
192 | parents | ||
193 | ); | ||
194 | } | ||
195 | _ => { | ||
196 | log::warn!("fail on macro_parse: (reason: {:?})", err); | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | let tt = match result.value { | ||
201 | Some(tt) => tt, | ||
202 | None => return ExpandResult { value: None, err: result.err }, | ||
203 | }; | ||
204 | |||
205 | let fragment_kind = to_fragment_kind(db, macro_file.macro_call_id); | ||
206 | |||
207 | log::debug!("expanded = {}", tt.as_debug_string()); | ||
208 | log::debug!("kind = {:?}", fragment_kind); | ||
209 | |||
210 | let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) { | ||
211 | Ok(it) => it, | ||
212 | Err(err) => { | ||
213 | log::debug!( | ||
214 | "failed to parse expanstion to {:?} = {}", | ||
215 | fragment_kind, | ||
216 | tt.as_debug_string() | ||
217 | ); | ||
218 | return ExpandResult::only_err(err); | ||
219 | } | ||
220 | }; | ||
221 | |||
222 | match result.err { | ||
223 | Some(err) => { | ||
224 | // Safety check for recursive identity macro. | ||
225 | let node = parse.syntax_node(); | ||
226 | let file: HirFileId = macro_file.into(); | ||
227 | let call_node = match file.call_node(db) { | ||
228 | Some(it) => it, | ||
229 | None => { | ||
230 | return ExpandResult::only_err(err); | ||
231 | } | ||
232 | }; | ||
233 | if is_self_replicating(&node, &call_node.value) { | ||
234 | return ExpandResult::only_err(err); | ||
235 | } else { | ||
236 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) } | ||
237 | } | ||
238 | } | ||
239 | None => { | ||
240 | log::debug!("parse = {:?}", parse.syntax_node().kind()); | ||
241 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None } | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | |||
246 | fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { | ||
247 | let arg = db.macro_arg_text(id)?; | ||
248 | let (tt, tmap) = mbe::syntax_node_to_token_tree(&SyntaxNode::new_root(arg)); | ||
249 | Some(Arc::new((tt, tmap))) | ||
250 | } | ||
251 | |||
252 | fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> { | ||
253 | let id = match id { | ||
254 | MacroCallId::LazyMacro(id) => id, | ||
255 | MacroCallId::EagerMacro(_id) => { | ||
256 | // FIXME: support macro_arg for eager macro | ||
257 | return None; | ||
258 | } | ||
259 | }; | ||
260 | let loc = db.lookup_intern_macro(id); | ||
261 | let arg = loc.kind.arg(db)?; | ||
262 | Some(arg.green()) | ||
263 | } | ||
264 | |||
146 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { | 265 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { |
147 | match id.kind { | 266 | match id.kind { |
148 | MacroDefKind::Declarative(ast_id) => match ast_id.to_node(db) { | 267 | MacroDefKind::Declarative(ast_id) => match ast_id.to_node(db) { |
@@ -186,25 +305,6 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, | |||
186 | } | 305 | } |
187 | } | 306 | } |
188 | 307 | ||
189 | fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> { | ||
190 | let id = match id { | ||
191 | MacroCallId::LazyMacro(id) => id, | ||
192 | MacroCallId::EagerMacro(_id) => { | ||
193 | // FIXME: support macro_arg for eager macro | ||
194 | return None; | ||
195 | } | ||
196 | }; | ||
197 | let loc = db.lookup_intern_macro(id); | ||
198 | let arg = loc.kind.arg(db)?; | ||
199 | Some(arg.green()) | ||
200 | } | ||
201 | |||
202 | fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { | ||
203 | let arg = db.macro_arg_text(id)?; | ||
204 | let (tt, tmap) = mbe::syntax_node_to_token_tree(&SyntaxNode::new_root(arg)); | ||
205 | Some(Arc::new((tt, tmap))) | ||
206 | } | ||
207 | |||
208 | fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>> { | 308 | fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>> { |
209 | macro_expand_with_arg(db, id, None) | 309 | macro_expand_with_arg(db, id, None) |
210 | } | 310 | } |
@@ -299,111 +399,6 @@ fn expand_proc_macro( | |||
299 | expander.expand(db, loc.krate, ¯o_arg.0) | 399 | expander.expand(db, loc.krate, ¯o_arg.0) |
300 | } | 400 | } |
301 | 401 | ||
302 | fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> { | ||
303 | match file_id.0 { | ||
304 | HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), | ||
305 | HirFileIdRepr::MacroFile(macro_file) => { | ||
306 | db.parse_macro_expansion(macro_file).value.map(|(it, _)| it.syntax_node()) | ||
307 | } | ||
308 | } | ||
309 | } | ||
310 | |||
311 | fn parse_macro_expansion( | ||
312 | db: &dyn AstDatabase, | ||
313 | macro_file: MacroFile, | ||
314 | ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> { | ||
315 | parse_macro_with_arg(db, macro_file, None) | ||
316 | } | ||
317 | |||
318 | fn parse_macro_with_arg( | ||
319 | db: &dyn AstDatabase, | ||
320 | macro_file: MacroFile, | ||
321 | arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>, | ||
322 | ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> { | ||
323 | let macro_call_id = macro_file.macro_call_id; | ||
324 | let result = if let Some(arg) = arg { | ||
325 | macro_expand_with_arg(db, macro_call_id, Some(arg)) | ||
326 | } else { | ||
327 | db.macro_expand(macro_call_id) | ||
328 | }; | ||
329 | |||
330 | let _p = profile::span("parse_macro_expansion"); | ||
331 | |||
332 | if let Some(err) = &result.err { | ||
333 | // Note: | ||
334 | // The final goal we would like to make all parse_macro success, | ||
335 | // such that the following log will not call anyway. | ||
336 | match macro_call_id { | ||
337 | MacroCallId::LazyMacro(id) => { | ||
338 | let loc: MacroCallLoc = db.lookup_intern_macro(id); | ||
339 | let node = loc.kind.node(db); | ||
340 | |||
341 | // collect parent information for warning log | ||
342 | let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| { | ||
343 | it.file_id.call_node(db) | ||
344 | }) | ||
345 | .map(|n| format!("{:#}", n.value)) | ||
346 | .collect::<Vec<_>>() | ||
347 | .join("\n"); | ||
348 | |||
349 | log::warn!( | ||
350 | "fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}", | ||
351 | err, | ||
352 | node.value, | ||
353 | parents | ||
354 | ); | ||
355 | } | ||
356 | _ => { | ||
357 | log::warn!("fail on macro_parse: (reason: {:?})", err); | ||
358 | } | ||
359 | } | ||
360 | } | ||
361 | let tt = match result.value { | ||
362 | Some(tt) => tt, | ||
363 | None => return ExpandResult { value: None, err: result.err }, | ||
364 | }; | ||
365 | |||
366 | let fragment_kind = to_fragment_kind(db, macro_call_id); | ||
367 | |||
368 | log::debug!("expanded = {}", tt.as_debug_string()); | ||
369 | log::debug!("kind = {:?}", fragment_kind); | ||
370 | |||
371 | let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) { | ||
372 | Ok(it) => it, | ||
373 | Err(err) => { | ||
374 | log::debug!( | ||
375 | "failed to parse expanstion to {:?} = {}", | ||
376 | fragment_kind, | ||
377 | tt.as_debug_string() | ||
378 | ); | ||
379 | return ExpandResult::only_err(err); | ||
380 | } | ||
381 | }; | ||
382 | |||
383 | match result.err { | ||
384 | Some(err) => { | ||
385 | // Safety check for recursive identity macro. | ||
386 | let node = parse.syntax_node(); | ||
387 | let file: HirFileId = macro_file.into(); | ||
388 | let call_node = match file.call_node(db) { | ||
389 | Some(it) => it, | ||
390 | None => { | ||
391 | return ExpandResult::only_err(err); | ||
392 | } | ||
393 | }; | ||
394 | if is_self_replicating(&node, &call_node.value) { | ||
395 | return ExpandResult::only_err(err); | ||
396 | } else { | ||
397 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) } | ||
398 | } | ||
399 | } | ||
400 | None => { | ||
401 | log::debug!("parse = {:?}", parse.syntax_node().kind()); | ||
402 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None } | ||
403 | } | ||
404 | } | ||
405 | } | ||
406 | |||
407 | fn is_self_replicating(from: &SyntaxNode, to: &SyntaxNode) -> bool { | 402 | fn is_self_replicating(from: &SyntaxNode, to: &SyntaxNode) -> bool { |
408 | if diff(from, to).is_empty() { | 403 | if diff(from, to).is_empty() { |
409 | return true; | 404 | return true; |