aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_def/src/body/lower.rs216
-rw-r--r--crates/hir_def/src/item_tree.rs3
-rw-r--r--crates/hir_expand/src/db.rs3
3 files changed, 139 insertions, 83 deletions
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 689a3274c..6c0de3ee8 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -548,62 +548,83 @@ impl ExprCollector<'_> {
548 } 548 }
549 } 549 }
550 ast::Expr::MacroCall(e) => { 550 ast::Expr::MacroCall(e) => {
551 if let Some(name) = e.is_macro_rules().map(|it| it.as_name()) { 551 let mut ids = vec![];
552 let mac = MacroDefId { 552 self.collect_macro_call(e, syntax_ptr.clone(), |this, expansion| {
553 krate: Some(self.expander.module.krate), 553 ids.push(match expansion {
554 ast_id: Some(self.expander.ast_id(&e)), 554 Some(it) => this.collect_expr(it),
555 kind: MacroDefKind::Declarative, 555 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
556 local_inner: false, 556 })
557 }; 557 });
558 self.body.item_scope.define_legacy_macro(name, mac); 558 ids[0]
559 559 }
560 // FIXME: do we still need to allocate this as missing ? 560 }
561 self.alloc_expr(Expr::Missing, syntax_ptr) 561 }
562 } else {
563 // File containing the macro call. Expansion errors will be attached here.
564 let outer_file = self.expander.current_file_id;
565
566 let macro_call = self.expander.to_source(AstPtr::new(&e));
567 let res = self.expander.enter_expand(self.db, Some(&self.body.item_scope), e);
568
569 match res.err {
570 Some(ExpandError::UnresolvedProcMacro) => {
571 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro(
572 UnresolvedProcMacro {
573 file: outer_file,
574 node: syntax_ptr.clone().into(),
575 precise_location: None,
576 macro_name: None,
577 },
578 ));
579 }
580 Some(err) => {
581 self.source_map.diagnostics.push(BodyDiagnostic::MacroError(
582 MacroError {
583 file: outer_file,
584 node: syntax_ptr.clone().into(),
585 message: err.to_string(),
586 },
587 ));
588 }
589 None => {}
590 }
591 562
592 match res.value { 563 fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
593 Some((mark, expansion)) => { 564 &mut self,
594 self.source_map 565 e: ast::MacroCall,
595 .expansions 566 syntax_ptr: AstPtr<ast::Expr>,
596 .insert(macro_call, self.expander.current_file_id); 567 mut collector: F,
597 568 ) {
598 let item_tree = self.db.item_tree(self.expander.current_file_id); 569 if let Some(name) = e.is_macro_rules().map(|it| it.as_name()) {
599 self.item_trees.insert(self.expander.current_file_id, item_tree); 570 let mac = MacroDefId {
600 let id = self.collect_expr(expansion); 571 krate: Some(self.expander.module.krate),
601 self.expander.exit(self.db, mark); 572 ast_id: Some(self.expander.ast_id(&e)),
602 id 573 kind: MacroDefKind::Declarative,
603 } 574 local_inner: false,
604 None => self.alloc_expr(Expr::Missing, syntax_ptr), 575 };
576 self.body.item_scope.define_legacy_macro(name, mac);
577
578 // FIXME: do we still need to allocate this as missing ?
579 collector(self, None);
580 } else {
581 // File containing the macro call. Expansion errors will be attached here.
582 let outer_file = self.expander.current_file_id;
583
584 let macro_call = self.expander.to_source(AstPtr::new(&e));
585 let res = self.expander.enter_expand(self.db, Some(&self.body.item_scope), e);
586
587 match &res.err {
588 Some(ExpandError::UnresolvedProcMacro) => {
589 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro(
590 UnresolvedProcMacro {
591 file: outer_file,
592 node: syntax_ptr.into(),
593 precise_location: None,
594 macro_name: None,
595 },
596 ));
597 }
598 Some(err) => {
599 self.source_map.diagnostics.push(BodyDiagnostic::MacroError(MacroError {
600 file: outer_file,
601 node: syntax_ptr.into(),
602 message: err.to_string(),
603 }));
604 }
605 None => {}
606 }
607
608 match res.value {
609 Some((mark, expansion)) => {
610 // FIXME: Statements are too complicated to recover from error for now.
611 // It is because we don't have any hygenine for local variable expansion right now.
612 if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() {
613 self.expander.exit(self.db, mark);
614 collector(self, None);
615 } else {
616 self.source_map
617 .expansions
618 .insert(macro_call, self.expander.current_file_id);
619
620 let item_tree = self.db.item_tree(self.expander.current_file_id);
621 self.item_trees.insert(self.expander.current_file_id, item_tree);
622
623 collector(self, Some(expansion));
624 self.expander.exit(self.db, mark);
605 } 625 }
606 } 626 }
627 None => collector(self, None),
607 } 628 }
608 } 629 }
609 } 630 }
@@ -642,44 +663,75 @@ impl ExprCollector<'_> {
642 } 663 }
643 } 664 }
644 665
645 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { 666 fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> {
646 let syntax_node_ptr = AstPtr::new(&block.clone().into()); 667 let stmt =
647 self.collect_block_items(&block); 668 match s {
648 let statements = block 669 ast::Stmt::LetStmt(stmt) => {
649 .statements() 670 self.check_cfg(&stmt)?;
650 .filter_map(|s| {
651 let stmt = match s {
652 ast::Stmt::LetStmt(stmt) => {
653 self.check_cfg(&stmt)?;
654
655 let pat = self.collect_pat_opt(stmt.pat());
656 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
657 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
658 Statement::Let { pat, type_ref, initializer }
659 }
660 ast::Stmt::ExprStmt(stmt) => {
661 self.check_cfg(&stmt)?;
662 671
663 Statement::Expr(self.collect_expr_opt(stmt.expr())) 672 let pat = self.collect_pat_opt(stmt.pat());
664 } 673 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
665 ast::Stmt::Item(item) => { 674 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
666 self.check_cfg(&item)?; 675 vec![Statement::Let { pat, type_ref, initializer }]
676 }
677 ast::Stmt::ExprStmt(stmt) => {
678 self.check_cfg(&stmt)?;
679
680 // Note that macro could be expended to multiple statements
681 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
682 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
683 let mut stmts = vec![];
684
685 self.collect_macro_call(m, syntax_ptr.clone(), |this, expansion| {
686 match expansion {
687 Some(expansion) => {
688 let statements: ast::MacroStmts = expansion;
689 this.collect_stmts_items(statements.statements());
667 690
668 return None; 691 statements.statements().for_each(|stmt| {
692 if let Some(mut r) = this.collect_stmt(stmt) {
693 stmts.append(&mut r);
694 }
695 });
696 if let Some(expr) = statements.expr() {
697 stmts.push(Statement::Expr(this.collect_expr(expr)));
698 }
699 }
700 None => {
701 stmts.push(Statement::Expr(
702 this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
703 ));
704 }
705 }
706 });
707 stmts
708 } else {
709 vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))]
669 } 710 }
670 }; 711 }
671 Some(stmt) 712 ast::Stmt::Item(item) => {
672 }) 713 self.check_cfg(&item)?;
673 .collect(); 714
715 return None;
716 }
717 };
718
719 Some(stmt)
720 }
721
722 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
723 let syntax_node_ptr = AstPtr::new(&block.clone().into());
724 self.collect_stmts_items(block.statements());
725 let statements =
726 block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect();
674 let tail = block.expr().map(|e| self.collect_expr(e)); 727 let tail = block.expr().map(|e| self.collect_expr(e));
675 self.alloc_expr(Expr::Block { statements, tail, label: None }, syntax_node_ptr) 728 self.alloc_expr(Expr::Block { statements, tail, label: None }, syntax_node_ptr)
676 } 729 }
677 730
678 fn collect_block_items(&mut self, block: &ast::BlockExpr) { 731 fn collect_stmts_items(&mut self, stmts: ast::AstChildren<ast::Stmt>) {
679 let container = ContainerId::DefWithBodyId(self.def); 732 let container = ContainerId::DefWithBodyId(self.def);
680 733
681 let items = block 734 let items = stmts
682 .statements()
683 .filter_map(|stmt| match stmt { 735 .filter_map(|stmt| match stmt {
684 ast::Stmt::Item(it) => Some(it), 736 ast::Stmt::Item(it) => Some(it),
685 ast::Stmt::LetStmt(_) | ast::Stmt::ExprStmt(_) => None, 737 ast::Stmt::LetStmt(_) | ast::Stmt::ExprStmt(_) => None,
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index b08167281..864fad170 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -94,6 +94,9 @@ impl ItemTree {
94 ast::MacroItems(items) => { 94 ast::MacroItems(items) => {
95 ctx.lower_module_items(&items) 95 ctx.lower_module_items(&items)
96 }, 96 },
97 ast::MacroStmts(stmts) => {
98 ctx.lower_inner_items(stmts.syntax())
99 },
97 // Macros can expand to expressions. We return an empty item tree in this case, but 100 // Macros can expand to expressions. We return an empty item tree in this case, but
98 // still need to collect inner items. 101 // still need to collect inner items.
99 ast::Expr(e) => { 102 ast::Expr(e) => {
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index ffb70f723..7fc700e82 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -395,7 +395,8 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
395 FragmentKind::Expr 395 FragmentKind::Expr
396 } 396 }
397 // FIXME: Expand to statements in appropriate positions; HIR lowering needs to handle that 397 // FIXME: Expand to statements in appropriate positions; HIR lowering needs to handle that
398 EXPR_STMT | BLOCK_EXPR => FragmentKind::Expr, 398 EXPR_STMT => FragmentKind::Statements,
399 BLOCK_EXPR => FragmentKind::Expr,
399 ARG_LIST => FragmentKind::Expr, 400 ARG_LIST => FragmentKind::Expr,
400 TRY_EXPR => FragmentKind::Expr, 401 TRY_EXPR => FragmentKind::Expr,
401 TUPLE_EXPR => FragmentKind::Expr, 402 TUPLE_EXPR => FragmentKind::Expr,