aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/adt.rs10
-rw-r--r--crates/hir_def/src/body/lower.rs105
-rw-r--r--crates/hir_def/src/data.rs22
-rw-r--r--crates/hir_def/src/diagnostics.rs2
-rw-r--r--crates/hir_def/src/item_tree.rs24
-rw-r--r--crates/hir_def/src/item_tree/lower.rs35
-rw-r--r--crates/hir_def/src/nameres/collector.rs33
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs45
-rw-r--r--crates/hir_def/src/path.rs11
9 files changed, 209 insertions, 78 deletions
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs
index efbde17d8..1b9bb8235 100644
--- a/crates/hir_def/src/adt.rs
+++ b/crates/hir_def/src/adt.rs
@@ -31,12 +31,14 @@ pub struct StructData {
31 pub name: Name, 31 pub name: Name,
32 pub variant_data: Arc<VariantData>, 32 pub variant_data: Arc<VariantData>,
33 pub repr: Option<ReprKind>, 33 pub repr: Option<ReprKind>,
34 pub visibility: RawVisibility,
34} 35}
35 36
36#[derive(Debug, Clone, PartialEq, Eq)] 37#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct EnumData { 38pub struct EnumData {
38 pub name: Name, 39 pub name: Name,
39 pub variants: Arena<EnumVariantData>, 40 pub variants: Arena<EnumVariantData>,
41 pub visibility: RawVisibility,
40} 42}
41 43
42#[derive(Debug, Clone, PartialEq, Eq)] 44#[derive(Debug, Clone, PartialEq, Eq)]
@@ -102,6 +104,7 @@ impl StructData {
102 name: strukt.name.clone(), 104 name: strukt.name.clone(),
103 variant_data: Arc::new(variant_data), 105 variant_data: Arc::new(variant_data),
104 repr, 106 repr,
107 visibility: item_tree[strukt.visibility].clone(),
105 }) 108 })
106 } 109 }
107 pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> { 110 pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
@@ -118,6 +121,7 @@ impl StructData {
118 name: union.name.clone(), 121 name: union.name.clone(),
119 variant_data: Arc::new(variant_data), 122 variant_data: Arc::new(variant_data),
120 repr, 123 repr,
124 visibility: item_tree[union.visibility].clone(),
121 }) 125 })
122 } 126 }
123} 127}
@@ -150,7 +154,11 @@ impl EnumData {
150 } 154 }
151 } 155 }
152 156
153 Arc::new(EnumData { name: enum_.name.clone(), variants }) 157 Arc::new(EnumData {
158 name: enum_.name.clone(),
159 variants,
160 visibility: item_tree[enum_.visibility].clone(),
161 })
154 } 162 }
155 163
156 pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> { 164 pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 8934ae6c9..7052058f2 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -519,7 +519,7 @@ impl ExprCollector<'_> {
519 } 519 }
520 ast::Expr::MacroCall(e) => { 520 ast::Expr::MacroCall(e) => {
521 let mut ids = vec![]; 521 let mut ids = vec![];
522 self.collect_macro_call(e, syntax_ptr.clone(), |this, expansion| { 522 self.collect_macro_call(e, syntax_ptr.clone(), true, |this, expansion| {
523 ids.push(match expansion { 523 ids.push(match expansion {
524 Some(it) => this.collect_expr(it), 524 Some(it) => this.collect_expr(it),
525 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()), 525 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
@@ -527,6 +527,17 @@ impl ExprCollector<'_> {
527 }); 527 });
528 ids[0] 528 ids[0]
529 } 529 }
530 ast::Expr::MacroStmts(e) => {
531 // FIXME: these statements should be held by some hir containter
532 for stmt in e.statements() {
533 self.collect_stmt(stmt);
534 }
535 if let Some(expr) = e.expr() {
536 self.collect_expr(expr)
537 } else {
538 self.alloc_expr(Expr::Missing, syntax_ptr)
539 }
540 }
530 } 541 }
531 } 542 }
532 543
@@ -534,6 +545,7 @@ impl ExprCollector<'_> {
534 &mut self, 545 &mut self,
535 e: ast::MacroCall, 546 e: ast::MacroCall,
536 syntax_ptr: AstPtr<ast::Expr>, 547 syntax_ptr: AstPtr<ast::Expr>,
548 is_error_recoverable: bool,
537 mut collector: F, 549 mut collector: F,
538 ) { 550 ) {
539 // File containing the macro call. Expansion errors will be attached here. 551 // File containing the macro call. Expansion errors will be attached here.
@@ -567,7 +579,7 @@ impl ExprCollector<'_> {
567 Some((mark, expansion)) => { 579 Some((mark, expansion)) => {
568 // FIXME: Statements are too complicated to recover from error for now. 580 // FIXME: Statements are too complicated to recover from error for now.
569 // It is because we don't have any hygiene for local variable expansion right now. 581 // It is because we don't have any hygiene for local variable expansion right now.
570 if T::can_cast(syntax::SyntaxKind::MACRO_STMTS) && res.err.is_some() { 582 if !is_error_recoverable && res.err.is_some() {
571 self.expander.exit(self.db, mark); 583 self.expander.exit(self.db, mark);
572 collector(self, None); 584 collector(self, None);
573 } else { 585 } else {
@@ -591,56 +603,55 @@ impl ExprCollector<'_> {
591 } 603 }
592 604
593 fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> { 605 fn collect_stmt(&mut self, s: ast::Stmt) -> Option<Vec<Statement>> {
594 let stmt = 606 let stmt = match s {
595 match s { 607 ast::Stmt::LetStmt(stmt) => {
596 ast::Stmt::LetStmt(stmt) => { 608 self.check_cfg(&stmt)?;
597 self.check_cfg(&stmt)?; 609
598 610 let pat = self.collect_pat_opt(stmt.pat());
599 let pat = self.collect_pat_opt(stmt.pat()); 611 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
600 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 612 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
601 let initializer = stmt.initializer().map(|e| self.collect_expr(e)); 613 vec![Statement::Let { pat, type_ref, initializer }]
602 vec![Statement::Let { pat, type_ref, initializer }] 614 }
603 } 615 ast::Stmt::ExprStmt(stmt) => {
604 ast::Stmt::ExprStmt(stmt) => { 616 self.check_cfg(&stmt)?;
605 self.check_cfg(&stmt)?; 617
606 618 // Note that macro could be expended to multiple statements
607 // Note that macro could be expended to multiple statements 619 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
608 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { 620 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
609 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); 621 let mut stmts = vec![];
610 let mut stmts = vec![]; 622
611 623 self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| {
612 self.collect_macro_call(m, syntax_ptr.clone(), |this, expansion| { 624 match expansion {
613 match expansion { 625 Some(expansion) => {
614 Some(expansion) => { 626 let statements: ast::MacroStmts = expansion;
615 let statements: ast::MacroStmts = expansion; 627
616 628 statements.statements().for_each(|stmt| {
617 statements.statements().for_each(|stmt| { 629 if let Some(mut r) = this.collect_stmt(stmt) {
618 if let Some(mut r) = this.collect_stmt(stmt) { 630 stmts.append(&mut r);
619 stmts.append(&mut r);
620 }
621 });
622 if let Some(expr) = statements.expr() {
623 stmts.push(Statement::Expr(this.collect_expr(expr)));
624 } 631 }
625 } 632 });
626 None => { 633 if let Some(expr) = statements.expr() {
627 stmts.push(Statement::Expr( 634 stmts.push(Statement::Expr(this.collect_expr(expr)));
628 this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
629 ));
630 } 635 }
631 } 636 }
632 }); 637 None => {
633 stmts 638 stmts.push(Statement::Expr(
634 } else { 639 this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
635 vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))] 640 ));
636 } 641 }
642 }
643 });
644 stmts
645 } else {
646 vec![Statement::Expr(self.collect_expr_opt(stmt.expr()))]
637 } 647 }
638 ast::Stmt::Item(item) => { 648 }
639 self.check_cfg(&item)?; 649 ast::Stmt::Item(item) => {
650 self.check_cfg(&item)?;
640 651
641 return None; 652 return None;
642 } 653 }
643 }; 654 };
644 655
645 Some(stmt) 656 Some(stmt)
646 } 657 }
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index aea53d527..74a2194e5 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -9,7 +9,7 @@ use crate::{
9 attr::Attrs, 9 attr::Attrs,
10 body::Expander, 10 body::Expander,
11 db::DefDatabase, 11 db::DefDatabase,
12 item_tree::{AssocItem, ItemTreeId, ModItem}, 12 item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem},
13 type_ref::{TypeBound, TypeRef}, 13 type_ref::{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,
@@ -26,9 +26,9 @@ pub struct FunctionData {
26 /// can be called as a method. 26 /// can be called as a method.
27 pub has_self_param: bool, 27 pub has_self_param: bool,
28 pub has_body: bool, 28 pub has_body: bool,
29 pub is_unsafe: bool, 29 pub qualifier: FunctionQualifier,
30 pub is_in_extern_block: bool,
30 pub is_varargs: bool, 31 pub is_varargs: bool,
31 pub is_extern: bool,
32 pub visibility: RawVisibility, 32 pub visibility: RawVisibility,
33} 33}
34 34
@@ -46,9 +46,9 @@ impl FunctionData {
46 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), 46 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
47 has_self_param: func.has_self_param, 47 has_self_param: func.has_self_param,
48 has_body: func.has_body, 48 has_body: func.has_body,
49 is_unsafe: func.is_unsafe, 49 qualifier: func.qualifier.clone(),
50 is_in_extern_block: func.is_in_extern_block,
50 is_varargs: func.is_varargs, 51 is_varargs: func.is_varargs,
51 is_extern: func.is_extern,
52 visibility: item_tree[func.visibility].clone(), 52 visibility: item_tree[func.visibility].clone(),
53 }) 53 })
54 } 54 }
@@ -87,7 +87,10 @@ impl TypeAliasData {
87pub struct TraitData { 87pub struct TraitData {
88 pub name: Name, 88 pub name: Name,
89 pub items: Vec<(Name, AssocItemId)>, 89 pub items: Vec<(Name, AssocItemId)>,
90 pub auto: bool, 90 pub is_auto: bool,
91 pub is_unsafe: bool,
92 pub visibility: RawVisibility,
93 pub bounds: Box<[TypeBound]>,
91} 94}
92 95
93impl TraitData { 96impl TraitData {
@@ -96,10 +99,13 @@ impl TraitData {
96 let item_tree = db.item_tree(tr_loc.id.file_id); 99 let item_tree = db.item_tree(tr_loc.id.file_id);
97 let tr_def = &item_tree[tr_loc.id.value]; 100 let tr_def = &item_tree[tr_loc.id.value];
98 let name = tr_def.name.clone(); 101 let name = tr_def.name.clone();
99 let auto = tr_def.auto; 102 let is_auto = tr_def.is_auto;
103 let is_unsafe = tr_def.is_unsafe;
100 let module_id = tr_loc.container; 104 let module_id = tr_loc.container;
101 let container = AssocContainerId::TraitId(tr); 105 let container = AssocContainerId::TraitId(tr);
102 let mut expander = Expander::new(db, tr_loc.id.file_id, module_id); 106 let mut expander = Expander::new(db, tr_loc.id.file_id, module_id);
107 let visibility = item_tree[tr_def.visibility].clone();
108 let bounds = tr_def.bounds.clone();
103 109
104 let items = collect_items( 110 let items = collect_items(
105 db, 111 db,
@@ -111,7 +117,7 @@ impl TraitData {
111 100, 117 100,
112 ); 118 );
113 119
114 Arc::new(TraitData { name, items, auto }) 120 Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility, bounds })
115 } 121 }
116 122
117 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { 123 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs
index ac7474f63..7188bb299 100644
--- a/crates/hir_def/src/diagnostics.rs
+++ b/crates/hir_def/src/diagnostics.rs
@@ -97,7 +97,7 @@ impl Diagnostic for UnresolvedImport {
97 97
98// Diagnostic: unresolved-macro-call 98// Diagnostic: unresolved-macro-call
99// 99//
100// This diagnostic is triggered if rust-analyzer is unable to resolove path to a 100// This diagnostic is triggered if rust-analyzer is unable to resolve the path to a
101// macro in a macro invocation. 101// macro in a macro invocation.
102#[derive(Debug)] 102#[derive(Debug)]
103pub struct UnresolvedMacroCall { 103pub struct UnresolvedMacroCall {
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 09bcb10dc..7bb22c4c4 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -24,7 +24,7 @@ use la_arena::{Arena, Idx, RawIdx};
24use profile::Count; 24use profile::Count;
25use rustc_hash::FxHashMap; 25use rustc_hash::FxHashMap;
26use smallvec::SmallVec; 26use smallvec::SmallVec;
27use syntax::{ast, match_ast, SyntaxKind}; 27use syntax::{ast, match_ast, SmolStr, SyntaxKind};
28 28
29use crate::{ 29use crate::{
30 attr::{Attrs, RawAttrs}, 30 attr::{Attrs, RawAttrs},
@@ -110,6 +110,11 @@ 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 },
113 _ => { 118 _ => {
114 panic!("cannot create item tree from {:?} {}", syntax, syntax); 119 panic!("cannot create item tree from {:?} {}", syntax, syntax);
115 }, 120 },
@@ -551,16 +556,25 @@ pub struct Function {
551 pub generic_params: GenericParamsId, 556 pub generic_params: GenericParamsId,
552 pub has_self_param: bool, 557 pub has_self_param: bool,
553 pub has_body: bool, 558 pub has_body: bool,
554 pub is_unsafe: bool, 559 pub qualifier: FunctionQualifier,
555 /// Whether the function is located in an `extern` block (*not* whether it is an 560 /// Whether the function is located in an `extern` block (*not* whether it is an
556 /// `extern "abi" fn`). 561 /// `extern "abi" fn`).
557 pub is_extern: bool, 562 pub is_in_extern_block: bool,
558 pub params: Box<[Idx<TypeRef>]>, 563 pub params: Box<[Idx<TypeRef>]>,
559 pub is_varargs: bool, 564 pub is_varargs: bool,
560 pub ret_type: Idx<TypeRef>, 565 pub ret_type: Idx<TypeRef>,
561 pub ast_id: FileAstId<ast::Fn>, 566 pub ast_id: FileAstId<ast::Fn>,
562} 567}
563 568
569#[derive(Debug, Clone, PartialEq, Eq)]
570pub struct FunctionQualifier {
571 pub is_default: bool,
572 pub is_const: bool,
573 pub is_async: bool,
574 pub is_unsafe: bool,
575 pub abi: Option<SmolStr>,
576}
577
564#[derive(Debug, Clone, Eq, PartialEq)] 578#[derive(Debug, Clone, Eq, PartialEq)]
565pub struct Struct { 579pub struct Struct {
566 pub name: Name, 580 pub name: Name,
@@ -624,7 +638,9 @@ pub struct Trait {
624 pub name: Name, 638 pub name: Name,
625 pub visibility: RawVisibilityId, 639 pub visibility: RawVisibilityId,
626 pub generic_params: GenericParamsId, 640 pub generic_params: GenericParamsId,
627 pub auto: bool, 641 pub is_auto: bool,
642 pub is_unsafe: bool,
643 pub bounds: Box<[TypeBound]>,
628 pub items: Box<[AssocItem]>, 644 pub items: Box<[AssocItem]>,
629 pub ast_id: FileAstId<ast::Trait>, 645 pub ast_id: FileAstId<ast::Trait>,
630} 646}
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 240fdacf9..7e91b991d 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -391,14 +391,33 @@ impl Ctx {
391 let has_body = func.body().is_some(); 391 let has_body = func.body().is_some();
392 392
393 let ast_id = self.source_ast_id_map.ast_id(func); 393 let ast_id = self.source_ast_id_map.ast_id(func);
394 let qualifier = FunctionQualifier {
395 is_default: func.default_token().is_some(),
396 is_const: func.const_token().is_some(),
397 is_async: func.async_token().is_some(),
398 is_unsafe: func.unsafe_token().is_some(),
399 abi: func.abi().map(|abi| {
400 // FIXME: Abi::abi() -> Option<SyntaxToken>?
401 match abi.syntax().last_token() {
402 Some(tok) if tok.kind() == SyntaxKind::STRING => {
403 // FIXME: Better way to unescape?
404 tok.text().trim_matches('"').into()
405 }
406 _ => {
407 // `extern` default to be `extern "C"`.
408 "C".into()
409 }
410 }
411 }),
412 };
394 let mut res = Function { 413 let mut res = Function {
395 name, 414 name,
396 visibility, 415 visibility,
397 generic_params: GenericParamsId::EMPTY, 416 generic_params: GenericParamsId::EMPTY,
398 has_self_param, 417 has_self_param,
399 has_body, 418 has_body,
400 is_unsafe: func.unsafe_token().is_some(), 419 qualifier,
401 is_extern: false, 420 is_in_extern_block: false,
402 params, 421 params,
403 is_varargs, 422 is_varargs,
404 ret_type, 423 ret_type,
@@ -481,7 +500,9 @@ impl Ctx {
481 let visibility = self.lower_visibility(trait_def); 500 let visibility = self.lower_visibility(trait_def);
482 let generic_params = 501 let generic_params =
483 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def); 502 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def);
484 let auto = trait_def.auto_token().is_some(); 503 let is_auto = trait_def.auto_token().is_some();
504 let is_unsafe = trait_def.unsafe_token().is_some();
505 let bounds = self.lower_type_bounds(trait_def);
485 let items = trait_def.assoc_item_list().map(|list| { 506 let items = trait_def.assoc_item_list().map(|list| {
486 self.with_inherited_visibility(visibility, |this| { 507 self.with_inherited_visibility(visibility, |this| {
487 list.assoc_items() 508 list.assoc_items()
@@ -501,7 +522,9 @@ impl Ctx {
501 name, 522 name,
502 visibility, 523 visibility,
503 generic_params, 524 generic_params,
504 auto, 525 is_auto,
526 is_unsafe,
527 bounds: bounds.into(),
505 items: items.unwrap_or_default(), 528 items: items.unwrap_or_default(),
506 ast_id, 529 ast_id,
507 }; 530 };
@@ -608,8 +631,8 @@ impl Ctx {
608 ast::ExternItem::Fn(ast) => { 631 ast::ExternItem::Fn(ast) => {
609 let func_id = self.lower_function(&ast)?; 632 let func_id = self.lower_function(&ast)?;
610 let func = &mut self.data().functions[func_id.index]; 633 let func = &mut self.data().functions[func_id.index];
611 func.is_unsafe = is_intrinsic_fn_unsafe(&func.name); 634 func.qualifier.is_unsafe = is_intrinsic_fn_unsafe(&func.name);
612 func.is_extern = true; 635 func.is_in_extern_block = true;
613 func_id.into() 636 func_id.into()
614 } 637 }
615 ast::ExternItem::Static(ast) => { 638 ast::ExternItem::Static(ast) => {
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 9ed48c506..81cf652b0 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -13,7 +13,7 @@ use hir_expand::{
13 builtin_macro::find_builtin_macro, 13 builtin_macro::find_builtin_macro,
14 name::{AsName, Name}, 14 name::{AsName, Name},
15 proc_macro::ProcMacroExpander, 15 proc_macro::ProcMacroExpander,
16 HirFileId, MacroCallId, MacroDefId, MacroDefKind, 16 HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
17}; 17};
18use hir_expand::{InFile, MacroCallLoc}; 18use hir_expand::{InFile, MacroCallLoc};
19use rustc_hash::{FxHashMap, FxHashSet}; 19use rustc_hash::{FxHashMap, FxHashSet};
@@ -1455,7 +1455,8 @@ impl ModCollector<'_, '_> {
1455 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); 1455 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
1456 1456
1457 // Case 1: try to resolve in legacy scope and expand macro_rules 1457 // Case 1: try to resolve in legacy scope and expand macro_rules
1458 if let Ok(Ok(macro_call_id)) = macro_call_as_call_id( 1458 let mut error = None;
1459 match macro_call_as_call_id(
1459 &ast_id, 1460 &ast_id,
1460 self.def_collector.db, 1461 self.def_collector.db,
1461 self.def_collector.def_map.krate, 1462 self.def_collector.def_map.krate,
@@ -1468,16 +1469,28 @@ impl ModCollector<'_, '_> {
1468 ) 1469 )
1469 }) 1470 })
1470 }, 1471 },
1471 &mut |_err| (), 1472 &mut |err| error = Some(err),
1472 ) { 1473 ) {
1473 self.def_collector.unexpanded_macros.push(MacroDirective { 1474 Ok(Ok(macro_call_id)) => {
1474 module_id: self.module_id, 1475 self.def_collector.unexpanded_macros.push(MacroDirective {
1475 ast_id, 1476 module_id: self.module_id,
1476 legacy: Some(macro_call_id), 1477 ast_id,
1477 depth: self.macro_depth + 1, 1478 legacy: Some(macro_call_id),
1478 }); 1479 depth: self.macro_depth + 1,
1480 });
1479 1481
1480 return; 1482 return;
1483 }
1484 Ok(Err(_)) => {
1485 // Built-in macro failed eager expansion.
1486 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
1487 self.module_id,
1488 MacroCallKind::FnLike(ast_id.ast_id),
1489 error.unwrap().to_string(),
1490 ));
1491 return;
1492 }
1493 Err(UnresolvedMacro) => (),
1481 } 1494 }
1482 1495
1483 // Case 2: resolve in module scope, expand during name resolution. 1496 // Case 2: resolve in module scope, expand during name resolution.
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index 1b8e885b0..c22ef46fd 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -155,3 +155,48 @@ fn inactive_via_cfg_attr() {
155 "#, 155 "#,
156 ); 156 );
157} 157}
158
159#[test]
160fn unresolved_legacy_scope_macro() {
161 check_diagnostics(
162 r#"
163 //- /lib.rs
164 macro_rules! m { () => {} }
165
166 m!();
167 m2!();
168 //^^^^^^ unresolved macro call
169 "#,
170 );
171}
172
173#[test]
174fn unresolved_module_scope_macro() {
175 check_diagnostics(
176 r#"
177 //- /lib.rs
178 mod mac {
179 #[macro_export]
180 macro_rules! m { () => {} }
181 }
182
183 self::m!();
184 self::m2!();
185 //^^^^^^^^^^^^ unresolved macro call
186 "#,
187 );
188}
189
190#[test]
191fn builtin_macro_fails_expansion() {
192 check_diagnostics(
193 r#"
194 //- /lib.rs
195 #[rustc_builtin_macro]
196 macro_rules! include { () => {} }
197
198 include!("doesntexist");
199 //^^^^^^^^^^^^^^^^^^^^^^^^ could not convert tokens
200 "#,
201 );
202}
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 0e60dc2b6..8c923bb7b 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -9,7 +9,10 @@ use std::{
9 9
10use crate::{body::LowerCtx, type_ref::LifetimeRef}; 10use crate::{body::LowerCtx, type_ref::LifetimeRef};
11use base_db::CrateId; 11use base_db::CrateId;
12use hir_expand::{hygiene::Hygiene, name::Name}; 12use hir_expand::{
13 hygiene::Hygiene,
14 name::{name, Name},
15};
13use syntax::ast; 16use syntax::ast;
14 17
15use crate::{ 18use crate::{
@@ -209,6 +212,12 @@ impl Path {
209 }; 212 };
210 Some(res) 213 Some(res)
211 } 214 }
215
216 pub fn is_self_type(&self) -> bool {
217 self.type_anchor.is_none()
218 && self.generic_args == &[None]
219 && self.mod_path.as_ident() == Some(&name!(Self))
220 }
212} 221}
213 222
214#[derive(Debug, Clone, PartialEq, Eq, Hash)] 223#[derive(Debug, Clone, PartialEq, Eq, Hash)]