diff options
Diffstat (limited to 'crates/hir_def/src/body')
-rw-r--r-- | crates/hir_def/src/body/lower.rs | 105 | ||||
-rw-r--r-- | crates/hir_def/src/body/tests.rs | 12 | ||||
-rw-r--r-- | crates/hir_def/src/body/tests/block.rs | 24 |
3 files changed, 112 insertions, 29 deletions
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 63e89a1f4..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, |
@@ -30,6 +31,7 @@ use crate::{ | |||
30 | LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, | 31 | LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, |
31 | Statement, | 32 | Statement, |
32 | }, | 33 | }, |
34 | intern::Interned, | ||
33 | item_scope::BuiltinShadowMode, | 35 | item_scope::BuiltinShadowMode, |
34 | path::{GenericArgs, Path}, | 36 | path::{GenericArgs, Path}, |
35 | type_ref::{Mutability, Rawness, TypeRef}, | 37 | type_ref::{Mutability, Rawness, TypeRef}, |
@@ -38,20 +40,39 @@ use crate::{ | |||
38 | 40 | ||
39 | use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; | 41 | use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; |
40 | 42 | ||
41 | pub(crate) struct LowerCtx { | 43 | pub struct LowerCtx { |
42 | hygiene: Hygiene, | 44 | hygiene: Hygiene, |
45 | file_id: Option<HirFileId>, | ||
46 | source_ast_id_map: Option<Arc<AstIdMap>>, | ||
43 | } | 47 | } |
44 | 48 | ||
45 | impl LowerCtx { | 49 | impl LowerCtx { |
46 | pub(crate) fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { | 50 | pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { |
47 | 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 | } | ||
48 | } | 56 | } |
49 | pub(crate) fn with_hygiene(hygiene: &Hygiene) -> Self { | 57 | |
50 | 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() | ||
51 | } | 68 | } |
52 | 69 | ||
53 | pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> { | 70 | pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> { |
54 | 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)) | ||
55 | } | 76 | } |
56 | } | 77 | } |
57 | 78 | ||
@@ -322,8 +343,10 @@ impl ExprCollector<'_> { | |||
322 | Vec::new() | 343 | Vec::new() |
323 | }; | 344 | }; |
324 | let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); | 345 | let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); |
325 | let generic_args = | 346 | let generic_args = e |
326 | e.generic_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it)); | 347 | .generic_arg_list() |
348 | .and_then(|it| GenericArgs::from_ast(&self.ctx(), it)) | ||
349 | .map(Box::new); | ||
327 | self.alloc_expr( | 350 | self.alloc_expr( |
328 | Expr::MethodCall { receiver, method_name, args, generic_args }, | 351 | Expr::MethodCall { receiver, method_name, args, generic_args }, |
329 | syntax_ptr, | 352 | syntax_ptr, |
@@ -385,7 +408,7 @@ impl ExprCollector<'_> { | |||
385 | self.alloc_expr(Expr::Yield { expr }, syntax_ptr) | 408 | self.alloc_expr(Expr::Yield { expr }, syntax_ptr) |
386 | } | 409 | } |
387 | ast::Expr::RecordExpr(e) => { | 410 | ast::Expr::RecordExpr(e) => { |
388 | let path = e.path().and_then(|path| self.expander.parse_path(path)); | 411 | let path = e.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); |
389 | let record_lit = if let Some(nfl) = e.record_expr_field_list() { | 412 | let record_lit = if let Some(nfl) = e.record_expr_field_list() { |
390 | let fields = nfl | 413 | let fields = nfl |
391 | .fields() | 414 | .fields() |
@@ -430,7 +453,7 @@ impl ExprCollector<'_> { | |||
430 | } | 453 | } |
431 | ast::Expr::CastExpr(e) => { | 454 | ast::Expr::CastExpr(e) => { |
432 | let expr = self.collect_expr_opt(e.expr()); | 455 | let expr = self.collect_expr_opt(e.expr()); |
433 | let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty()); | 456 | let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty())); |
434 | self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) | 457 | self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) |
435 | } | 458 | } |
436 | ast::Expr::RefExpr(e) => { | 459 | ast::Expr::RefExpr(e) => { |
@@ -464,13 +487,16 @@ impl ExprCollector<'_> { | |||
464 | if let Some(pl) = e.param_list() { | 487 | if let Some(pl) = e.param_list() { |
465 | for param in pl.params() { | 488 | for param in pl.params() { |
466 | let pat = self.collect_pat_opt(param.pat()); | 489 | let pat = self.collect_pat_opt(param.pat()); |
467 | let type_ref = param.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); | 490 | let type_ref = |
491 | param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it))); | ||
468 | args.push(pat); | 492 | args.push(pat); |
469 | arg_types.push(type_ref); | 493 | arg_types.push(type_ref); |
470 | } | 494 | } |
471 | } | 495 | } |
472 | let ret_type = | 496 | let ret_type = e |
473 | e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it)); | 497 | .ret_type() |
498 | .and_then(|r| r.ty()) | ||
499 | .map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it))); | ||
474 | let body = self.collect_expr_opt(e.body()); | 500 | let body = self.collect_expr_opt(e.body()); |
475 | self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) | 501 | self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) |
476 | } | 502 | } |
@@ -525,8 +551,9 @@ impl ExprCollector<'_> { | |||
525 | } | 551 | } |
526 | } | 552 | } |
527 | ast::Expr::MacroCall(e) => { | 553 | ast::Expr::MacroCall(e) => { |
554 | let macro_ptr = AstPtr::new(&e); | ||
528 | let mut ids = vec![]; | 555 | let mut ids = vec![]; |
529 | self.collect_macro_call(e, syntax_ptr.clone(), true, |this, expansion| { | 556 | self.collect_macro_call(e, macro_ptr, true, |this, expansion| { |
530 | ids.push(match expansion { | 557 | ids.push(match expansion { |
531 | Some(it) => this.collect_expr(it), | 558 | Some(it) => this.collect_expr(it), |
532 | None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()), | 559 | None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()), |
@@ -549,7 +576,7 @@ impl ExprCollector<'_> { | |||
549 | 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>( |
550 | &mut self, | 577 | &mut self, |
551 | e: ast::MacroCall, | 578 | e: ast::MacroCall, |
552 | syntax_ptr: AstPtr<ast::Expr>, | 579 | syntax_ptr: AstPtr<ast::MacroCall>, |
553 | is_error_recoverable: bool, | 580 | is_error_recoverable: bool, |
554 | mut collector: F, | 581 | mut collector: F, |
555 | ) { | 582 | ) { |
@@ -561,9 +588,13 @@ impl ExprCollector<'_> { | |||
561 | 588 | ||
562 | let res = match res { | 589 | let res = match res { |
563 | Ok(res) => res, | 590 | Ok(res) => res, |
564 | Err(UnresolvedMacro) => { | 591 | Err(UnresolvedMacro { path }) => { |
565 | self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall( | 592 | self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall( |
566 | UnresolvedMacroCall { file: outer_file, node: syntax_ptr.cast().unwrap() }, | 593 | UnresolvedMacroCall { |
594 | file: outer_file, | ||
595 | node: syntax_ptr.cast().unwrap(), | ||
596 | path, | ||
597 | }, | ||
567 | )); | 598 | )); |
568 | collector(self, None); | 599 | collector(self, None); |
569 | return; | 600 | return; |
@@ -625,7 +656,8 @@ impl ExprCollector<'_> { | |||
625 | return; | 656 | return; |
626 | } | 657 | } |
627 | let pat = self.collect_pat_opt(stmt.pat()); | 658 | let pat = self.collect_pat_opt(stmt.pat()); |
628 | let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); | 659 | let type_ref = |
660 | stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it))); | ||
629 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); | 661 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); |
630 | self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer }); | 662 | self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer }); |
631 | } | 663 | } |
@@ -636,10 +668,14 @@ impl ExprCollector<'_> { | |||
636 | 668 | ||
637 | // Note that macro could be expended to multiple statements | 669 | // Note that macro could be expended to multiple statements |
638 | 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); | ||
639 | let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); | 672 | let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); |
640 | 673 | ||
641 | self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { | 674 | self.collect_macro_call( |
642 | match expansion { | 675 | m, |
676 | macro_ptr, | ||
677 | false, | ||
678 | |this, expansion| match expansion { | ||
643 | Some(expansion) => { | 679 | Some(expansion) => { |
644 | let statements: ast::MacroStmts = expansion; | 680 | let statements: ast::MacroStmts = expansion; |
645 | 681 | ||
@@ -653,8 +689,8 @@ impl ExprCollector<'_> { | |||
653 | let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone()); | 689 | let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone()); |
654 | this.statements_in_scope.push(Statement::Expr(expr)); | 690 | this.statements_in_scope.push(Statement::Expr(expr)); |
655 | } | 691 | } |
656 | } | 692 | }, |
657 | }); | 693 | ); |
658 | } else { | 694 | } else { |
659 | let expr = self.collect_expr_opt(stmt.expr()); | 695 | let expr = self.collect_expr_opt(stmt.expr()); |
660 | self.statements_in_scope.push(Statement::Expr(expr)); | 696 | self.statements_in_scope.push(Statement::Expr(expr)); |
@@ -755,7 +791,7 @@ impl ExprCollector<'_> { | |||
755 | } | 791 | } |
756 | } | 792 | } |
757 | ast::Pat::TupleStructPat(p) => { | 793 | ast::Pat::TupleStructPat(p) => { |
758 | let path = p.path().and_then(|path| self.expander.parse_path(path)); | 794 | let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); |
759 | let (args, ellipsis) = self.collect_tuple_pat(p.fields()); | 795 | let (args, ellipsis) = self.collect_tuple_pat(p.fields()); |
760 | Pat::TupleStruct { path, args, ellipsis } | 796 | Pat::TupleStruct { path, args, ellipsis } |
761 | } | 797 | } |
@@ -765,7 +801,7 @@ impl ExprCollector<'_> { | |||
765 | Pat::Ref { pat, mutability } | 801 | Pat::Ref { pat, mutability } |
766 | } | 802 | } |
767 | ast::Pat::PathPat(p) => { | 803 | ast::Pat::PathPat(p) => { |
768 | let path = p.path().and_then(|path| self.expander.parse_path(path)); | 804 | let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); |
769 | path.map(Pat::Path).unwrap_or(Pat::Missing) | 805 | path.map(Pat::Path).unwrap_or(Pat::Missing) |
770 | } | 806 | } |
771 | ast::Pat::OrPat(p) => { | 807 | ast::Pat::OrPat(p) => { |
@@ -779,7 +815,7 @@ impl ExprCollector<'_> { | |||
779 | } | 815 | } |
780 | ast::Pat::WildcardPat(_) => Pat::Wild, | 816 | ast::Pat::WildcardPat(_) => Pat::Wild, |
781 | ast::Pat::RecordPat(p) => { | 817 | ast::Pat::RecordPat(p) => { |
782 | let path = p.path().and_then(|path| self.expander.parse_path(path)); | 818 | let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); |
783 | let args: Vec<_> = p | 819 | let args: Vec<_> = p |
784 | .record_pat_field_list() | 820 | .record_pat_field_list() |
785 | .expect("every struct should have a field list") | 821 | .expect("every struct should have a field list") |
@@ -841,8 +877,23 @@ impl ExprCollector<'_> { | |||
841 | Pat::Missing | 877 | Pat::Missing |
842 | } | 878 | } |
843 | } | 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 | }, | ||
844 | // FIXME: implement | 895 | // FIXME: implement |
845 | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, | 896 | ast::Pat::RangePat(_) => Pat::Missing, |
846 | }; | 897 | }; |
847 | let ptr = AstPtr::new(&pat); | 898 | let ptr = AstPtr::new(&pat); |
848 | 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 faa133297..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); |
@@ -143,7 +151,7 @@ fn f() { | |||
143 | //^^^^^^^^^^^^^ could not convert tokens | 151 | //^^^^^^^^^^^^^ could not convert tokens |
144 | 152 | ||
145 | env!("OUT_DIR"); | 153 | env!("OUT_DIR"); |
146 | //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix | 154 | //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix |
147 | 155 | ||
148 | compile_error!("compile_error works"); | 156 | compile_error!("compile_error works"); |
149 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works | 157 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works |
@@ -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. |