aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/body
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/body')
-rw-r--r--crates/hir_def/src/body/lower.rs246
1 files changed, 151 insertions, 95 deletions
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 689a3274c..bdba4c33e 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -548,63 +548,70 @@ 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 }
560 }
561 }
559 562
560 // FIXME: do we still need to allocate this as missing ? 563 fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
561 self.alloc_expr(Expr::Missing, syntax_ptr) 564 &mut self,
565 e: ast::MacroCall,
566 syntax_ptr: AstPtr<ast::Expr>,
567 mut collector: F,
568 ) {
569 // File containing the macro call. Expansion errors will be attached here.
570 let outer_file = self.expander.current_file_id;
571
572 let macro_call = self.expander.to_source(AstPtr::new(&e));
573 let res = self.expander.enter_expand(self.db, Some(&self.body.item_scope), e);
574
575 match &res.err {
576 Some(ExpandError::UnresolvedProcMacro) => {
577 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro(
578 UnresolvedProcMacro {
579 file: outer_file,
580 node: syntax_ptr.into(),
581 precise_location: None,
582 macro_name: None,
583 },
584 ));
585 }
586 Some(err) => {
587 self.source_map.diagnostics.push(BodyDiagnostic::MacroError(MacroError {
588 file: outer_file,
589 node: syntax_ptr.into(),
590 message: err.to_string(),
591 }));
592 }
593 None => {}
594 }
595
596 match res.value {
597 Some((mark, expansion)) => {
598 // FIXME: Statements are too complicated to recover from error for now.
599 // It is because we don't have any hygenine for local variable expansion right now.
600 if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() {
601 self.expander.exit(self.db, mark);
602 collector(self, None);
562 } else { 603 } else {
563 // File containing the macro call. Expansion errors will be attached here. 604 self.source_map.expansions.insert(macro_call, self.expander.current_file_id);
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 605
592 match res.value { 606 let item_tree = self.db.item_tree(self.expander.current_file_id);
593 Some((mark, expansion)) => { 607 self.item_trees.insert(self.expander.current_file_id, item_tree);
594 self.source_map 608
595 .expansions 609 let id = collector(self, Some(expansion));
596 .insert(macro_call, self.expander.current_file_id); 610 self.expander.exit(self.db, mark);
597 611 id
598 let item_tree = self.db.item_tree(self.expander.current_file_id);
599 self.item_trees.insert(self.expander.current_file_id, item_tree);
600 let id = self.collect_expr(expansion);
601 self.expander.exit(self.db, mark);
602 id
603 }
604 None => self.alloc_expr(Expr::Missing, syntax_ptr),
605 }
606 } 612 }
607 } 613 }
614 None => collector(self, None),
608 } 615 }
609 } 616 }
610 617
@@ -642,44 +649,75 @@ impl ExprCollector<'_> {
642 } 649 }
643 } 650 }
644 651
645 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { 652 fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> {
646 let syntax_node_ptr = AstPtr::new(&block.clone().into()); 653 let stmt =
647 self.collect_block_items(&block); 654 match s {
648 let statements = block 655 ast::Stmt::LetStmt(stmt) => {
649 .statements() 656 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 657
663 Statement::Expr(self.collect_expr_opt(stmt.expr())) 658 let pat = self.collect_pat_opt(stmt.pat());
664 } 659 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
665 ast::Stmt::Item(item) => { 660 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
666 self.check_cfg(&item)?; 661 vec![Statement::Let { pat, type_ref, initializer }]
662 }
663 ast::Stmt::ExprStmt(stmt) => {
664 self.check_cfg(&stmt)?;
665
666 // Note that macro could be expended to multiple statements
667 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
668 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
669 let mut stmts = vec![];
670
671 self.collect_macro_call(m, syntax_ptr.clone(), |this, expansion| {
672 match expansion {
673 Some(expansion) => {
674 let statements: ast::MacroStmts = expansion;
675 this.collect_stmts_items(statements.statements());
667 676
668 return None; 677 statements.statements().for_each(|stmt| {
678 if let Some(mut r) = this.collect_stmt(stmt) {
679 stmts.append(&mut r);
680 }
681 });
682 if let Some(expr) = statements.expr() {
683 stmts.push(Statement::Expr(this.collect_expr(expr)));
684 }
685 }
686 None => {
687 stmts.push(Statement::Expr(
688 this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
689 ));
690 }
691 }
692 });
693 stmts
694 } else {
695 vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))]
669 } 696 }
670 }; 697 }
671 Some(stmt) 698 ast::Stmt::Item(item) => {
672 }) 699 self.check_cfg(&item)?;
673 .collect(); 700
701 return None;
702 }
703 };
704
705 Some(stmt)
706 }
707
708 fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
709 let syntax_node_ptr = AstPtr::new(&block.clone().into());
710 self.collect_stmts_items(block.statements());
711 let statements =
712 block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect();
674 let tail = block.expr().map(|e| self.collect_expr(e)); 713 let tail = block.expr().map(|e| self.collect_expr(e));
675 self.alloc_expr(Expr::Block { statements, tail, label: None }, syntax_node_ptr) 714 self.alloc_expr(Expr::Block { statements, tail, label: None }, syntax_node_ptr)
676 } 715 }
677 716
678 fn collect_block_items(&mut self, block: &ast::BlockExpr) { 717 fn collect_stmts_items(&mut self, stmts: ast::AstChildren<ast::Stmt>) {
679 let container = ContainerId::DefWithBodyId(self.def); 718 let container = ContainerId::DefWithBodyId(self.def);
680 719
681 let items = block 720 let items = stmts
682 .statements()
683 .filter_map(|stmt| match stmt { 721 .filter_map(|stmt| match stmt {
684 ast::Stmt::Item(it) => Some(it), 722 ast::Stmt::Item(it) => Some(it),
685 ast::Stmt::LetStmt(_) | ast::Stmt::ExprStmt(_) => None, 723 ast::Stmt::LetStmt(_) | ast::Stmt::ExprStmt(_) => None,
@@ -733,26 +771,44 @@ impl ExprCollector<'_> {
733 | ast::Item::ExternCrate(_) 771 | ast::Item::ExternCrate(_)
734 | ast::Item::Module(_) 772 | ast::Item::Module(_)
735 | ast::Item::MacroCall(_) => return None, 773 | ast::Item::MacroCall(_) => return None,
774 ast::Item::MacroRules(def) => {
775 return Some(Either::Right(def));
776 }
736 }; 777 };
737 778
738 Some((def, name)) 779 Some(Either::Left((def, name)))
739 }) 780 })
740 .collect::<Vec<_>>(); 781 .collect::<Vec<_>>();
741 782
742 for (def, name) in items { 783 for either in items {
743 self.body.item_scope.define_def(def); 784 match either {
744 if let Some(name) = name { 785 Either::Left((def, name)) => {
745 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly 786 self.body.item_scope.define_def(def);
746 let has_constructor = match def { 787 if let Some(name) = name {
747 ModuleDefId::AdtId(AdtId::StructId(s)) => { 788 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
748 self.db.struct_data(s).variant_data.kind() != StructKind::Record 789 let has_constructor = match def {
790 ModuleDefId::AdtId(AdtId::StructId(s)) => {
791 self.db.struct_data(s).variant_data.kind() != StructKind::Record
792 }
793 _ => true,
794 };
795 self.body.item_scope.push_res(
796 name.as_name(),
797 crate::per_ns::PerNs::from_def(def, vis, has_constructor),
798 );
749 } 799 }
750 _ => true, 800 }
751 }; 801 Either::Right(e) => {
752 self.body.item_scope.push_res( 802 let mac = MacroDefId {
753 name.as_name(), 803 krate: Some(self.expander.module.krate),
754 crate::per_ns::PerNs::from_def(def, vis, has_constructor), 804 ast_id: Some(self.expander.ast_id(&e)),
755 ); 805 kind: MacroDefKind::Declarative,
806 local_inner: false,
807 };
808 if let Some(name) = e.name() {
809 self.body.item_scope.define_legacy_macro(name.as_name(), mac);
810 }
811 }
756 } 812 }
757 } 813 }
758 } 814 }