diff options
author | Edwin Cheng <[email protected]> | 2021-03-25 19:52:35 +0000 |
---|---|---|
committer | Edwin Cheng <[email protected]> | 2021-03-25 20:21:15 +0000 |
commit | 8ce15b02dea7152953775904fd937cced2422bc6 (patch) | |
tree | 7ae4be1d4da3bd083fe0bec65f9ed4f5db8eb8c4 /crates/hir_expand | |
parent | 59fdd7c84c5fdc16573f3cca4081d6735eaa9208 (diff) |
Fix recursive macro statement expansion
Diffstat (limited to 'crates/hir_expand')
-rw-r--r-- | crates/hir_expand/src/db.rs | 59 |
1 files changed, 42 insertions, 17 deletions
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index fc73e435b..d672f6723 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -5,7 +5,13 @@ use std::sync::Arc; | |||
5 | use base_db::{salsa, SourceDatabase}; | 5 | use base_db::{salsa, SourceDatabase}; |
6 | use mbe::{ExpandError, ExpandResult, MacroRules}; | 6 | use mbe::{ExpandError, ExpandResult, MacroRules}; |
7 | use parser::FragmentKind; | 7 | use parser::FragmentKind; |
8 | use syntax::{algo::diff, ast::NameOwner, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; | 8 | use syntax::{ |
9 | algo::diff, | ||
10 | ast::{MacroStmts, NameOwner}, | ||
11 | AstNode, GreenNode, Parse, | ||
12 | SyntaxKind::*, | ||
13 | SyntaxNode, | ||
14 | }; | ||
9 | 15 | ||
10 | use crate::{ | 16 | use crate::{ |
11 | ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander, | 17 | ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander, |
@@ -340,13 +346,19 @@ fn parse_macro_with_arg( | |||
340 | None => return ExpandResult { value: None, err: result.err }, | 346 | None => return ExpandResult { value: None, err: result.err }, |
341 | }; | 347 | }; |
342 | 348 | ||
343 | log::debug!("expanded = {}", tt.as_debug_string()); | ||
344 | |||
345 | let fragment_kind = to_fragment_kind(db, macro_call_id); | 349 | let fragment_kind = to_fragment_kind(db, macro_call_id); |
346 | 350 | ||
351 | log::debug!("expanded = {}", tt.as_debug_string()); | ||
352 | log::debug!("kind = {:?}", fragment_kind); | ||
353 | |||
347 | let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) { | 354 | let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) { |
348 | Ok(it) => it, | 355 | Ok(it) => it, |
349 | Err(err) => { | 356 | Err(err) => { |
357 | log::debug!( | ||
358 | "failed to parse expanstion to {:?} = {}", | ||
359 | fragment_kind, | ||
360 | tt.as_debug_string() | ||
361 | ); | ||
350 | return ExpandResult::only_err(err); | 362 | return ExpandResult::only_err(err); |
351 | } | 363 | } |
352 | }; | 364 | }; |
@@ -362,15 +374,34 @@ fn parse_macro_with_arg( | |||
362 | return ExpandResult::only_err(err); | 374 | return ExpandResult::only_err(err); |
363 | } | 375 | } |
364 | }; | 376 | }; |
365 | 377 | if is_self_replicating(&node, &call_node.value) { | |
366 | if !diff(&node, &call_node.value).is_empty() { | ||
367 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) } | ||
368 | } else { | ||
369 | return ExpandResult::only_err(err); | 378 | return ExpandResult::only_err(err); |
379 | } else { | ||
380 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) } | ||
381 | } | ||
382 | } | ||
383 | None => { | ||
384 | log::debug!("parse = {:?}", parse.syntax_node().kind()); | ||
385 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None } | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | |||
390 | fn is_self_replicating(from: &SyntaxNode, to: &SyntaxNode) -> bool { | ||
391 | if diff(from, to).is_empty() { | ||
392 | return true; | ||
393 | } | ||
394 | if let Some(stmts) = MacroStmts::cast(from.clone()) { | ||
395 | if stmts.statements().any(|stmt| diff(stmt.syntax(), to).is_empty()) { | ||
396 | return true; | ||
397 | } | ||
398 | if let Some(expr) = stmts.expr() { | ||
399 | if diff(expr.syntax(), to).is_empty() { | ||
400 | return true; | ||
370 | } | 401 | } |
371 | } | 402 | } |
372 | None => ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None }, | ||
373 | } | 403 | } |
404 | false | ||
374 | } | 405 | } |
375 | 406 | ||
376 | fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> { | 407 | fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> { |
@@ -390,21 +421,15 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { | |||
390 | 421 | ||
391 | let parent = match syn.parent() { | 422 | let parent = match syn.parent() { |
392 | Some(it) => it, | 423 | Some(it) => it, |
393 | None => { | 424 | None => return FragmentKind::Statements, |
394 | // FIXME: | ||
395 | // If it is root, which means the parent HirFile | ||
396 | // MacroKindFile must be non-items | ||
397 | // return expr now. | ||
398 | return FragmentKind::Expr; | ||
399 | } | ||
400 | }; | 425 | }; |
401 | 426 | ||
402 | match parent.kind() { | 427 | match parent.kind() { |
403 | MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, | 428 | MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, |
404 | MACRO_STMTS => FragmentKind::Statement, | 429 | MACRO_STMTS => FragmentKind::Statements, |
405 | ITEM_LIST => FragmentKind::Items, | 430 | ITEM_LIST => FragmentKind::Items, |
406 | LET_STMT => { | 431 | LET_STMT => { |
407 | // FIXME: Handle Pattern | 432 | // FIXME: Handle LHS Pattern |
408 | FragmentKind::Expr | 433 | FragmentKind::Expr |
409 | } | 434 | } |
410 | EXPR_STMT => FragmentKind::Statements, | 435 | EXPR_STMT => FragmentKind::Statements, |