diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs index 69585b44a1..8e6e6a11ab 100644 --- a/crates/base-db/src/fixture.rs +++ b/crates/base-db/src/fixture.rs @@ -159,7 +159,7 @@ impl ChangeFixture { meta.cfg.clone(), meta.cfg, meta.env, - Default::default(), + Ok(Vec::new()), false, origin, ); @@ -194,7 +194,7 @@ impl ChangeFixture { default_cfg.clone(), default_cfg, Env::default(), - Default::default(), + Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None }, ); @@ -231,7 +231,7 @@ impl ChangeFixture { CfgOptions::default(), CfgOptions::default(), Env::default(), - Vec::new(), + Ok(Vec::new()), false, CrateOrigin::Lang(LangCrateOrigin::Core), ); @@ -268,7 +268,7 @@ impl ChangeFixture { CfgOptions::default(), CfgOptions::default(), Env::default(), - proc_macro, + Ok(proc_macro), true, CrateOrigin::CratesIo { repo: None }, ); diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 9fcaa4b06d..4d0a3a3012 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -231,6 +231,8 @@ pub enum ProcMacroExpansionError { System(String), } +pub type ProcMacroLoadResult = Result, String>; + #[derive(Debug, Clone)] pub struct ProcMacro { pub name: SmolStr, @@ -254,7 +256,7 @@ pub struct CrateData { pub potential_cfg_options: CfgOptions, pub env: Env, pub dependencies: Vec, - pub proc_macro: Vec, + pub proc_macro: ProcMacroLoadResult, pub origin: CrateOrigin, pub is_proc_macro: bool, } @@ -300,19 +302,19 @@ impl Dependency { impl CrateGraph { pub fn add_crate_root( &mut self, - file_id: FileId, + root_file_id: FileId, edition: Edition, display_name: Option, version: Option, cfg_options: CfgOptions, potential_cfg_options: CfgOptions, env: Env, - proc_macro: Vec, + proc_macro: ProcMacroLoadResult, is_proc_macro: bool, origin: CrateOrigin, ) -> CrateId { let data = CrateData { - root_file_id: file_id, + root_file_id, edition, version, display_name, @@ -628,7 +630,7 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Default::default(), + Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None }, ); @@ -640,7 +642,7 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Default::default(), + Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None }, ); @@ -652,7 +654,7 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Default::default(), + Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None }, ); @@ -678,7 +680,7 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Default::default(), + Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None }, ); @@ -690,7 +692,7 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Default::default(), + Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None }, ); @@ -713,7 +715,7 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Default::default(), + Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None }, ); @@ -725,7 +727,7 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Default::default(), + Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None }, ); @@ -737,7 +739,7 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Default::default(), + Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None }, ); @@ -760,7 +762,7 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Default::default(), + Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None }, ); @@ -772,7 +774,7 @@ mod tests { CfgOptions::default(), CfgOptions::default(), Env::default(), - Default::default(), + Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None }, ); diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index 2454698bb6..f5622ecf60 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -13,7 +13,7 @@ pub use crate::{ input::{ CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, LangCrateOrigin, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, - ProcMacroId, ProcMacroKind, SourceRoot, SourceRootId, + ProcMacroId, ProcMacroKind, ProcMacroLoadResult, SourceRoot, SourceRootId, }, }; pub use salsa::{self, Cancelled}; diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 7fea46bee3..1c276e0d6f 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -74,19 +74,27 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T } let cfg_options = &krate.cfg_options; - let proc_macros = krate - .proc_macro - .iter() - .enumerate() - .map(|(idx, it)| { - // FIXME: a hacky way to create a Name from string. - let name = tt::Ident { text: it.name.clone(), id: tt::TokenId::unspecified() }; + let (proc_macros, proc_macro_err) = match &krate.proc_macro { + Ok(proc_macros) => { ( - name.as_name(), - ProcMacroExpander::new(def_map.krate, base_db::ProcMacroId(idx as u32)), + proc_macros + .iter() + .enumerate() + .map(|(idx, it)| { + // FIXME: a hacky way to create a Name from string. + let name = + tt::Ident { text: it.name.clone(), id: tt::TokenId::unspecified() }; + ( + name.as_name(), + ProcMacroExpander::new(def_map.krate, base_db::ProcMacroId(idx as u32)), + ) + }) + .collect(), + None, ) - }) - .collect(); + } + Err(e) => (Vec::new(), Some(e.clone())), + }; let is_proc_macro = krate.is_proc_macro; let mut collector = DefCollector { @@ -100,6 +108,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T mod_dirs: FxHashMap::default(), cfg_options, proc_macros, + proc_macro_err, from_glob_import: Default::default(), skip_attrs: Default::default(), derive_helpers_in_scope: Default::default(), @@ -241,6 +250,7 @@ struct DefCollector<'a> { /// empty when proc. macro support is disabled (in which case we still do name resolution for /// them). proc_macros: Vec<(Name, ProcMacroExpander)>, + proc_macro_err: Option, is_proc_macro: bool, from_glob_import: PerNsGlobImports, /// If we fail to resolve an attribute on a `ModItem`, we fall back to ignoring the attribute. @@ -1232,6 +1242,7 @@ impl DefCollector<'_> { self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro( directive.module_id, loc.kind, + self.proc_macro_err.clone(), )); return recollect_without(self); @@ -1283,7 +1294,11 @@ impl DefCollector<'_> { let diag = match err { hir_expand::ExpandError::UnresolvedProcMacro => { // Missing proc macros are non-fatal, so they are handled specially. - DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone()) + DefDiagnostic::unresolved_proc_macro( + module_id, + loc.kind.clone(), + self.proc_macro_err.clone(), + ) } _ => DefDiagnostic::macro_error(module_id, loc.kind.clone(), err.to_string()), }; @@ -2097,6 +2112,7 @@ mod tests { mod_dirs: FxHashMap::default(), cfg_options: &CfgOptions::default(), proc_macros: Default::default(), + proc_macro_err: None, from_glob_import: Default::default(), skip_attrs: Default::default(), derive_helpers_in_scope: Default::default(), diff --git a/crates/hir-def/src/nameres/diagnostics.rs b/crates/hir-def/src/nameres/diagnostics.rs index dd3ff92cb3..927237962d 100644 --- a/crates/hir-def/src/nameres/diagnostics.rs +++ b/crates/hir-def/src/nameres/diagnostics.rs @@ -23,7 +23,7 @@ pub enum DefDiagnosticKind { UnconfiguredCode { ast: AstId, cfg: CfgExpr, opts: CfgOptions }, - UnresolvedProcMacro { ast: MacroCallKind }, + UnresolvedProcMacro { ast: MacroCallKind, proc_macro_err: Option }, UnresolvedMacroCall { ast: MacroCallKind, path: ModPath }, @@ -81,8 +81,15 @@ impl DefDiagnostic { Self { in_module: container, kind: DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } } } - pub(super) fn unresolved_proc_macro(container: LocalModuleId, ast: MacroCallKind) -> Self { - Self { in_module: container, kind: DefDiagnosticKind::UnresolvedProcMacro { ast } } + pub(super) fn unresolved_proc_macro( + container: LocalModuleId, + ast: MacroCallKind, + proc_macro_err: Option, + ) -> Self { + Self { + in_module: container, + kind: DefDiagnosticKind::UnresolvedProcMacro { ast, proc_macro_err }, + } } pub(super) fn macro_error( diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs index df6c38761c..b2686592a5 100644 --- a/crates/hir-expand/src/proc_macro.rs +++ b/crates/hir-expand/src/proc_macro.rs @@ -34,7 +34,15 @@ impl ProcMacroExpander { match self.proc_macro_id { Some(id) => { let krate_graph = db.crate_graph(); - let proc_macro = match krate_graph[self.krate].proc_macro.get(id.0 as usize) { + let proc_macros = match &krate_graph[self.krate].proc_macro { + Ok(proc_macros) => proc_macros, + Err(e) => { + return ExpandResult::only_err(ExpandError::Other( + e.clone().into_boxed_str(), + )) + } + }; + let proc_macro = match proc_macros.get(id.0 as usize) { Some(proc_macro) => proc_macro, None => { return ExpandResult::only_err(ExpandError::Other( diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 0c88d15b08..4dd23dfa14 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -87,6 +87,7 @@ pub struct UnresolvedProcMacro { pub precise_location: Option, pub macro_name: Option, pub kind: MacroKind, + pub proc_macro_err: Option, } #[derive(Debug, Clone, Eq, PartialEq)] diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 4620d0c03a..9f7a2d63fe 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -627,7 +627,7 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec, diag: ); } - DefDiagnosticKind::UnresolvedProcMacro { ast } => { + DefDiagnosticKind::UnresolvedProcMacro { ast, proc_macro_err } => { let (node, precise_location, macro_name, kind) = match ast { MacroCallKind::FnLike { ast_id, .. } => { let node = ast_id.to_node(db.upcast()); @@ -689,7 +689,16 @@ fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec, diag: ) } }; - acc.push(UnresolvedProcMacro { node, precise_location, macro_name, kind }.into()); + acc.push( + UnresolvedProcMacro { + node, + precise_location, + macro_name, + kind, + proc_macro_err: proc_macro_err.clone(), + } + .into(), + ); } DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { @@ -1163,6 +1172,7 @@ impl DefWithBody { precise_location: None, macro_name: None, kind: MacroKind::ProcMacro, + proc_macro_err: None, } .into(), ), diff --git a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs index 37350a7aaf..5f905de4f1 100644 --- a/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs +++ b/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs @@ -29,19 +29,23 @@ pub(crate) fn unresolved_proc_macro( Some(name) => format!("proc macro `{}` not expanded", name), None => "proc macro not expanded".to_string(), }; - let (message, severity) = if config_enabled { - (message, Severity::Error) - } else { - let message = match d.kind { - hir::MacroKind::Attr if proc_macros_enabled => { - format!("{message}{}", " (attribute macro expansion is disabled)") + let severity = if config_enabled { Severity::Error } else { Severity::WeakWarning }; + let message = format!( + "{message}: {}", + if config_enabled { + match &d.proc_macro_err { + Some(e) => e, + None => "proc macro not found", } - _ => { - format!("{message}{}", " (proc-macro expansion is disabled)") + } else { + match d.kind { + hir::MacroKind::Attr if proc_macros_enabled => { + "attribute macro expansion is disabled" + } + _ => "proc-macro expansion is disabled", } - }; - (message, Severity::WeakWarning) - }; + }, + ); Diagnostic::new("unresolved-proc-macro", message, display_range).severity(severity) } diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index aab5ceda36..07a7fbd783 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -233,7 +233,7 @@ impl Analysis { cfg_options.clone(), cfg_options, Env::default(), - Default::default(), + Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None }, ); diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs index eb7a28b972..4a30168ca5 100644 --- a/crates/proc-macro-api/src/lib.rs +++ b/crates/proc-macro-api/src/lib.rs @@ -118,16 +118,13 @@ impl ProcMacroServer { Ok(ProcMacroServer { process: Arc::new(Mutex::new(process)) }) } - pub fn load_dylib( - &self, - dylib: MacroDylib, - ) -> Result, String>, ServerError> { + pub fn load_dylib(&self, dylib: MacroDylib) -> Result, ServerError> { let _p = profile::span("ProcMacroClient::by_dylib_path"); let macros = self.process.lock().unwrap_or_else(|e| e.into_inner()).find_proc_macros(&dylib.path)?; - let res = macros.map(|macros| { - macros + match macros { + Ok(macros) => Ok(macros .into_iter() .map(|(name, kind)| ProcMacro { process: self.process.clone(), @@ -135,10 +132,9 @@ impl ProcMacroServer { kind, dylib_path: dylib.path.clone(), }) - .collect() - }); - - Ok(res) + .collect()), + Err(message) => Err(ServerError { message, io: None }), + } } } diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index e72903e55f..8eb8c40a22 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -88,7 +88,7 @@ fn rooted_project_json(data: ProjectJsonData) -> ProjectJson { } fn to_crate_graph(project_workspace: ProjectWorkspace) -> CrateGraph { - project_workspace.to_crate_graph(&mut |_, _| Vec::new(), &mut { + project_workspace.to_crate_graph(&mut |_, _| Ok(Vec::new()), &mut { let mut counter = 0; move |_path| { counter += 1; diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index a94a38a17d..8982a9904e 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -7,7 +7,7 @@ use std::{collections::VecDeque, fmt, fs, process::Command}; use anyhow::{format_err, Context, Result}; use base_db::{ CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, - FileId, LangCrateOrigin, ProcMacro, + FileId, LangCrateOrigin, ProcMacroLoadResult, }; use cfg::{CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; @@ -389,7 +389,7 @@ impl ProjectWorkspace { pub fn to_crate_graph( &self, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> Vec, + load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, ) -> CrateGraph { let _p = profile::span("ProjectWorkspace::to_crate_graph"); @@ -434,7 +434,7 @@ impl ProjectWorkspace { fn project_json_to_crate_graph( rustc_cfg: Vec, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> Vec, + load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, project: &ProjectJson, sysroot: &Option, @@ -454,12 +454,13 @@ fn project_json_to_crate_graph( }) .map(|(crate_id, krate, file_id)| { let env = krate.env.clone().into_iter().collect(); - let proc_macro = krate.proc_macro_dylib_path.clone().map(|it| { - load_proc_macro( + let proc_macro = match krate.proc_macro_dylib_path.clone() { + Some(it) => load_proc_macro( krate.display_name.as_ref().map(|it| it.canonical_name()).unwrap_or(""), &it, - ) - }); + ), + None => Ok(Vec::new()), + }; let target_cfgs = match krate.target.as_deref() { Some(target) => { @@ -480,7 +481,7 @@ fn project_json_to_crate_graph( cfg_options.clone(), cfg_options, env, - proc_macro.unwrap_or_default(), + proc_macro, krate.is_proc_macro, if krate.display_name.is_some() { CrateOrigin::CratesIo { repo: krate.repository.clone() } @@ -521,7 +522,7 @@ fn project_json_to_crate_graph( fn cargo_to_crate_graph( rustc_cfg: Vec, override_cfg: &CfgOverrides, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> Vec, + load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, cargo: &CargoWorkspace, build_scripts: &WorkspaceBuildScripts, @@ -708,7 +709,7 @@ fn detached_files_to_crate_graph( cfg_options.clone(), cfg_options.clone(), Env::default(), - Vec::new(), + Ok(Vec::new()), false, CrateOrigin::CratesIo { repo: None }, ); @@ -724,7 +725,7 @@ fn handle_rustc_crates( crate_graph: &mut CrateGraph, cfg_options: &CfgOptions, override_cfg: &CfgOverrides, - load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> Vec, + load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult, pkg_to_lib_crate: &mut FxHashMap, CrateId>, public_deps: &SysrootPublicDeps, cargo: &CargoWorkspace, @@ -840,7 +841,7 @@ fn add_target_crate_root( pkg: &PackageData, build_data: Option<&BuildScriptOutput>, cfg_options: &CfgOptions, - load_proc_macro: &mut dyn FnMut(&AbsPath) -> Vec, + load_proc_macro: &mut dyn FnMut(&AbsPath) -> ProcMacroLoadResult, file_id: FileId, cargo_name: &str, is_proc_macro: bool, @@ -866,11 +867,10 @@ fn add_target_crate_root( } } - let proc_macro = build_data - .as_ref() - .and_then(|it| it.proc_macro_dylib_path.as_ref()) - .map(|it| load_proc_macro(it)) - .unwrap_or_default(); + let proc_macro = match build_data.as_ref().and_then(|it| it.proc_macro_dylib_path.as_ref()) { + Some(it) => load_proc_macro(it), + None => Ok(Vec::new()), + }; let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string()); let mut potential_cfg_options = cfg_options.clone(); @@ -922,7 +922,6 @@ fn sysroot_to_crate_graph( let file_id = load(&sysroot[krate].root)?; let env = Env::default(); - let proc_macro = vec![]; let display_name = CrateDisplayName::from_canonical_name(sysroot[krate].name.clone()); let crate_id = crate_graph.add_crate_root( file_id, @@ -932,7 +931,7 @@ fn sysroot_to_crate_graph( cfg_options.clone(), cfg_options.clone(), env, - proc_macro, + Ok(Vec::new()), false, CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)), ); diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 62a446ce2a..3f129efd95 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -19,7 +19,7 @@ use hir::db::DefDatabase; use ide::Change; use ide_db::base_db::{ CrateGraph, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, - SourceRoot, VfsPath, + ProcMacroLoadResult, SourceRoot, VfsPath, }; use proc_macro_api::{MacroDylib, ProcMacroServer}; use project_model::{ProjectWorkspace, WorkspaceBuildScripts}; @@ -536,45 +536,37 @@ impl SourceRootConfig { /// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace` /// with an identity dummy expander. pub(crate) fn load_proc_macro( - client: Option<&ProcMacroServer>, + server: Option<&ProcMacroServer>, path: &AbsPath, dummy_replace: &[Box], -) -> Vec { - let dylib = match MacroDylib::new(path.to_path_buf()) { - Ok(it) => it, - Err(err) => { - // FIXME: that's not really right -- we store this error in a - // persistent status. - tracing::warn!("failed to load proc macro: {}", err); - return Vec::new(); +) -> ProcMacroLoadResult { + let res: Result<_, String> = (|| { + let dylib = MacroDylib::new(path.to_path_buf()) + .map_err(|io| format!("Proc-macro dylib loading failed: {io}"))?; + Ok(if let Some(it) = server { + let vec = it.load_dylib(dylib).map_err(|e| format!("{e}"))?; + vec.into_iter() + .map(|expander| expander_to_proc_macro(expander, dummy_replace)) + .collect() + } else { + Vec::new() + }) + })(); + return match res { + Ok(proc_macros) => { + tracing::info!( + "Loaded proc-macros for {}: {:?}", + path.display(), + proc_macros.iter().map(|it| it.name.clone()).collect::>() + ); + Ok(proc_macros) + } + Err(e) => { + tracing::warn!("proc-macro loading for {} failed: {e}", path.display()); + Err(e) } }; - let proc_macros: Vec<_> = client - .map(|it| it.load_dylib(dylib)) - .into_iter() - .flat_map(|it| match it { - Ok(Ok(macros)) => macros, - Err(err) => { - tracing::error!("proc macro server crashed: {}", err); - Vec::new() - } - Ok(Err(err)) => { - // FIXME: that's not really right -- we store this error in a - // persistent status. - tracing::warn!("failed to load proc macro: {}", err); - Vec::new() - } - }) - .map(|expander| expander_to_proc_macro(expander, dummy_replace)) - .collect(); - tracing::info!( - "Loaded proc-macros for {}: {:?}", - path.display(), - proc_macros.iter().map(|it| it.name.clone()).collect::>() - ); - return proc_macros; - fn expander_to_proc_macro( expander: proc_macro_api::ProcMacro, dummy_replace: &[Box],