diff options
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r-- | crates/hir_def/src/body/lower.rs | 105 | ||||
-rw-r--r-- | crates/hir_def/src/diagnostics.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 5 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 33 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/diagnostics.rs | 45 |
5 files changed, 132 insertions, 58 deletions
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 8934ae6c9..7052058f2 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -519,7 +519,7 @@ impl ExprCollector<'_> { | |||
519 | } | 519 | } |
520 | ast::Expr::MacroCall(e) => { | 520 | ast::Expr::MacroCall(e) => { |
521 | let mut ids = vec![]; | 521 | let mut ids = vec![]; |
522 | self.collect_macro_call(e, syntax_ptr.clone(), |this, expansion| { | 522 | self.collect_macro_call(e, syntax_ptr.clone(), true, |this, expansion| { |
523 | ids.push(match expansion { | 523 | ids.push(match expansion { |
524 | Some(it) => this.collect_expr(it), | 524 | Some(it) => this.collect_expr(it), |
525 | None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()), | 525 | None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()), |
@@ -527,6 +527,17 @@ impl ExprCollector<'_> { | |||
527 | }); | 527 | }); |
528 | ids[0] | 528 | ids[0] |
529 | } | 529 | } |
530 | ast::Expr::MacroStmts(e) => { | ||
531 | // FIXME: these statements should be held by some hir containter | ||
532 | for stmt in e.statements() { | ||
533 | self.collect_stmt(stmt); | ||
534 | } | ||
535 | if let Some(expr) = e.expr() { | ||
536 | self.collect_expr(expr) | ||
537 | } else { | ||
538 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
539 | } | ||
540 | } | ||
530 | } | 541 | } |
531 | } | 542 | } |
532 | 543 | ||
@@ -534,6 +545,7 @@ impl ExprCollector<'_> { | |||
534 | &mut self, | 545 | &mut self, |
535 | e: ast::MacroCall, | 546 | e: ast::MacroCall, |
536 | syntax_ptr: AstPtr<ast::Expr>, | 547 | syntax_ptr: AstPtr<ast::Expr>, |
548 | is_error_recoverable: bool, | ||
537 | mut collector: F, | 549 | mut collector: F, |
538 | ) { | 550 | ) { |
539 | // File containing the macro call. Expansion errors will be attached here. | 551 | // File containing the macro call. Expansion errors will be attached here. |
@@ -567,7 +579,7 @@ impl ExprCollector<'_> { | |||
567 | Some((mark, expansion)) => { | 579 | Some((mark, expansion)) => { |
568 | // FIXME: Statements are too complicated to recover from error for now. | 580 | // FIXME: Statements are too complicated to recover from error for now. |
569 | // It is because we don't have any hygiene for local variable expansion right now. | 581 | // It is because we don't have any hygiene for local variable expansion right now. |
570 | if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() { | 582 | if !is_error_recoverable && res.err.is_some() { |
571 | self.expander.exit(self.db, mark); | 583 | self.expander.exit(self.db, mark); |
572 | collector(self, None); | 584 | collector(self, None); |
573 | } else { | 585 | } else { |
@@ -591,56 +603,55 @@ impl ExprCollector<'_> { | |||
591 | } | 603 | } |
592 | 604 | ||
593 | fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> { | 605 | fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> { |
594 | let stmt = | 606 | let stmt = match s { |
595 | match s { | 607 | ast::Stmt::LetStmt(stmt) => { |
596 | ast::Stmt::LetStmt(stmt) => { | 608 | self.check_cfg(&stmt)?; |
597 | self.check_cfg(&stmt)?; | 609 | |
598 | 610 | let pat = self.collect_pat_opt(stmt.pat()); | |
599 | let pat = self.collect_pat_opt(stmt.pat()); | 611 | let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); |
600 | let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); | 612 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); |
601 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); | 613 | vec![Statement::Let { pat, type_ref, initializer }] |
602 | vec![Statement::Let { pat, type_ref, initializer }] | 614 | } |
603 | } | 615 | ast::Stmt::ExprStmt(stmt) => { |
604 | ast::Stmt::ExprStmt(stmt) => { | 616 | self.check_cfg(&stmt)?; |
605 | self.check_cfg(&stmt)?; | 617 | |
606 | 618 | // Note that macro could be expended to multiple statements | |
607 | // Note that macro could be expended to multiple statements | 619 | if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { |
608 | if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { | 620 | let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); |
609 | let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); | 621 | let mut stmts = vec![]; |
610 | let mut stmts = vec![]; | 622 | |
611 | 623 | self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { | |
612 | self.collect_macro_call(m, syntax_ptr.clone(), |this, expansion| { | 624 | match expansion { |
613 | match expansion { | 625 | Some(expansion) => { |
614 | Some(expansion) => { | 626 | let statements: ast::MacroStmts = expansion; |
615 | let statements: ast::MacroStmts = expansion; | 627 | |
616 | 628 | statements.statements().for_each(|stmt| { | |
617 | statements.statements().for_each(|stmt| { | 629 | if let Some(mut r) = this.collect_stmt(stmt) { |
618 | if let Some(mut r) = this.collect_stmt(stmt) { | 630 | stmts.append(&mut r); |
619 | stmts.append(&mut r); | ||
620 | } | ||
621 | }); | ||
622 | if let Some(expr) = statements.expr() { | ||
623 | stmts.push(Statement::Expr(this.collect_expr(expr))); | ||
624 | } | 631 | } |
625 | } | 632 | }); |
626 | None => { | 633 | if let Some(expr) = statements.expr() { |
627 | stmts.push(Statement::Expr( | 634 | stmts.push(Statement::Expr(this.collect_expr(expr))); |
628 | this.alloc_expr(Expr::Missing, syntax_ptr.clone()), | ||
629 | )); | ||
630 | } | 635 | } |
631 | } | 636 | } |
632 | }); | 637 | None => { |
633 | stmts | 638 | stmts.push(Statement::Expr( |
634 | } else { | 639 | this.alloc_expr(Expr::Missing, syntax_ptr.clone()), |
635 | vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))] | 640 | )); |
636 | } | 641 | } |
642 | } | ||
643 | }); | ||
644 | stmts | ||
645 | } else { | ||
646 | vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))] | ||
637 | } | 647 | } |
638 | ast::Stmt::Item(item) => { | 648 | } |
639 | self.check_cfg(&item)?; | 649 | ast::Stmt::Item(item) => { |
650 | self.check_cfg(&item)?; | ||
640 | 651 | ||
641 | return None; | 652 | return None; |
642 | } | 653 | } |
643 | }; | 654 | }; |
644 | 655 | ||
645 | Some(stmt) | 656 | Some(stmt) |
646 | } | 657 | } |
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs index ac7474f63..7188bb299 100644 --- a/crates/hir_def/src/diagnostics.rs +++ b/crates/hir_def/src/diagnostics.rs | |||
@@ -97,7 +97,7 @@ impl Diagnostic for UnresolvedImport { | |||
97 | 97 | ||
98 | // Diagnostic: unresolved-macro-call | 98 | // Diagnostic: unresolved-macro-call |
99 | // | 99 | // |
100 | // This diagnostic is triggered if rust-analyzer is unable to resolove path to a | 100 | // This diagnostic is triggered if rust-analyzer is unable to resolve the path to a |
101 | // macro in a macro invocation. | 101 | // macro in a macro invocation. |
102 | #[derive(Debug)] | 102 | #[derive(Debug)] |
103 | pub struct UnresolvedMacroCall { | 103 | pub struct UnresolvedMacroCall { |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index d63ac3df3..7bb22c4c4 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -110,6 +110,11 @@ 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 | }, | ||
113 | _ => { | 118 | _ => { |
114 | panic!("cannot create item tree from {:?} {}", syntax, syntax); | 119 | panic!("cannot create item tree from {:?} {}", syntax, syntax); |
115 | }, | 120 | }, |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 9ed48c506..81cf652b0 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -13,7 +13,7 @@ use hir_expand::{ | |||
13 | builtin_macro::find_builtin_macro, | 13 | builtin_macro::find_builtin_macro, |
14 | name::{AsName, Name}, | 14 | name::{AsName, Name}, |
15 | proc_macro::ProcMacroExpander, | 15 | proc_macro::ProcMacroExpander, |
16 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, | 16 | HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, |
17 | }; | 17 | }; |
18 | use hir_expand::{InFile, MacroCallLoc}; | 18 | use hir_expand::{InFile, MacroCallLoc}; |
19 | use rustc_hash::{FxHashMap, FxHashSet}; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -1455,7 +1455,8 @@ impl ModCollector<'_, '_> { | |||
1455 | let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); | 1455 | let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); |
1456 | 1456 | ||
1457 | // Case 1: try to resolve in legacy scope and expand macro_rules | 1457 | // Case 1: try to resolve in legacy scope and expand macro_rules |
1458 | if let Ok(Ok(macro_call_id)) = macro_call_as_call_id( | 1458 | let mut error = None; |
1459 | match macro_call_as_call_id( | ||
1459 | &ast_id, | 1460 | &ast_id, |
1460 | self.def_collector.db, | 1461 | self.def_collector.db, |
1461 | self.def_collector.def_map.krate, | 1462 | self.def_collector.def_map.krate, |
@@ -1468,16 +1469,28 @@ impl ModCollector<'_, '_> { | |||
1468 | ) | 1469 | ) |
1469 | }) | 1470 | }) |
1470 | }, | 1471 | }, |
1471 | &mut |_err| (), | 1472 | &mut |err| error = Some(err), |
1472 | ) { | 1473 | ) { |
1473 | self.def_collector.unexpanded_macros.push(MacroDirective { | 1474 | Ok(Ok(macro_call_id)) => { |
1474 | module_id: self.module_id, | 1475 | self.def_collector.unexpanded_macros.push(MacroDirective { |
1475 | ast_id, | 1476 | module_id: self.module_id, |
1476 | legacy: Some(macro_call_id), | 1477 | ast_id, |
1477 | depth: self.macro_depth + 1, | 1478 | legacy: Some(macro_call_id), |
1478 | }); | 1479 | depth: self.macro_depth + 1, |
1480 | }); | ||
1479 | 1481 | ||
1480 | return; | 1482 | return; |
1483 | } | ||
1484 | Ok(Err(_)) => { | ||
1485 | // Built-in macro failed eager expansion. | ||
1486 | self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error( | ||
1487 | self.module_id, | ||
1488 | MacroCallKind::FnLike(ast_id.ast_id), | ||
1489 | error.unwrap().to_string(), | ||
1490 | )); | ||
1491 | return; | ||
1492 | } | ||
1493 | Err(UnresolvedMacro) => (), | ||
1481 | } | 1494 | } |
1482 | 1495 | ||
1483 | // Case 2: resolve in module scope, expand during name resolution. | 1496 | // Case 2: resolve in module scope, expand during name resolution. |
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs index 1b8e885b0..c22ef46fd 100644 --- a/crates/hir_def/src/nameres/tests/diagnostics.rs +++ b/crates/hir_def/src/nameres/tests/diagnostics.rs | |||
@@ -155,3 +155,48 @@ fn inactive_via_cfg_attr() { | |||
155 | "#, | 155 | "#, |
156 | ); | 156 | ); |
157 | } | 157 | } |
158 | |||
159 | #[test] | ||
160 | fn unresolved_legacy_scope_macro() { | ||
161 | check_diagnostics( | ||
162 | r#" | ||
163 | //- /lib.rs | ||
164 | macro_rules! m { () => {} } | ||
165 | |||
166 | m!(); | ||
167 | m2!(); | ||
168 | //^^^^^^ unresolved macro call | ||
169 | "#, | ||
170 | ); | ||
171 | } | ||
172 | |||
173 | #[test] | ||
174 | fn unresolved_module_scope_macro() { | ||
175 | check_diagnostics( | ||
176 | r#" | ||
177 | //- /lib.rs | ||
178 | mod mac { | ||
179 | #[macro_export] | ||
180 | macro_rules! m { () => {} } | ||
181 | } | ||
182 | |||
183 | self::m!(); | ||
184 | self::m2!(); | ||
185 | //^^^^^^^^^^^^ unresolved macro call | ||
186 | "#, | ||
187 | ); | ||
188 | } | ||
189 | |||
190 | #[test] | ||
191 | fn builtin_macro_fails_expansion() { | ||
192 | check_diagnostics( | ||
193 | r#" | ||
194 | //- /lib.rs | ||
195 | #[rustc_builtin_macro] | ||
196 | macro_rules! include { () => {} } | ||
197 | |||
198 | include!("doesntexist"); | ||
199 | //^^^^^^^^^^^^^^^^^^^^^^^^ could not convert tokens | ||
200 | "#, | ||
201 | ); | ||
202 | } | ||