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 <brandondong604@hotmail.com> Co-authored-by: brandondong <brandondong604@hotmail.com>
This commit is contained in:
commit
47b74cadf9
@ -97,7 +97,7 @@ impl Diagnostic for UnresolvedImport {
|
||||
|
||||
// Diagnostic: unresolved-macro-call
|
||||
//
|
||||
// This diagnostic is triggered if rust-analyzer is unable to resolove path to a
|
||||
// This diagnostic is triggered if rust-analyzer is unable to resolve the path to a
|
||||
// macro in a macro invocation.
|
||||
#[derive(Debug)]
|
||||
pub struct UnresolvedMacroCall {
|
||||
|
@ -13,7 +13,7 @@ use hir_expand::{
|
||||
builtin_macro::find_builtin_macro,
|
||||
name::{AsName, Name},
|
||||
proc_macro::ProcMacroExpander,
|
||||
HirFileId, MacroCallId, MacroDefId, MacroDefKind,
|
||||
HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
|
||||
};
|
||||
use hir_expand::{InFile, MacroCallLoc};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
@ -1455,7 +1455,8 @@ impl ModCollector<'_, '_> {
|
||||
let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone());
|
||||
|
||||
// Case 1: try to resolve in legacy scope and expand macro_rules
|
||||
if let Ok(Ok(macro_call_id)) = macro_call_as_call_id(
|
||||
let mut error = None;
|
||||
match macro_call_as_call_id(
|
||||
&ast_id,
|
||||
self.def_collector.db,
|
||||
self.def_collector.def_map.krate,
|
||||
@ -1468,16 +1469,28 @@ impl ModCollector<'_, '_> {
|
||||
)
|
||||
})
|
||||
},
|
||||
&mut |_err| (),
|
||||
&mut |err| error = Some(err),
|
||||
) {
|
||||
self.def_collector.unexpanded_macros.push(MacroDirective {
|
||||
module_id: self.module_id,
|
||||
ast_id,
|
||||
legacy: Some(macro_call_id),
|
||||
depth: self.macro_depth + 1,
|
||||
});
|
||||
Ok(Ok(macro_call_id)) => {
|
||||
self.def_collector.unexpanded_macros.push(MacroDirective {
|
||||
module_id: self.module_id,
|
||||
ast_id,
|
||||
legacy: Some(macro_call_id),
|
||||
depth: self.macro_depth + 1,
|
||||
});
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
Ok(Err(_)) => {
|
||||
// Built-in macro failed eager expansion.
|
||||
self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
|
||||
self.module_id,
|
||||
MacroCallKind::FnLike(ast_id.ast_id),
|
||||
error.unwrap().to_string(),
|
||||
));
|
||||
return;
|
||||
}
|
||||
Err(UnresolvedMacro) => (),
|
||||
}
|
||||
|
||||
// Case 2: resolve in module scope, expand during name resolution.
|
||||
|
@ -155,3 +155,48 @@ fn inactive_via_cfg_attr() {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unresolved_legacy_scope_macro() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
macro_rules! m { () => {} }
|
||||
|
||||
m!();
|
||||
m2!();
|
||||
//^^^^^^ unresolved macro call
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unresolved_module_scope_macro() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
mod mac {
|
||||
#[macro_export]
|
||||
macro_rules! m { () => {} }
|
||||
}
|
||||
|
||||
self::m!();
|
||||
self::m2!();
|
||||
//^^^^^^^^^^^^ unresolved macro call
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builtin_macro_fails_expansion() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! include { () => {} }
|
||||
|
||||
include!("doesntexist");
|
||||
//^^^^^^^^^^^^^^^^^^^^^^^^ could not convert tokens
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user