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.rs76
-rw-r--r--crates/hir_def/src/body/tests.rs10
-rw-r--r--crates/hir_def/src/body/tests/block.rs24
3 files changed, 93 insertions, 17 deletions
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index bfb75a8a5..c11da30d2 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -1,10 +1,11 @@
1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` 1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
2//! representation. 2//! representation.
3 3
4use std::mem; 4use std::{mem, sync::Arc};
5 5
6use either::Either; 6use either::Either;
7use hir_expand::{ 7use hir_expand::{
8 ast_id_map::{AstIdMap, FileAstId},
8 hygiene::Hygiene, 9 hygiene::Hygiene,
9 name::{name, AsName, Name}, 10 name::{name, AsName, Name},
10 ExpandError, HirFileId, 11 ExpandError, HirFileId,
@@ -39,20 +40,39 @@ use crate::{
39 40
40use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; 41use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
41 42
42pub(crate) struct LowerCtx { 43pub struct LowerCtx {
43 hygiene: Hygiene, 44 hygiene: Hygiene,
45 file_id: Option<HirFileId>,
46 source_ast_id_map: Option<Arc<AstIdMap>>,
44} 47}
45 48
46impl LowerCtx { 49impl LowerCtx {
47 pub(crate) fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { 50 pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self {
48 LowerCtx { hygiene: Hygiene::new(db.upcast(), file_id) } 51 LowerCtx {
52 hygiene: Hygiene::new(db.upcast(), file_id),
53 file_id: Some(file_id),
54 source_ast_id_map: Some(db.ast_id_map(file_id)),
55 }
49 } 56 }
50 pub(crate) fn with_hygiene(hygiene: &Hygiene) -> Self { 57
51 LowerCtx { hygiene: hygiene.clone() } 58 pub fn with_hygiene(hygiene: &Hygiene) -> Self {
59 LowerCtx { hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None }
60 }
61
62 pub(crate) fn hygiene(&self) -> &Hygiene {
63 &self.hygiene
64 }
65
66 pub(crate) fn file_id(&self) -> HirFileId {
67 self.file_id.unwrap()
52 } 68 }
53 69
54 pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> { 70 pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
55 Path::from_src(ast, &self.hygiene) 71 Path::from_src(ast, self)
72 }
73
74 pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> Option<FileAstId<N>> {
75 self.source_ast_id_map.as_ref().map(|ast_id_map| ast_id_map.ast_id(item))
56 } 76 }
57} 77}
58 78
@@ -531,8 +551,9 @@ impl ExprCollector<'_> {
531 } 551 }
532 } 552 }
533 ast::Expr::MacroCall(e) => { 553 ast::Expr::MacroCall(e) => {
554 let macro_ptr = AstPtr::new(&e);
534 let mut ids = vec![]; 555 let mut ids = vec![];
535 self.collect_macro_call(e, syntax_ptr.clone(), true, |this, expansion| { 556 self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
536 ids.push(match expansion { 557 ids.push(match expansion {
537 Some(it) => this.collect_expr(it), 558 Some(it) => this.collect_expr(it),
538 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()), 559 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
@@ -555,7 +576,7 @@ impl ExprCollector<'_> {
555 fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>( 576 fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
556 &mut self, 577 &mut self,
557 e: ast::MacroCall, 578 e: ast::MacroCall,
558 syntax_ptr: AstPtr<ast::Expr>, 579 syntax_ptr: AstPtr<ast::MacroCall>,
559 is_error_recoverable: bool, 580 is_error_recoverable: bool,
560 mut collector: F, 581 mut collector: F,
561 ) { 582 ) {
@@ -567,9 +588,13 @@ impl ExprCollector<'_> {
567 588
568 let res = match res { 589 let res = match res {
569 Ok(res) => res, 590 Ok(res) => res,
570 Err(UnresolvedMacro) => { 591 Err(UnresolvedMacro { path }) => {
571 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall( 592 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall(
572 UnresolvedMacroCall { file: outer_file, node: syntax_ptr.cast().unwrap() }, 593 UnresolvedMacroCall {
594 file: outer_file,
595 node: syntax_ptr.cast().unwrap(),
596 path,
597 },
573 )); 598 ));
574 collector(self, None); 599 collector(self, None);
575 return; 600 return;
@@ -643,10 +668,14 @@ impl ExprCollector<'_> {
643 668
644 // Note that macro could be expended to multiple statements 669 // Note that macro could be expended to multiple statements
645 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { 670 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
671 let macro_ptr = AstPtr::new(&m);
646 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); 672 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
647 673
648 self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { 674 self.collect_macro_call(
649 match expansion { 675 m,
676 macro_ptr,
677 false,
678 |this, expansion| match expansion {
650 Some(expansion) => { 679 Some(expansion) => {
651 let statements: ast::MacroStmts = expansion; 680 let statements: ast::MacroStmts = expansion;
652 681
@@ -660,8 +689,8 @@ impl ExprCollector<'_> {
660 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone()); 689 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
661 this.statements_in_scope.push(Statement::Expr(expr)); 690 this.statements_in_scope.push(Statement::Expr(expr));
662 } 691 }
663 } 692 },
664 }); 693 );
665 } else { 694 } else {
666 let expr = self.collect_expr_opt(stmt.expr()); 695 let expr = self.collect_expr_opt(stmt.expr());
667 self.statements_in_scope.push(Statement::Expr(expr)); 696 self.statements_in_scope.push(Statement::Expr(expr));
@@ -848,8 +877,23 @@ impl ExprCollector<'_> {
848 Pat::Missing 877 Pat::Missing
849 } 878 }
850 } 879 }
880 ast::Pat::MacroPat(mac) => match mac.macro_call() {
881 Some(call) => {
882 let macro_ptr = AstPtr::new(&call);
883 let mut pat = None;
884 self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
885 pat = Some(this.collect_pat_opt(expanded_pat));
886 });
887
888 match pat {
889 Some(pat) => return pat,
890 None => Pat::Missing,
891 }
892 }
893 None => Pat::Missing,
894 },
851 // FIXME: implement 895 // FIXME: implement
852 ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, 896 ast::Pat::RangePat(_) => Pat::Missing,
853 }; 897 };
854 let ptr = AstPtr::new(&pat); 898 let ptr = AstPtr::new(&pat);
855 self.alloc_pat(pattern, Either::Left(ptr)) 899 self.alloc_pat(pattern, Either::Left(ptr))
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index c1d3e998f..3e8f16306 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -40,6 +40,14 @@ fn block_def_map_at(ra_fixture: &str) -> String {
40 module.def_map(&db).dump(&db) 40 module.def_map(&db).dump(&db)
41} 41}
42 42
43fn check_block_scopes_at(ra_fixture: &str, expect: Expect) {
44 let (db, position) = crate::test_db::TestDB::with_position(ra_fixture);
45
46 let module = db.module_at_position(position);
47 let actual = module.def_map(&db).dump_block_scopes(&db);
48 expect.assert_eq(&actual);
49}
50
43fn check_at(ra_fixture: &str, expect: Expect) { 51fn check_at(ra_fixture: &str, expect: Expect) {
44 let actual = block_def_map_at(ra_fixture); 52 let actual = block_def_map_at(ra_fixture);
45 expect.assert_eq(&actual); 53 expect.assert_eq(&actual);
@@ -180,7 +188,7 @@ fn unresolved_macro_diag() {
180 r#" 188 r#"
181fn f() { 189fn f() {
182 m!(); 190 m!();
183 //^^^^ unresolved macro call 191 //^^^^ unresolved macro `m!`
184} 192}
185 "#, 193 "#,
186 ); 194 );
diff --git a/crates/hir_def/src/body/tests/block.rs b/crates/hir_def/src/body/tests/block.rs
index 3b6ba4cde..bc3d0f138 100644
--- a/crates/hir_def/src/body/tests/block.rs
+++ b/crates/hir_def/src/body/tests/block.rs
@@ -134,6 +134,30 @@ struct Struct {}
134} 134}
135 135
136#[test] 136#[test]
137fn nested_module_scoping() {
138 check_block_scopes_at(
139 r#"
140fn f() {
141 mod module {
142 struct Struct {}
143 fn f() {
144 use self::Struct;
145 $0
146 }
147 }
148}
149 "#,
150 expect![[r#"
151 BlockId(1) in ModuleId { krate: CrateId(0), block: Some(BlockId(0)), local_id: Idx::<ModuleData>(0) }
152 BlockId(0) in ModuleId { krate: CrateId(0), block: None, local_id: Idx::<ModuleData>(0) }
153 crate scope
154 "#]],
155 );
156 // FIXME: The module nesting here is wrong!
157 // The first block map should be located in module #1 (`mod module`), not #0 (BlockId(0) root module)
158}
159
160#[test]
137fn legacy_macro_items() { 161fn legacy_macro_items() {
138 // Checks that legacy-scoped `macro_rules!` from parent namespaces are resolved and expanded 162 // Checks that legacy-scoped `macro_rules!` from parent namespaces are resolved and expanded
139 // correctly. 163 // correctly.