aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/body.rs19
-rw-r--r--crates/hir_def/src/body/diagnostics.rs6
-rw-r--r--crates/hir_def/src/body/lower.rs15
-rw-r--r--crates/hir_def/src/body/tests.rs12
-rw-r--r--crates/hir_def/src/data.rs37
-rw-r--r--crates/hir_def/src/diagnostics.rs2
-rw-r--r--crates/hir_def/src/lib.rs23
7 files changed, 75 insertions, 39 deletions
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 8bcc350ce..d2dcd6727 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -32,6 +32,7 @@ use crate::{
32 path::{ModPath, Path}, 32 path::{ModPath, Path},
33 src::HasSource, 33 src::HasSource,
34 AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleId, 34 AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleId,
35 UnresolvedMacro,
35}; 36};
36 37
37/// A subset of Expander that only deals with cfg attributes. We only need it to 38/// A subset of Expander that only deals with cfg attributes. We only need it to
@@ -101,10 +102,12 @@ impl Expander {
101 &mut self, 102 &mut self,
102 db: &dyn DefDatabase, 103 db: &dyn DefDatabase,
103 macro_call: ast::MacroCall, 104 macro_call: ast::MacroCall,
104 ) -> ExpandResult<Option<(Mark, T)>> { 105 ) -> Result<ExpandResult<Option<(Mark, T)>>, UnresolvedMacro> {
105 if self.recursion_limit + 1 > EXPANSION_RECURSION_LIMIT { 106 if self.recursion_limit + 1 > EXPANSION_RECURSION_LIMIT {
106 cov_mark::hit!(your_stack_belongs_to_me); 107 cov_mark::hit!(your_stack_belongs_to_me);
107 return ExpandResult::str_err("reached recursion limit during macro expansion".into()); 108 return Ok(ExpandResult::str_err(
109 "reached recursion limit during macro expansion".into(),
110 ));
108 } 111 }
109 112
110 let macro_call = InFile::new(self.current_file_id, &macro_call); 113 let macro_call = InFile::new(self.current_file_id, &macro_call);
@@ -116,14 +119,14 @@ impl Expander {
116 let call_id = 119 let call_id =
117 macro_call.as_call_id_with_errors(db, self.def_map.krate(), resolver, &mut |e| { 120 macro_call.as_call_id_with_errors(db, self.def_map.krate(), resolver, &mut |e| {
118 err.get_or_insert(e); 121 err.get_or_insert(e);
119 }); 122 })?;
120 let call_id = match call_id { 123 let call_id = match call_id {
121 Some(it) => it, 124 Some(it) => it,
122 None => { 125 None => {
123 if err.is_none() { 126 if err.is_none() {
124 log::warn!("no error despite `as_call_id_with_errors` returning `None`"); 127 log::warn!("no error despite `as_call_id_with_errors` returning `None`");
125 } 128 }
126 return ExpandResult { value: None, err }; 129 return Ok(ExpandResult { value: None, err });
127 } 130 }
128 }; 131 };
129 132
@@ -141,9 +144,9 @@ impl Expander {
141 log::warn!("no error despite `parse_or_expand` failing"); 144 log::warn!("no error despite `parse_or_expand` failing");
142 } 145 }
143 146
144 return ExpandResult::only_err(err.unwrap_or_else(|| { 147 return Ok(ExpandResult::only_err(err.unwrap_or_else(|| {
145 mbe::ExpandError::Other("failed to parse macro invocation".into()) 148 mbe::ExpandError::Other("failed to parse macro invocation".into())
146 })); 149 })));
147 } 150 }
148 }; 151 };
149 152
@@ -151,7 +154,7 @@ impl Expander {
151 Some(it) => it, 154 Some(it) => it,
152 None => { 155 None => {
153 // This can happen without being an error, so only forward previous errors. 156 // This can happen without being an error, so only forward previous errors.
154 return ExpandResult { value: None, err }; 157 return Ok(ExpandResult { value: None, err });
155 } 158 }
156 }; 159 };
157 160
@@ -167,7 +170,7 @@ impl Expander {
167 self.current_file_id = file_id; 170 self.current_file_id = file_id;
168 self.ast_id_map = db.ast_id_map(file_id); 171 self.ast_id_map = db.ast_id_map(file_id);
169 172
170 ExpandResult { value: Some((mark, node)), err } 173 Ok(ExpandResult { value: Some((mark, node)), err })
171 } 174 }
172 175
173 pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { 176 pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
diff --git a/crates/hir_def/src/body/diagnostics.rs b/crates/hir_def/src/body/diagnostics.rs
index 1de7d30e2..f6992c9a8 100644
--- a/crates/hir_def/src/body/diagnostics.rs
+++ b/crates/hir_def/src/body/diagnostics.rs
@@ -2,13 +2,14 @@
2 2
3use hir_expand::diagnostics::DiagnosticSink; 3use hir_expand::diagnostics::DiagnosticSink;
4 4
5use crate::diagnostics::{InactiveCode, MacroError, UnresolvedProcMacro}; 5use crate::diagnostics::{InactiveCode, MacroError, UnresolvedMacroCall, UnresolvedProcMacro};
6 6
7#[derive(Debug, Eq, PartialEq)] 7#[derive(Debug, Eq, PartialEq)]
8pub(crate) enum BodyDiagnostic { 8pub(crate) enum BodyDiagnostic {
9 InactiveCode(InactiveCode), 9 InactiveCode(InactiveCode),
10 MacroError(MacroError), 10 MacroError(MacroError),
11 UnresolvedProcMacro(UnresolvedProcMacro), 11 UnresolvedProcMacro(UnresolvedProcMacro),
12 UnresolvedMacroCall(UnresolvedMacroCall),
12} 13}
13 14
14impl BodyDiagnostic { 15impl BodyDiagnostic {
@@ -23,6 +24,9 @@ impl BodyDiagnostic {
23 BodyDiagnostic::UnresolvedProcMacro(diag) => { 24 BodyDiagnostic::UnresolvedProcMacro(diag) => {
24 sink.push(diag.clone()); 25 sink.push(diag.clone());
25 } 26 }
27 BodyDiagnostic::UnresolvedMacroCall(diag) => {
28 sink.push(diag.clone());
29 }
26 } 30 }
27 } 31 }
28} 32}
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 8934ae6c9..08f0c32f4 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -24,7 +24,7 @@ use crate::{
24 body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax}, 24 body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
25 builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, 25 builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
26 db::DefDatabase, 26 db::DefDatabase,
27 diagnostics::{InactiveCode, MacroError, UnresolvedProcMacro}, 27 diagnostics::{InactiveCode, MacroError, UnresolvedMacroCall, UnresolvedProcMacro},
28 expr::{ 28 expr::{
29 dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label, 29 dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label,
30 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, 30 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
@@ -33,7 +33,7 @@ use crate::{
33 item_scope::BuiltinShadowMode, 33 item_scope::BuiltinShadowMode,
34 path::{GenericArgs, Path}, 34 path::{GenericArgs, Path},
35 type_ref::{Mutability, Rawness, TypeRef}, 35 type_ref::{Mutability, Rawness, TypeRef},
36 AdtId, BlockLoc, ModuleDefId, 36 AdtId, BlockLoc, ModuleDefId, UnresolvedMacro,
37}; 37};
38 38
39use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; 39use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
@@ -542,6 +542,17 @@ impl ExprCollector<'_> {
542 let macro_call = self.expander.to_source(AstPtr::new(&e)); 542 let macro_call = self.expander.to_source(AstPtr::new(&e));
543 let res = self.expander.enter_expand(self.db, e); 543 let res = self.expander.enter_expand(self.db, e);
544 544
545 let res = match res {
546 Ok(res) => res,
547 Err(UnresolvedMacro) => {
548 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall(
549 UnresolvedMacroCall { file: outer_file, node: syntax_ptr.cast().unwrap() },
550 ));
551 collector(self, None);
552 return;
553 }
554 };
555
545 match &res.err { 556 match &res.err {
546 Some(ExpandError::UnresolvedProcMacro) => { 557 Some(ExpandError::UnresolvedProcMacro) => {
547 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro( 558 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro(
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index 991a32b15..f8e6f70e8 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -175,6 +175,18 @@ fn f() {
175} 175}
176 176
177#[test] 177#[test]
178fn unresolved_macro_diag() {
179 check_diagnostics(
180 r#"
181fn f() {
182 m!();
183 //^^^^ unresolved macro call
184}
185 "#,
186 );
187}
188
189#[test]
178fn dollar_crate_in_builtin_macro() { 190fn dollar_crate_in_builtin_macro() {
179 check_diagnostics( 191 check_diagnostics(
180 r#" 192 r#"
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index aea53d527..e3bb9de08 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -261,23 +261,26 @@ fn collect_items(
261 let ast_id_map = db.ast_id_map(file_id); 261 let ast_id_map = db.ast_id_map(file_id);
262 let root = db.parse_or_expand(file_id).unwrap(); 262 let root = db.parse_or_expand(file_id).unwrap();
263 let call = ast_id_map.get(call.ast_id).to_node(&root); 263 let call = ast_id_map.get(call.ast_id).to_node(&root);
264 264 let res = expander.enter_expand(db, call);
265 if let Some((mark, mac)) = expander.enter_expand(db, call).value { 265
266 let src: InFile<ast::MacroItems> = expander.to_source(mac); 266 if let Ok(res) = res {
267 let item_tree = db.item_tree(src.file_id); 267 if let Some((mark, mac)) = res.value {
268 let iter = 268 let src: InFile<ast::MacroItems> = expander.to_source(mac);
269 item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item); 269 let item_tree = db.item_tree(src.file_id);
270 items.extend(collect_items( 270 let iter =
271 db, 271 item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item);
272 module, 272 items.extend(collect_items(
273 expander, 273 db,
274 iter, 274 module,
275 src.file_id, 275 expander,
276 container, 276 iter,
277 limit - 1, 277 src.file_id,
278 )); 278 container,
279 279 limit - 1,
280 expander.exit(db, mark); 280 ));
281
282 expander.exit(db, mark);
283 }
281 } 284 }
282 } 285 }
283 } 286 }
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs
index 7188bb299..97abf8653 100644
--- a/crates/hir_def/src/diagnostics.rs
+++ b/crates/hir_def/src/diagnostics.rs
@@ -99,7 +99,7 @@ impl Diagnostic for UnresolvedImport {
99// 99//
100// This diagnostic is triggered if rust-analyzer is unable to resolve the 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, Clone, Eq, PartialEq)]
103pub struct UnresolvedMacroCall { 103pub struct UnresolvedMacroCall {
104 pub file: HirFileId, 104 pub file: HirFileId,
105 pub node: AstPtr<ast::MacroCall>, 105 pub node: AstPtr<ast::MacroCall>,
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index c6655c5fb..4b5cdd7a1 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -583,7 +583,7 @@ pub trait AsMacroCall {
583 krate: CrateId, 583 krate: CrateId,
584 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 584 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
585 ) -> Option<MacroCallId> { 585 ) -> Option<MacroCallId> {
586 self.as_call_id_with_errors(db, krate, resolver, &mut |_| ()) 586 self.as_call_id_with_errors(db, krate, resolver, &mut |_| ()).ok()?
587 } 587 }
588 588
589 fn as_call_id_with_errors( 589 fn as_call_id_with_errors(
@@ -592,7 +592,7 @@ pub trait AsMacroCall {
592 krate: CrateId, 592 krate: CrateId,
593 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 593 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
594 error_sink: &mut dyn FnMut(mbe::ExpandError), 594 error_sink: &mut dyn FnMut(mbe::ExpandError),
595 ) -> Option<MacroCallId>; 595 ) -> Result<Option<MacroCallId>, UnresolvedMacro>;
596} 596}
597 597
598impl AsMacroCall for InFile<&ast::MacroCall> { 598impl AsMacroCall for InFile<&ast::MacroCall> {
@@ -602,24 +602,27 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
602 krate: CrateId, 602 krate: CrateId,
603 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 603 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
604 error_sink: &mut dyn FnMut(mbe::ExpandError), 604 error_sink: &mut dyn FnMut(mbe::ExpandError),
605 ) -> Option<MacroCallId> { 605 ) -> Result<Option<MacroCallId>, UnresolvedMacro> {
606 let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); 606 let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value));
607 let h = Hygiene::new(db.upcast(), self.file_id); 607 let h = Hygiene::new(db.upcast(), self.file_id);
608 let path = self.value.path().and_then(|path| path::ModPath::from_src(path, &h)); 608 let path = self.value.path().and_then(|path| path::ModPath::from_src(path, &h));
609 609
610 if path.is_none() { 610 let path = match path {
611 error_sink(mbe::ExpandError::Other("malformed macro invocation".into())); 611 None => {
612 } 612 error_sink(mbe::ExpandError::Other("malformed macro invocation".into()));
613 return Ok(None);
614 }
615 Some(path) => path,
616 };
613 617
614 macro_call_as_call_id( 618 macro_call_as_call_id(
615 &AstIdWithPath::new(ast_id.file_id, ast_id.value, path?), 619 &AstIdWithPath::new(ast_id.file_id, ast_id.value, path),
616 db, 620 db,
617 krate, 621 krate,
618 resolver, 622 resolver,
619 error_sink, 623 error_sink,
620 ) 624 )
621 .ok()? 625 .map(Result::ok)
622 .ok()
623 } 626 }
624} 627}
625 628
@@ -636,7 +639,7 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
636 } 639 }
637} 640}
638 641
639struct UnresolvedMacro; 642pub struct UnresolvedMacro;
640 643
641fn macro_call_as_call_id( 644fn macro_call_as_call_id(
642 call: &AstIdWithPath<ast::MacroCall>, 645 call: &AstIdWithPath<ast::MacroCall>,