diff options
Diffstat (limited to 'crates/hir_def/src/body')
-rw-r--r-- | crates/hir_def/src/body/lower.rs | 246 |
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 | } |