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/src | |
| parent | 59fdd7c84c5fdc16573f3cca4081d6735eaa9208 (diff) | |
Fix recursive macro statement expansion
Diffstat (limited to 'crates/hir_expand/src')
| -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, |
