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.rs105
-rw-r--r--crates/hir_def/src/body/tests.rs12
-rw-r--r--crates/hir_def/src/body/tests/block.rs24
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
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,
@@ -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
39use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; 41use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
40 42
41pub(crate) struct LowerCtx { 43pub 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
45impl LowerCtx { 49impl 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
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);
@@ -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#"
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.