diff options
Diffstat (limited to 'crates/hir_def/src/body')
-rw-r--r-- | crates/hir_def/src/body/lower.rs | 76 | ||||
-rw-r--r-- | crates/hir_def/src/body/tests.rs | 10 | ||||
-rw-r--r-- | crates/hir_def/src/body/tests/block.rs | 24 |
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 | ||
4 | use std::mem; | 4 | use std::{mem, sync::Arc}; |
5 | 5 | ||
6 | use either::Either; | 6 | use either::Either; |
7 | use hir_expand::{ | 7 | use 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 | ||
40 | use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; | 41 | use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; |
41 | 42 | ||
42 | pub(crate) struct LowerCtx { | 43 | pub 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 | ||
46 | impl LowerCtx { | 49 | impl 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 | ||
43 | fn 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 | |||
43 | fn check_at(ra_fixture: &str, expect: Expect) { | 51 | fn 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#" |
181 | fn f() { | 189 | fn 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] |
137 | fn nested_module_scoping() { | ||
138 | check_block_scopes_at( | ||
139 | r#" | ||
140 | fn 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] | ||
137 | fn legacy_macro_items() { | 161 | fn 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. |