mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 05:45:12 +00:00
Merge #8201
8201: Fix recursive macro statements expansion r=edwin0cheng a=edwin0cheng This PR attempts to properly handle macro statement expansion by implementing the following: 1. Merge macro expanded statements to parent scope statements. 2. Add a new hir `Expr::MacroStmts` for handle tail expression infer. PS : The scope of macro expanded statements are so strange that it took more time than I thought to understand and implement it :( Fixes #8171 Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
commit
c8066ebd17
7 changed files with 119 additions and 70 deletions
|
@ -5,7 +5,13 @@ use std::sync::Arc;
|
|||
use base_db::{salsa, SourceDatabase};
|
||||
use mbe::{ExpandError, ExpandResult, MacroRules};
|
||||
use parser::FragmentKind;
|
||||
use syntax::{algo::diff, ast::NameOwner, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode};
|
||||
use syntax::{
|
||||
algo::diff,
|
||||
ast::{MacroStmts, NameOwner},
|
||||
AstNode, GreenNode, Parse,
|
||||
SyntaxKind::*,
|
||||
SyntaxNode,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander,
|
||||
|
@ -340,13 +346,19 @@ fn parse_macro_with_arg(
|
|||
None => return ExpandResult { value: None, err: result.err },
|
||||
};
|
||||
|
||||
log::debug!("expanded = {}", tt.as_debug_string());
|
||||
|
||||
let fragment_kind = to_fragment_kind(db, macro_call_id);
|
||||
|
||||
log::debug!("expanded = {}", tt.as_debug_string());
|
||||
log::debug!("kind = {:?}", fragment_kind);
|
||||
|
||||
let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) {
|
||||
Ok(it) => it,
|
||||
Err(err) => {
|
||||
log::debug!(
|
||||
"failed to parse expanstion to {:?} = {}",
|
||||
fragment_kind,
|
||||
tt.as_debug_string()
|
||||
);
|
||||
return ExpandResult::only_err(err);
|
||||
}
|
||||
};
|
||||
|
@ -362,17 +374,36 @@ fn parse_macro_with_arg(
|
|||
return ExpandResult::only_err(err);
|
||||
}
|
||||
};
|
||||
|
||||
if !diff(&node, &call_node.value).is_empty() {
|
||||
ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) }
|
||||
} else {
|
||||
if is_self_replicating(&node, &call_node.value) {
|
||||
return ExpandResult::only_err(err);
|
||||
} else {
|
||||
ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) }
|
||||
}
|
||||
}
|
||||
None => ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None },
|
||||
None => {
|
||||
log::debug!("parse = {:?}", parse.syntax_node().kind());
|
||||
ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_self_replicating(from: &SyntaxNode, to: &SyntaxNode) -> bool {
|
||||
if diff(from, to).is_empty() {
|
||||
return true;
|
||||
}
|
||||
if let Some(stmts) = MacroStmts::cast(from.clone()) {
|
||||
if stmts.statements().any(|stmt| diff(stmt.syntax(), to).is_empty()) {
|
||||
return true;
|
||||
}
|
||||
if let Some(expr) = stmts.expr() {
|
||||
if diff(expr.syntax(), to).is_empty() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> {
|
||||
Arc::new(HygieneFrame::new(db, file_id))
|
||||
}
|
||||
|
@ -390,21 +421,15 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
|
|||
|
||||
let parent = match syn.parent() {
|
||||
Some(it) => it,
|
||||
None => {
|
||||
// FIXME:
|
||||
// If it is root, which means the parent HirFile
|
||||
// MacroKindFile must be non-items
|
||||
// return expr now.
|
||||
return FragmentKind::Expr;
|
||||
}
|
||||
None => return FragmentKind::Statements,
|
||||
};
|
||||
|
||||
match parent.kind() {
|
||||
MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
|
||||
MACRO_STMTS => FragmentKind::Statement,
|
||||
MACRO_STMTS => FragmentKind::Statements,
|
||||
ITEM_LIST => FragmentKind::Items,
|
||||
LET_STMT => {
|
||||
// FIXME: Handle Pattern
|
||||
// FIXME: Handle LHS Pattern
|
||||
FragmentKind::Expr
|
||||
}
|
||||
EXPR_STMT => FragmentKind::Statements,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue