aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_expand/src/db.rs273
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
140fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { 142fn 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
147fn 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
156fn 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
164fn 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
246fn 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
252fn 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
146fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { 265fn 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
189fn 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
202fn 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
208fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>> { 308fn 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, &macro_arg.0) 399 expander.expand(db, loc.krate, &macro_arg.0)
300} 400}
301 401
302fn 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
311fn 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
318fn 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
407fn is_self_replicating(from: &SyntaxNode, to: &SyntaxNode) -> bool { 402fn 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;