aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdwin Cheng <[email protected]>2021-03-25 19:52:35 +0000
committerEdwin Cheng <[email protected]>2021-03-25 20:21:15 +0000
commit8ce15b02dea7152953775904fd937cced2422bc6 (patch)
tree7ae4be1d4da3bd083fe0bec65f9ed4f5db8eb8c4
parent59fdd7c84c5fdc16573f3cca4081d6735eaa9208 (diff)
Fix recursive macro statement expansion
-rw-r--r--crates/hir_def/src/body/lower.rs68
-rw-r--r--crates/hir_def/src/expr.rs4
-rw-r--r--crates/hir_def/src/item_tree.rs9
-rw-r--r--crates/hir_def/src/item_tree/lower.rs8
-rw-r--r--crates/hir_expand/src/db.rs59
-rw-r--r--crates/hir_ty/src/infer/expr.rs1
-rw-r--r--crates/hir_ty/src/tests/macros.rs40
7 files changed, 119 insertions, 70 deletions
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 19f5065d1..229e81dd4 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -74,6 +74,7 @@ pub(super) fn lower(
74 _c: Count::new(), 74 _c: Count::new(),
75 }, 75 },
76 expander, 76 expander,
77 statements_in_scope: Vec::new(),
77 } 78 }
78 .collect(params, body) 79 .collect(params, body)
79} 80}
@@ -83,6 +84,7 @@ struct ExprCollector<'a> {
83 expander: Expander, 84 expander: Expander,
84 body: Body, 85 body: Body,
85 source_map: BodySourceMap, 86 source_map: BodySourceMap,
87 statements_in_scope: Vec<Statement>,
86} 88}
87 89
88impl ExprCollector<'_> { 90impl ExprCollector<'_> {
@@ -533,15 +535,13 @@ impl ExprCollector<'_> {
533 ids[0] 535 ids[0]
534 } 536 }
535 ast::Expr::MacroStmts(e) => { 537 ast::Expr::MacroStmts(e) => {
536 // FIXME: these statements should be held by some hir containter 538 e.statements().for_each(|s| self.collect_stmt(s));
537 for stmt in e.statements() { 539 let tail = e
538 self.collect_stmt(stmt); 540 .expr()
539 } 541 .map(|e| self.collect_expr(e))
540 if let Some(expr) = e.expr() { 542 .unwrap_or_else(|| self.alloc_expr(Expr::Missing, syntax_ptr.clone()));
541 self.collect_expr(expr) 543
542 } else { 544 self.alloc_expr(Expr::MacroStmts { tail }, syntax_ptr)
543 self.alloc_expr(Expr::Missing, syntax_ptr)
544 }
545 } 545 }
546 }) 546 })
547 } 547 }
@@ -618,58 +618,54 @@ impl ExprCollector<'_> {
618 } 618 }
619 } 619 }
620 620
621 fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> { 621 fn collect_stmt(&mut self, s: ast::Stmt) {
622 let stmt = match s { 622 match s {
623 ast::Stmt::LetStmt(stmt) => { 623 ast::Stmt::LetStmt(stmt) => {
624 self.check_cfg(&stmt)?; 624 if self.check_cfg(&stmt).is_none() {
625 625 return;
626 }
626 let pat = self.collect_pat_opt(stmt.pat()); 627 let pat = self.collect_pat_opt(stmt.pat());
627 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 628 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
628 let initializer = stmt.initializer().map(|e| self.collect_expr(e)); 629 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
629 vec![Statement::Let { pat, type_ref, initializer }] 630 self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer });
630 } 631 }
631 ast::Stmt::ExprStmt(stmt) => { 632 ast::Stmt::ExprStmt(stmt) => {
632 self.check_cfg(&stmt)?; 633 if self.check_cfg(&stmt).is_none() {
634 return;
635 }
633 636
634 // Note that macro could be expended to multiple statements 637 // Note that macro could be expended to multiple statements
635 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { 638 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
636 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); 639 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
637 let mut stmts = vec![];
638 640
639 self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { 641 self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| {
640 match expansion { 642 match expansion {
641 Some(expansion) => { 643 Some(expansion) => {
642 let statements: ast::MacroStmts = expansion; 644 let statements: ast::MacroStmts = expansion;
643 645
644 statements.statements().for_each(|stmt| { 646 statements.statements().for_each(|stmt| this.collect_stmt(stmt));
645 if let Some(mut r) = this.collect_stmt(stmt) {
646 stmts.append(&mut r);
647 }
648 });
649 if let Some(expr) = statements.expr() { 647 if let Some(expr) = statements.expr() {
650 stmts.push(Statement::Expr(this.collect_expr(expr))); 648 let expr = this.collect_expr(expr);
649 this.statements_in_scope.push(Statement::Expr(expr));
651 } 650 }
652 } 651 }
653 None => { 652 None => {
654 stmts.push(Statement::Expr( 653 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
655 this.alloc_expr(Expr::Missing, syntax_ptr.clone()), 654 this.statements_in_scope.push(Statement::Expr(expr));
656 ));
657 } 655 }
658 } 656 }
659 }); 657 });
660 stmts
661 } else { 658 } else {
662 vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))] 659 let expr = self.collect_expr_opt(stmt.expr());
660 self.statements_in_scope.push(Statement::Expr(expr));
663 } 661 }
664 } 662 }
665 ast::Stmt::Item(item) => { 663 ast::Stmt::Item(item) => {
666 self.check_cfg(&item)?; 664 if self.check_cfg(&item).is_none() {
667 665 return;
668 return None; 666 }
669 } 667 }
670 }; 668 }
671
672 Some(stmt)
673 } 669 }
674 670
675 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { 671 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
@@ -685,10 +681,12 @@ impl ExprCollector<'_> {
685 let module = if has_def_map { def_map.root() } else { self.expander.module }; 681 let module = if has_def_map { def_map.root() } else { self.expander.module };
686 let prev_def_map = mem::replace(&mut self.expander.def_map, def_map); 682 let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
687 let prev_local_module = mem::replace(&mut self.expander.module, module); 683 let prev_local_module = mem::replace(&mut self.expander.module, module);
684 let prev_statements = std::mem::take(&mut self.statements_in_scope);
685
686 block.statements().for_each(|s| self.collect_stmt(s));
688 687
689 let statements =
690 block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect();
691 let tail = block.tail_expr().map(|e| self.collect_expr(e)); 688 let tail = block.tail_expr().map(|e| self.collect_expr(e));
689 let statements = std::mem::replace(&mut self.statements_in_scope, prev_statements);
692 let syntax_node_ptr = AstPtr::new(&block.into()); 690 let syntax_node_ptr = AstPtr::new(&block.into());
693 let expr_id = self.alloc_expr( 691 let expr_id = self.alloc_expr(
694 Expr::Block { id: block_id, statements, tail, label: None }, 692 Expr::Block { id: block_id, statements, tail, label: None },
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs
index 24be93773..6c7376fad 100644
--- a/crates/hir_def/src/expr.rs
+++ b/crates/hir_def/src/expr.rs
@@ -171,6 +171,9 @@ pub enum Expr {
171 Unsafe { 171 Unsafe {
172 body: ExprId, 172 body: ExprId,
173 }, 173 },
174 MacroStmts {
175 tail: ExprId,
176 },
174 Array(Array), 177 Array(Array),
175 Literal(Literal), 178 Literal(Literal),
176} 179}
@@ -357,6 +360,7 @@ impl Expr {
357 f(*repeat) 360 f(*repeat)
358 } 361 }
359 }, 362 },
363 Expr::MacroStmts { tail } => f(*tail),
360 Expr::Literal(_) => {} 364 Expr::Literal(_) => {}
361 } 365 }
362 } 366 }
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index ae2475b4e..ca0048b16 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -110,15 +110,6 @@ impl ItemTree {
110 // still need to collect inner items. 110 // still need to collect inner items.
111 ctx.lower_inner_items(e.syntax()) 111 ctx.lower_inner_items(e.syntax())
112 }, 112 },
113 ast::ExprStmt(stmt) => {
114 // Macros can expand to stmt. We return an empty item tree in this case, but
115 // still need to collect inner items.
116 ctx.lower_inner_items(stmt.syntax())
117 },
118 ast::Item(item) => {
119 // Macros can expand to stmt and other item, and we add it as top level item
120 ctx.lower_single_item(item)
121 },
122 _ => { 113 _ => {
123 panic!("cannot create item tree from {:?} {}", syntax, syntax); 114 panic!("cannot create item tree from {:?} {}", syntax, syntax);
124 }, 115 },
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index d3fe1ce1e..3f558edd8 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -87,14 +87,6 @@ impl Ctx {
87 self.tree 87 self.tree
88 } 88 }
89 89
90 pub(super) fn lower_single_item(mut self, item: ast::Item) -> ItemTree {
91 self.tree.top_level = self
92 .lower_mod_item(&item, false)
93 .map(|item| item.0)
94 .unwrap_or_else(|| Default::default());
95 self.tree
96 }
97
98 pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree { 90 pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree {
99 self.collect_inner_items(within); 91 self.collect_inner_items(within);
100 self.tree 92 self.tree
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;
5use base_db::{salsa, SourceDatabase}; 5use base_db::{salsa, SourceDatabase};
6use mbe::{ExpandError, ExpandResult, MacroRules}; 6use mbe::{ExpandError, ExpandResult, MacroRules};
7use parser::FragmentKind; 7use parser::FragmentKind;
8use syntax::{algo::diff, ast::NameOwner, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; 8use syntax::{
9 algo::diff,
10 ast::{MacroStmts, NameOwner},
11 AstNode, GreenNode, Parse,
12 SyntaxKind::*,
13 SyntaxNode,
14};
9 15
10use crate::{ 16use 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
390fn 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
376fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> { 407fn 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,
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 3f3187ea2..e6ede05ca 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -767,6 +767,7 @@ impl<'a> InferenceContext<'a> {
767 None => self.table.new_float_var(), 767 None => self.table.new_float_var(),
768 }, 768 },
769 }, 769 },
770 Expr::MacroStmts { tail } => self.infer_expr(*tail, expected),
770 }; 771 };
771 // use a new type variable if we got unknown here 772 // use a new type variable if we got unknown here
772 let ty = self.insert_type_vars_shallow(ty); 773 let ty = self.insert_type_vars_shallow(ty);
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index 7eda51866..01935ec99 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -226,12 +226,49 @@ fn expr_macro_expanded_in_stmts() {
226 "#, 226 "#,
227 expect![[r#" 227 expect![[r#"
228 !0..8 'leta=();': () 228 !0..8 'leta=();': ()
229 !0..8 'leta=();': ()
230 !3..4 'a': ()
231 !5..7 '()': ()
229 57..84 '{ ...); } }': () 232 57..84 '{ ...); } }': ()
230 "#]], 233 "#]],
231 ); 234 );
232} 235}
233 236
234#[test] 237#[test]
238fn recurisve_macro_expanded_in_stmts() {
239 check_infer(
240 r#"
241 macro_rules! ng {
242 ([$($tts:tt)*]) => {
243 $($tts)*;
244 };
245 ([$($tts:tt)*] $head:tt $($rest:tt)*) => {
246 ng! {
247 [$($tts)* $head] $($rest)*
248 }
249 };
250 }
251 fn foo() {
252 ng!([] let a = 3);
253 let b = a;
254 }
255 "#,
256 expect![[r#"
257 !0..7 'leta=3;': {unknown}
258 !0..7 'leta=3;': {unknown}
259 !0..13 'ng!{[leta=3]}': {unknown}
260 !0..13 'ng!{[leta=]3}': {unknown}
261 !0..13 'ng!{[leta]=3}': {unknown}
262 !3..4 'a': i32
263 !5..6 '3': i32
264 196..237 '{ ...= a; }': ()
265 229..230 'b': i32
266 233..234 'a': i32
267 "#]],
268 );
269}
270
271#[test]
235fn recursive_inner_item_macro_rules() { 272fn recursive_inner_item_macro_rules() {
236 check_infer( 273 check_infer(
237 r#" 274 r#"
@@ -246,7 +283,8 @@ fn recursive_inner_item_macro_rules() {
246 "#, 283 "#,
247 expect![[r#" 284 expect![[r#"
248 !0..1 '1': i32 285 !0..1 '1': i32
249 !0..7 'mac!($)': {unknown} 286 !0..26 'macro_...>{1};}': {unknown}
287 !0..26 'macro_...>{1};}': {unknown}
250 107..143 '{ ...!(); }': () 288 107..143 '{ ...!(); }': ()
251 129..130 'a': i32 289 129..130 'a': i32
252 "#]], 290 "#]],