aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r--crates/hir_def/src/body/lower.rs68
-rw-r--r--crates/hir_def/src/data.rs10
-rw-r--r--crates/hir_def/src/expr.rs4
-rw-r--r--crates/hir_def/src/item_tree.rs52
-rw-r--r--crates/hir_def/src/item_tree/lower.rs25
-rw-r--r--crates/hir_def/src/nameres/collector.rs102
-rw-r--r--crates/hir_def/src/nameres/tests/macros.rs18
-rw-r--r--crates/hir_def/src/path/lower.rs4
-rw-r--r--crates/hir_def/src/type_ref.rs17
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
88impl ExprCollector<'_> { 90impl 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)]
158pub struct ImplData { 158pub 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)]
302struct TraitRefStorage {
303 arena: Arena<Arc<TraitRef>>,
304 map: FxHashMap<Arc<TraitRef>, Idx<Arc<TraitRef>>>,
305}
306
307impl 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)]
308struct ItemTreeData { 327struct 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
588impl 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
568impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { 596impl<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)]
702pub struct Impl { 730pub 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
12use crate::{ 12use crate::{
13 generics::{GenericParams, TypeParamData, TypeParamProvenance}, 13 generics::{GenericParams, TypeParamData, TypeParamProvenance},
14 type_ref::LifetimeRef, 14 type_ref::{LifetimeRef, TraitRef},
15}; 15};
16 16
17use super::*; 17use 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]
842fn resolve_macro_def() {
843 check(
844 r#"
845//- /lib.rs
846pub macro structs($($i:ident),*) {
847 $(struct $i { field: u32 } )*
848}
849structs!(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)]
55pub struct TraitRef {
56 pub path: Path,
57}
58
59impl 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)]
56pub enum TypeRef { 73pub enum TypeRef {