diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-03-15 18:24:22 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-03-15 18:24:22 +0000 |
commit | 47b74cadf9774f624ff13f8c7929c66be8247fc8 (patch) | |
tree | 6dc42e70ef3635bb53354b4e8991f517eb9b389d | |
parent | e24453c5ee46546b0852c15500d51f77b10a7a6f (diff) | |
parent | ebb10da563f1c3a0ebf48c1022bceb9641b6e964 (diff) |
Merge #7970
7970: Fix incorrect diagnostics for failing built in macros r=jonas-schievink a=brandondong
**Reproduction:**
1. Use a built in macro in such a way that rust-analyzer fails to expand it. For example:
**lib.rs**
```
include!("<valid file but without a .rs extension so it is not indexed by rust-analyzer>");
```
2. rust-analyzer highlights the macro call and says the macro itself cannot be resolved even though include! is in the standard library (unresolved-macro-call diagnostic).
3. No macro-error diagnostic is raised.
**Root cause for incorrect unresolved-macro-call diagnostic:**
1. collector:collect_macro_call is able to resolve include! in legacy scope but the expansion fails. Therefore, it's pushed into unexpanded_macros to be retried with module scope.
2. include! fails at the resolution step in collector:resolve_macros now that it's using module scope. Therefore, it's retained in unexpanded_macros.
3. Finally, collector:finish tries resolving the remaining unexpanded macros but only with module scope. include! again fails at the resolution step so a diagnostic is created.
**Root cause for missing macro-error diagnostic:**
1. In collector:resolve_macros, directive.legacy is None since eager expansion failed in collector:collect_macro_call. The macro_call_as_call_id fails to resolve since we're retrying in module scope. Therefore, collect_macro_expansion is not called for the macro and no macro-error diagnostic is generated.
**Fix:**
- In collector:collect_macro_call, do not add failing built-in macros to the unexpanded_macros list and immediately raise the macro-error diagnostic. This is in contrast to lazy macros which are resolved in collector::resolve_macros and later expanded in collect_macro_expansion where a macro-error diagnostic may be raised.
Co-authored-by: Brandon <[email protected]>
Co-authored-by: brandondong <[email protected]>
-rw-r--r-- | crates/hir_def/src/diagnostics.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 33 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/diagnostics.rs | 45 |
3 files changed, 69 insertions, 11 deletions
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)] |
103 | pub struct UnresolvedMacroCall { | 103 | pub struct UnresolvedMacroCall { |
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 | }; |
18 | use hir_expand::{InFile, MacroCallLoc}; | 18 | use hir_expand::{InFile, MacroCallLoc}; |
19 | use rustc_hash::{FxHashMap, FxHashSet}; | 19 | use 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] | ||
160 | fn 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] | ||
174 | fn 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] | ||
191 | fn 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 | } | ||