diff options
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r-- | crates/hir_def/src/body/lower.rs | 68 | ||||
-rw-r--r-- | crates/hir_def/src/data.rs | 10 | ||||
-rw-r--r-- | crates/hir_def/src/expr.rs | 4 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 52 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree/lower.rs | 25 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 102 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/macros.rs | 18 | ||||
-rw-r--r-- | crates/hir_def/src/path/lower.rs | 4 | ||||
-rw-r--r-- | crates/hir_def/src/type_ref.rs | 17 |
9 files changed, 196 insertions, 104 deletions
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 19f5065d1..229e81dd4 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -74,6 +74,7 @@ pub(super) fn lower( | |||
74 | _c: Count::new(), | 74 | _c: Count::new(), |
75 | }, | 75 | }, |
76 | expander, | 76 | expander, |
77 | statements_in_scope: Vec::new(), | ||
77 | } | 78 | } |
78 | .collect(params, body) | 79 | .collect(params, body) |
79 | } | 80 | } |
@@ -83,6 +84,7 @@ struct ExprCollector<'a> { | |||
83 | expander: Expander, | 84 | expander: Expander, |
84 | body: Body, | 85 | body: Body, |
85 | source_map: BodySourceMap, | 86 | source_map: BodySourceMap, |
87 | statements_in_scope: Vec<Statement>, | ||
86 | } | 88 | } |
87 | 89 | ||
88 | impl ExprCollector<'_> { | 90 | impl ExprCollector<'_> { |
@@ -533,15 +535,13 @@ impl ExprCollector<'_> { | |||
533 | ids[0] | 535 | ids[0] |
534 | } | 536 | } |
535 | ast::Expr::MacroStmts(e) => { | 537 | ast::Expr::MacroStmts(e) => { |
536 | // FIXME: these statements should be held by some hir containter | 538 | e.statements().for_each(|s| self.collect_stmt(s)); |
537 | for stmt in e.statements() { | 539 | let tail = e |
538 | self.collect_stmt(stmt); | 540 | .expr() |
539 | } | 541 | .map(|e| self.collect_expr(e)) |
540 | if let Some(expr) = e.expr() { | 542 | .unwrap_or_else(|| self.alloc_expr(Expr::Missing, syntax_ptr.clone())); |
541 | self.collect_expr(expr) | 543 | |
542 | } else { | 544 | self.alloc_expr(Expr::MacroStmts { tail }, syntax_ptr) |
543 | self.alloc_expr(Expr::Missing, syntax_ptr) | ||
544 | } | ||
545 | } | 545 | } |
546 | }) | 546 | }) |
547 | } | 547 | } |
@@ -618,58 +618,54 @@ impl ExprCollector<'_> { | |||
618 | } | 618 | } |
619 | } | 619 | } |
620 | 620 | ||
621 | fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> { | 621 | fn collect_stmt(&mut self, s: ast::Stmt) { |
622 | let stmt = match s { | 622 | match s { |
623 | ast::Stmt::LetStmt(stmt) => { | 623 | ast::Stmt::LetStmt(stmt) => { |
624 | self.check_cfg(&stmt)?; | 624 | if self.check_cfg(&stmt).is_none() { |
625 | 625 | return; | |
626 | } | ||
626 | let pat = self.collect_pat_opt(stmt.pat()); | 627 | let pat = self.collect_pat_opt(stmt.pat()); |
627 | let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); | 628 | let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); |
628 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); | 629 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); |
629 | vec![Statement::Let { pat, type_ref, initializer }] | 630 | self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer }); |
630 | } | 631 | } |
631 | ast::Stmt::ExprStmt(stmt) => { | 632 | ast::Stmt::ExprStmt(stmt) => { |
632 | self.check_cfg(&stmt)?; | 633 | if self.check_cfg(&stmt).is_none() { |
634 | return; | ||
635 | } | ||
633 | 636 | ||
634 | // Note that macro could be expended to multiple statements | 637 | // Note that macro could be expended to multiple statements |
635 | if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { | 638 | if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { |
636 | let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); | 639 | let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); |
637 | let mut stmts = vec![]; | ||
638 | 640 | ||
639 | self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { | 641 | self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { |
640 | match expansion { | 642 | match expansion { |
641 | Some(expansion) => { | 643 | Some(expansion) => { |
642 | let statements: ast::MacroStmts = expansion; | 644 | let statements: ast::MacroStmts = expansion; |
643 | 645 | ||
644 | statements.statements().for_each(|stmt| { | 646 | statements.statements().for_each(|stmt| this.collect_stmt(stmt)); |
645 | if let Some(mut r) = this.collect_stmt(stmt) { | ||
646 | stmts.append(&mut r); | ||
647 | } | ||
648 | }); | ||
649 | if let Some(expr) = statements.expr() { | 647 | if let Some(expr) = statements.expr() { |
650 | stmts.push(Statement::Expr(this.collect_expr(expr))); | 648 | let expr = this.collect_expr(expr); |
649 | this.statements_in_scope.push(Statement::Expr(expr)); | ||
651 | } | 650 | } |
652 | } | 651 | } |
653 | None => { | 652 | None => { |
654 | stmts.push(Statement::Expr( | 653 | let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone()); |
655 | this.alloc_expr(Expr::Missing, syntax_ptr.clone()), | 654 | this.statements_in_scope.push(Statement::Expr(expr)); |
656 | )); | ||
657 | } | 655 | } |
658 | } | 656 | } |
659 | }); | 657 | }); |
660 | stmts | ||
661 | } else { | 658 | } else { |
662 | vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))] | 659 | let expr = self.collect_expr_opt(stmt.expr()); |
660 | self.statements_in_scope.push(Statement::Expr(expr)); | ||
663 | } | 661 | } |
664 | } | 662 | } |
665 | ast::Stmt::Item(item) => { | 663 | ast::Stmt::Item(item) => { |
666 | self.check_cfg(&item)?; | 664 | if self.check_cfg(&item).is_none() { |
667 | 665 | return; | |
668 | return None; | 666 | } |
669 | } | 667 | } |
670 | }; | 668 | } |
671 | |||
672 | Some(stmt) | ||
673 | } | 669 | } |
674 | 670 | ||
675 | fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { | 671 | fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { |
@@ -685,10 +681,12 @@ impl ExprCollector<'_> { | |||
685 | let module = if has_def_map { def_map.root() } else { self.expander.module }; | 681 | let module = if has_def_map { def_map.root() } else { self.expander.module }; |
686 | let prev_def_map = mem::replace(&mut self.expander.def_map, def_map); | 682 | let prev_def_map = mem::replace(&mut self.expander.def_map, def_map); |
687 | let prev_local_module = mem::replace(&mut self.expander.module, module); | 683 | let prev_local_module = mem::replace(&mut self.expander.module, module); |
684 | let prev_statements = std::mem::take(&mut self.statements_in_scope); | ||
685 | |||
686 | block.statements().for_each(|s| self.collect_stmt(s)); | ||
688 | 687 | ||
689 | let statements = | ||
690 | block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect(); | ||
691 | let tail = block.tail_expr().map(|e| self.collect_expr(e)); | 688 | let tail = block.tail_expr().map(|e| self.collect_expr(e)); |
689 | let statements = std::mem::replace(&mut self.statements_in_scope, prev_statements); | ||
692 | let syntax_node_ptr = AstPtr::new(&block.into()); | 690 | let syntax_node_ptr = AstPtr::new(&block.into()); |
693 | let expr_id = self.alloc_expr( | 691 | let expr_id = self.alloc_expr( |
694 | Expr::Block { id: block_id, statements, tail, label: None }, | 692 | Expr::Block { id: block_id, statements, tail, label: None }, |
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs index 0be868ba2..214bcc648 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs | |||
@@ -10,7 +10,7 @@ use crate::{ | |||
10 | body::Expander, | 10 | body::Expander, |
11 | db::DefDatabase, | 11 | db::DefDatabase, |
12 | item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param}, | 12 | item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param}, |
13 | type_ref::{TypeBound, TypeRef}, | 13 | type_ref::{TraitRef, TypeBound, TypeRef}, |
14 | visibility::RawVisibility, | 14 | visibility::RawVisibility, |
15 | AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, | 15 | AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, |
16 | Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | 16 | Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, |
@@ -156,8 +156,8 @@ impl TraitData { | |||
156 | 156 | ||
157 | #[derive(Debug, Clone, PartialEq, Eq)] | 157 | #[derive(Debug, Clone, PartialEq, Eq)] |
158 | pub struct ImplData { | 158 | pub struct ImplData { |
159 | pub target_trait: Option<TypeRef>, | 159 | pub target_trait: Option<TraitRef>, |
160 | pub target_type: TypeRef, | 160 | pub self_ty: TypeRef, |
161 | pub items: Vec<AssocItemId>, | 161 | pub items: Vec<AssocItemId>, |
162 | pub is_negative: bool, | 162 | pub is_negative: bool, |
163 | } | 163 | } |
@@ -170,7 +170,7 @@ impl ImplData { | |||
170 | let item_tree = impl_loc.id.item_tree(db); | 170 | let item_tree = impl_loc.id.item_tree(db); |
171 | let impl_def = &item_tree[impl_loc.id.value]; | 171 | let impl_def = &item_tree[impl_loc.id.value]; |
172 | let target_trait = impl_def.target_trait.map(|id| item_tree[id].clone()); | 172 | let target_trait = impl_def.target_trait.map(|id| item_tree[id].clone()); |
173 | let target_type = item_tree[impl_def.target_type].clone(); | 173 | let self_ty = item_tree[impl_def.self_ty].clone(); |
174 | let is_negative = impl_def.is_negative; | 174 | let is_negative = impl_def.is_negative; |
175 | let module_id = impl_loc.container; | 175 | let module_id = impl_loc.container; |
176 | let container = AssocContainerId::ImplId(id); | 176 | let container = AssocContainerId::ImplId(id); |
@@ -187,7 +187,7 @@ impl ImplData { | |||
187 | ); | 187 | ); |
188 | let items = items.into_iter().map(|(_, item)| item).collect(); | 188 | let items = items.into_iter().map(|(_, item)| item).collect(); |
189 | 189 | ||
190 | Arc::new(ImplData { target_trait, target_type, items, is_negative }) | 190 | Arc::new(ImplData { target_trait, self_ty, items, is_negative }) |
191 | } | 191 | } |
192 | } | 192 | } |
193 | 193 | ||
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs index 24be93773..6c7376fad 100644 --- a/crates/hir_def/src/expr.rs +++ b/crates/hir_def/src/expr.rs | |||
@@ -171,6 +171,9 @@ pub enum Expr { | |||
171 | Unsafe { | 171 | Unsafe { |
172 | body: ExprId, | 172 | body: ExprId, |
173 | }, | 173 | }, |
174 | MacroStmts { | ||
175 | tail: ExprId, | ||
176 | }, | ||
174 | Array(Array), | 177 | Array(Array), |
175 | Literal(Literal), | 178 | Literal(Literal), |
176 | } | 179 | } |
@@ -357,6 +360,7 @@ impl Expr { | |||
357 | f(*repeat) | 360 | f(*repeat) |
358 | } | 361 | } |
359 | }, | 362 | }, |
363 | Expr::MacroStmts { tail } => f(*tail), | ||
360 | Expr::Literal(_) => {} | 364 | Expr::Literal(_) => {} |
361 | } | 365 | } |
362 | } | 366 | } |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index ae2475b4e..5449bbf5d 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -31,7 +31,7 @@ use crate::{ | |||
31 | db::DefDatabase, | 31 | db::DefDatabase, |
32 | generics::GenericParams, | 32 | generics::GenericParams, |
33 | path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, | 33 | path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, |
34 | type_ref::{Mutability, TypeBound, TypeRef}, | 34 | type_ref::{Mutability, TraitRef, TypeBound, TypeRef}, |
35 | visibility::RawVisibility, | 35 | visibility::RawVisibility, |
36 | }; | 36 | }; |
37 | 37 | ||
@@ -110,15 +110,6 @@ 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 | }, | ||
118 | ast::Item(item) => { | ||
119 | // Macros can expand to stmt and other item, and we add it as top level item | ||
120 | ctx.lower_single_item(item) | ||
121 | }, | ||
122 | _ => { | 113 | _ => { |
123 | panic!("cannot create item tree from {:?} {}", syntax, syntax); | 114 | panic!("cannot create item tree from {:?} {}", syntax, syntax); |
124 | }, | 115 | }, |
@@ -156,6 +147,7 @@ impl ItemTree { | |||
156 | vis, | 147 | vis, |
157 | generics, | 148 | generics, |
158 | type_refs, | 149 | type_refs, |
150 | trait_refs, | ||
159 | inner_items, | 151 | inner_items, |
160 | } = &mut **data; | 152 | } = &mut **data; |
161 | 153 | ||
@@ -182,6 +174,7 @@ impl ItemTree { | |||
182 | generics.arena.shrink_to_fit(); | 174 | generics.arena.shrink_to_fit(); |
183 | type_refs.arena.shrink_to_fit(); | 175 | type_refs.arena.shrink_to_fit(); |
184 | type_refs.map.shrink_to_fit(); | 176 | type_refs.map.shrink_to_fit(); |
177 | trait_refs.map.shrink_to_fit(); | ||
185 | 178 | ||
186 | inner_items.shrink_to_fit(); | 179 | inner_items.shrink_to_fit(); |
187 | } | 180 | } |
@@ -304,6 +297,32 @@ impl TypeRefStorage { | |||
304 | } | 297 | } |
305 | } | 298 | } |
306 | 299 | ||
300 | /// `TraitRef` interner. | ||
301 | #[derive(Default, Debug, Eq, PartialEq)] | ||
302 | struct TraitRefStorage { | ||
303 | arena: Arena<Arc<TraitRef>>, | ||
304 | map: FxHashMap<Arc<TraitRef>, Idx<Arc<TraitRef>>>, | ||
305 | } | ||
306 | |||
307 | impl TraitRefStorage { | ||
308 | // Note: We lie about the `Idx<TraitRef>` to hide the interner details. | ||
309 | |||
310 | fn intern(&mut self, ty: TraitRef) -> Idx<TraitRef> { | ||
311 | if let Some(id) = self.map.get(&ty) { | ||
312 | return Idx::from_raw(id.into_raw()); | ||
313 | } | ||
314 | |||
315 | let ty = Arc::new(ty); | ||
316 | let idx = self.arena.alloc(ty.clone()); | ||
317 | self.map.insert(ty, idx); | ||
318 | Idx::from_raw(idx.into_raw()) | ||
319 | } | ||
320 | |||
321 | fn lookup(&self, id: Idx<TraitRef>) -> &TraitRef { | ||
322 | &self.arena[Idx::from_raw(id.into_raw())] | ||
323 | } | ||
324 | } | ||
325 | |||
307 | #[derive(Default, Debug, Eq, PartialEq)] | 326 | #[derive(Default, Debug, Eq, PartialEq)] |
308 | struct ItemTreeData { | 327 | struct ItemTreeData { |
309 | imports: Arena<Import>, | 328 | imports: Arena<Import>, |
@@ -328,6 +347,7 @@ struct ItemTreeData { | |||
328 | vis: ItemVisibilities, | 347 | vis: ItemVisibilities, |
329 | generics: GenericParamsStorage, | 348 | generics: GenericParamsStorage, |
330 | type_refs: TypeRefStorage, | 349 | type_refs: TypeRefStorage, |
350 | trait_refs: TraitRefStorage, | ||
331 | 351 | ||
332 | inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, | 352 | inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, |
333 | } | 353 | } |
@@ -565,6 +585,14 @@ impl Index<Idx<TypeRef>> for ItemTree { | |||
565 | } | 585 | } |
566 | } | 586 | } |
567 | 587 | ||
588 | impl Index<Idx<TraitRef>> for ItemTree { | ||
589 | type Output = TraitRef; | ||
590 | |||
591 | fn index(&self, id: Idx<TraitRef>) -> &Self::Output { | ||
592 | self.data().trait_refs.lookup(id) | ||
593 | } | ||
594 | } | ||
595 | |||
568 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { | 596 | impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { |
569 | type Output = N; | 597 | type Output = N; |
570 | fn index(&self, id: FileItemTreeId<N>) -> &N { | 598 | fn index(&self, id: FileItemTreeId<N>) -> &N { |
@@ -701,8 +729,8 @@ pub struct Trait { | |||
701 | #[derive(Debug, Clone, Eq, PartialEq)] | 729 | #[derive(Debug, Clone, Eq, PartialEq)] |
702 | pub struct Impl { | 730 | pub struct Impl { |
703 | pub generic_params: GenericParamsId, | 731 | pub generic_params: GenericParamsId, |
704 | pub target_trait: Option<Idx<TypeRef>>, | 732 | pub target_trait: Option<Idx<TraitRef>>, |
705 | pub target_type: Idx<TypeRef>, | 733 | pub self_ty: Idx<TypeRef>, |
706 | pub is_negative: bool, | 734 | pub is_negative: bool, |
707 | pub items: Box<[AssocItem]>, | 735 | pub items: Box<[AssocItem]>, |
708 | pub ast_id: FileAstId<ast::Impl>, | 736 | pub ast_id: FileAstId<ast::Impl>, |
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index d3fe1ce1e..8d3862811 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -11,7 +11,7 @@ use syntax::{ | |||
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | generics::{GenericParams, TypeParamData, TypeParamProvenance}, | 13 | generics::{GenericParams, TypeParamData, TypeParamProvenance}, |
14 | type_ref::LifetimeRef, | 14 | type_ref::{LifetimeRef, TraitRef}, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | use super::*; | 17 | use super::*; |
@@ -87,14 +87,6 @@ impl Ctx { | |||
87 | self.tree | 87 | self.tree |
88 | } | 88 | } |
89 | 89 | ||
90 | pub(super) fn lower_single_item(mut self, item: ast::Item) -> ItemTree { | ||
91 | self.tree.top_level = self | ||
92 | .lower_mod_item(&item, false) | ||
93 | .map(|item| item.0) | ||
94 | .unwrap_or_else(|| Default::default()); | ||
95 | self.tree | ||
96 | } | ||
97 | |||
98 | pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree { | 90 | pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree { |
99 | self.collect_inner_items(within); | 91 | self.collect_inner_items(within); |
100 | self.tree | 92 | self.tree |
@@ -544,8 +536,11 @@ impl Ctx { | |||
544 | fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> { | 536 | fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> { |
545 | let generic_params = | 537 | let generic_params = |
546 | self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); | 538 | self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); |
547 | let target_trait = impl_def.trait_().map(|tr| self.lower_type_ref(&tr)); | 539 | // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl |
548 | let target_type = self.lower_type_ref(&impl_def.self_ty()?); | 540 | // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only |
541 | // equals itself. | ||
542 | let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr)); | ||
543 | let self_ty = self.lower_type_ref(&impl_def.self_ty()?); | ||
549 | let is_negative = impl_def.excl_token().is_some(); | 544 | let is_negative = impl_def.excl_token().is_some(); |
550 | 545 | ||
551 | // We cannot use `assoc_items()` here as that does not include macro calls. | 546 | // We cannot use `assoc_items()` here as that does not include macro calls. |
@@ -562,7 +557,7 @@ impl Ctx { | |||
562 | }) | 557 | }) |
563 | .collect(); | 558 | .collect(); |
564 | let ast_id = self.source_ast_id_map.ast_id(impl_def); | 559 | let ast_id = self.source_ast_id_map.ast_id(impl_def); |
565 | let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }; | 560 | let res = Impl { generic_params, target_trait, self_ty, is_negative, items, ast_id }; |
566 | Some(id(self.data().impls.alloc(res))) | 561 | Some(id(self.data().impls.alloc(res))) |
567 | } | 562 | } |
568 | 563 | ||
@@ -748,10 +743,16 @@ impl Ctx { | |||
748 | self.data().vis.alloc(vis) | 743 | self.data().vis.alloc(vis) |
749 | } | 744 | } |
750 | 745 | ||
746 | fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Idx<TraitRef>> { | ||
747 | let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?; | ||
748 | Some(self.data().trait_refs.intern(trait_ref)) | ||
749 | } | ||
750 | |||
751 | fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Idx<TypeRef> { | 751 | fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Idx<TypeRef> { |
752 | let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone()); | 752 | let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone()); |
753 | self.data().type_refs.intern(tyref) | 753 | self.data().type_refs.intern(tyref) |
754 | } | 754 | } |
755 | |||
755 | fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Idx<TypeRef> { | 756 | fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Idx<TypeRef> { |
756 | match type_ref.map(|ty| self.lower_type_ref(&ty)) { | 757 | match type_ref.map(|ty| self.lower_type_ref(&ty)) { |
757 | Some(it) => it, | 758 | Some(it) => it, |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index d8fabe49b..d58135ec9 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -25,8 +25,8 @@ use crate::{ | |||
25 | derive_macro_as_call_id, | 25 | derive_macro_as_call_id, |
26 | item_scope::{ImportType, PerNsGlobImports}, | 26 | item_scope::{ImportType, PerNsGlobImports}, |
27 | item_tree::{ | 27 | item_tree::{ |
28 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroRules, Mod, ModItem, ModKind, | 28 | self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroDef, MacroRules, Mod, ModItem, |
29 | StructDefKind, | 29 | ModKind, StructDefKind, |
30 | }, | 30 | }, |
31 | macro_call_as_call_id, | 31 | macro_call_as_call_id, |
32 | nameres::{ | 32 | nameres::{ |
@@ -395,7 +395,7 @@ impl DefCollector<'_> { | |||
395 | /// macro_rules! foo { () => {} } | 395 | /// macro_rules! foo { () => {} } |
396 | /// use foo as bar; | 396 | /// use foo as bar; |
397 | /// ``` | 397 | /// ``` |
398 | fn define_macro( | 398 | fn define_macro_rules( |
399 | &mut self, | 399 | &mut self, |
400 | module_id: LocalModuleId, | 400 | module_id: LocalModuleId, |
401 | name: Name, | 401 | name: Name, |
@@ -430,6 +430,21 @@ impl DefCollector<'_> { | |||
430 | self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); | 430 | self.def_map.modules[module_id].scope.define_legacy_macro(name, mac); |
431 | } | 431 | } |
432 | 432 | ||
433 | /// Define a macro 2.0 macro | ||
434 | /// | ||
435 | /// The scoped of macro 2.0 macro is equal to normal function | ||
436 | fn define_macro_def( | ||
437 | &mut self, | ||
438 | module_id: LocalModuleId, | ||
439 | name: Name, | ||
440 | macro_: MacroDefId, | ||
441 | vis: &RawVisibility, | ||
442 | ) { | ||
443 | let vis = | ||
444 | self.def_map.resolve_visibility(self.db, module_id, vis).unwrap_or(Visibility::Public); | ||
445 | self.update(module_id, &[(Some(name), PerNs::macros(macro_, vis))], vis, ImportType::Named); | ||
446 | } | ||
447 | |||
433 | /// Define a proc macro | 448 | /// Define a proc macro |
434 | /// | 449 | /// |
435 | /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped. | 450 | /// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped. |
@@ -1067,40 +1082,7 @@ impl ModCollector<'_, '_> { | |||
1067 | } | 1082 | } |
1068 | ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]), | 1083 | ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]), |
1069 | ModItem::MacroRules(id) => self.collect_macro_rules(id), | 1084 | ModItem::MacroRules(id) => self.collect_macro_rules(id), |
1070 | ModItem::MacroDef(id) => { | 1085 | ModItem::MacroDef(id) => self.collect_macro_def(id), |
1071 | let mac = &self.item_tree[id]; | ||
1072 | let ast_id = InFile::new(self.file_id, mac.ast_id.upcast()); | ||
1073 | |||
1074 | // "Macro 2.0" is not currently supported by rust-analyzer, but libcore uses it | ||
1075 | // to define builtin macros, so we support at least that part. | ||
1076 | let attrs = self.item_tree.attrs( | ||
1077 | self.def_collector.db, | ||
1078 | krate, | ||
1079 | ModItem::from(id).into(), | ||
1080 | ); | ||
1081 | if attrs.by_key("rustc_builtin_macro").exists() { | ||
1082 | let krate = self.def_collector.def_map.krate; | ||
1083 | let macro_id = find_builtin_macro(&mac.name, krate, ast_id) | ||
1084 | .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); | ||
1085 | if let Some(macro_id) = macro_id { | ||
1086 | let vis = self | ||
1087 | .def_collector | ||
1088 | .def_map | ||
1089 | .resolve_visibility( | ||
1090 | self.def_collector.db, | ||
1091 | self.module_id, | ||
1092 | &self.item_tree[mac.visibility], | ||
1093 | ) | ||
1094 | .unwrap_or(Visibility::Public); | ||
1095 | self.def_collector.update( | ||
1096 | self.module_id, | ||
1097 | &[(Some(mac.name.clone()), PerNs::macros(macro_id, vis))], | ||
1098 | vis, | ||
1099 | ImportType::Named, | ||
1100 | ); | ||
1101 | } | ||
1102 | } | ||
1103 | } | ||
1104 | ModItem::Impl(imp) => { | 1086 | ModItem::Impl(imp) => { |
1105 | let module = self.def_collector.def_map.module_id(self.module_id); | 1087 | let module = self.def_collector.def_map.module_id(self.module_id); |
1106 | let impl_id = | 1088 | let impl_id = |
@@ -1420,7 +1402,7 @@ impl ModCollector<'_, '_> { | |||
1420 | if attrs.by_key("rustc_builtin_macro").exists() { | 1402 | if attrs.by_key("rustc_builtin_macro").exists() { |
1421 | let krate = self.def_collector.def_map.krate; | 1403 | let krate = self.def_collector.def_map.krate; |
1422 | if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) { | 1404 | if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) { |
1423 | self.def_collector.define_macro( | 1405 | self.def_collector.define_macro_rules( |
1424 | self.module_id, | 1406 | self.module_id, |
1425 | mac.name.clone(), | 1407 | mac.name.clone(), |
1426 | macro_id, | 1408 | macro_id, |
@@ -1436,7 +1418,49 @@ impl ModCollector<'_, '_> { | |||
1436 | kind: MacroDefKind::Declarative(ast_id), | 1418 | kind: MacroDefKind::Declarative(ast_id), |
1437 | local_inner: is_local_inner, | 1419 | local_inner: is_local_inner, |
1438 | }; | 1420 | }; |
1439 | self.def_collector.define_macro(self.module_id, mac.name.clone(), macro_id, is_export); | 1421 | self.def_collector.define_macro_rules( |
1422 | self.module_id, | ||
1423 | mac.name.clone(), | ||
1424 | macro_id, | ||
1425 | is_export, | ||
1426 | ); | ||
1427 | } | ||
1428 | |||
1429 | fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>) { | ||
1430 | let krate = self.def_collector.def_map.krate; | ||
1431 | let mac = &self.item_tree[id]; | ||
1432 | let ast_id = InFile::new(self.file_id, mac.ast_id.upcast()); | ||
1433 | |||
1434 | // Case 1: bulitin macros | ||
1435 | let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into()); | ||
1436 | if attrs.by_key("rustc_builtin_macro").exists() { | ||
1437 | let macro_id = find_builtin_macro(&mac.name, krate, ast_id) | ||
1438 | .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); | ||
1439 | |||
1440 | if let Some(macro_id) = macro_id { | ||
1441 | self.def_collector.define_macro_def( | ||
1442 | self.module_id, | ||
1443 | mac.name.clone(), | ||
1444 | macro_id, | ||
1445 | &self.item_tree[mac.visibility], | ||
1446 | ); | ||
1447 | } | ||
1448 | return; | ||
1449 | } | ||
1450 | |||
1451 | // Case 2: normal `macro` | ||
1452 | let macro_id = MacroDefId { | ||
1453 | krate: self.def_collector.def_map.krate, | ||
1454 | kind: MacroDefKind::Declarative(ast_id), | ||
1455 | local_inner: false, | ||
1456 | }; | ||
1457 | |||
1458 | self.def_collector.define_macro_def( | ||
1459 | self.module_id, | ||
1460 | mac.name.clone(), | ||
1461 | macro_id, | ||
1462 | &self.item_tree[mac.visibility], | ||
1463 | ); | ||
1440 | } | 1464 | } |
1441 | 1465 | ||
1442 | fn collect_macro_call(&mut self, mac: &MacroCall) { | 1466 | fn collect_macro_call(&mut self, mac: &MacroCall) { |
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs index 6d3cb8d7a..c37f915ab 100644 --- a/crates/hir_def/src/nameres/tests/macros.rs +++ b/crates/hir_def/src/nameres/tests/macros.rs | |||
@@ -837,3 +837,21 @@ fn collects_derive_helpers() { | |||
837 | _ => unreachable!(), | 837 | _ => unreachable!(), |
838 | } | 838 | } |
839 | } | 839 | } |
840 | |||
841 | #[test] | ||
842 | fn resolve_macro_def() { | ||
843 | check( | ||
844 | r#" | ||
845 | //- /lib.rs | ||
846 | pub macro structs($($i:ident),*) { | ||
847 | $(struct $i { field: u32 } )* | ||
848 | } | ||
849 | structs!(Foo); | ||
850 | "#, | ||
851 | expect![[r#" | ||
852 | crate | ||
853 | Foo: t | ||
854 | structs: m | ||
855 | "#]], | ||
856 | ); | ||
857 | } | ||
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index 505493a74..4de951fd3 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs | |||
@@ -74,6 +74,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
74 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo | 74 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo |
75 | Some(trait_ref) => { | 75 | Some(trait_ref) => { |
76 | let path = Path::from_src(trait_ref.path()?, hygiene)?; | 76 | let path = Path::from_src(trait_ref.path()?, hygiene)?; |
77 | let num_segments = path.mod_path.segments.len(); | ||
77 | kind = path.mod_path.kind; | 78 | kind = path.mod_path.kind; |
78 | 79 | ||
79 | let mut prefix_segments = path.mod_path.segments; | 80 | let mut prefix_segments = path.mod_path.segments; |
@@ -85,7 +86,8 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
85 | generic_args.extend(prefix_args); | 86 | generic_args.extend(prefix_args); |
86 | 87 | ||
87 | // Insert the type reference (T in the above example) as Self parameter for the trait | 88 | // Insert the type reference (T in the above example) as Self parameter for the trait |
88 | let last_segment = generic_args.last_mut()?; | 89 | let last_segment = |
90 | generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?; | ||
89 | if last_segment.is_none() { | 91 | if last_segment.is_none() { |
90 | *last_segment = Some(Arc::new(GenericArgs::empty())); | 92 | *last_segment = Some(Arc::new(GenericArgs::empty())); |
91 | }; | 93 | }; |
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs index 049b2e462..4c24aae94 100644 --- a/crates/hir_def/src/type_ref.rs +++ b/crates/hir_def/src/type_ref.rs | |||
@@ -51,6 +51,23 @@ impl Rawness { | |||
51 | } | 51 | } |
52 | } | 52 | } |
53 | 53 | ||
54 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||
55 | pub struct TraitRef { | ||
56 | pub path: Path, | ||
57 | } | ||
58 | |||
59 | impl TraitRef { | ||
60 | /// Converts an `ast::PathType` to a `hir::TraitRef`. | ||
61 | pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Option<Self> { | ||
62 | // FIXME: Use `Path::from_src` | ||
63 | match node { | ||
64 | ast::Type::PathType(path) => { | ||
65 | path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path }) | ||
66 | } | ||
67 | _ => None, | ||
68 | } | ||
69 | } | ||
70 | } | ||
54 | /// Compare ty::Ty | 71 | /// Compare ty::Ty |
55 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | 72 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] |
56 | pub enum TypeRef { | 73 | pub enum TypeRef { |