diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 874e91a7a1..c3142c9cfc 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -46,6 +46,11 @@ pub(crate) struct FetchWorkspaceRequest { pub(crate) force_crate_graph_reload: bool, } +pub(crate) struct FetchWorkspaceResponse { + pub(crate) workspaces: Vec>, + pub(crate) force_crate_graph_reload: bool, +} + // Enforces drop order pub(crate) struct Handle { pub(crate) handle: H, @@ -146,8 +151,7 @@ pub(crate) struct GlobalState { pub(crate) detached_files: FxHashSet, // op queues - pub(crate) fetch_workspaces_queue: - OpQueue>, bool)>>, + pub(crate) fetch_workspaces_queue: OpQueue, pub(crate) fetch_build_data_queue: OpQueue<(), (Arc>, Vec>)>, pub(crate) fetch_proc_macros_queue: OpQueue, bool>, @@ -502,7 +506,7 @@ impl GlobalState { mem_docs: self.mem_docs.clone(), semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache), proc_macros_loaded: !self.config.expand_proc_macros() - || *self.fetch_proc_macros_queue.last_op_result(), + || self.fetch_proc_macros_queue.last_op_result().copied().unwrap_or(false), flycheck: self.flycheck.clone(), } } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 78a302b1aa..ef28972056 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -22,7 +22,9 @@ use crate::{ diagnostics::{fetch_native_diagnostics, DiagnosticsGeneration, NativeDiagnosticsFetchKind}, discover::{DiscoverArgument, DiscoverCommand, DiscoverProjectMessage}, flycheck::{self, FlycheckMessage}, - global_state::{file_id_to_url, url_to_file_id, FetchWorkspaceRequest, GlobalState}, + global_state::{ + file_id_to_url, url_to_file_id, FetchWorkspaceRequest, FetchWorkspaceResponse, GlobalState, + }, hack_recover_crate_name, handlers::dispatch::{NotificationDispatcher, RequestDispatcher}, lsp::{ @@ -695,9 +697,9 @@ impl GlobalState { let (state, msg) = match progress { ProjectWorkspaceProgress::Begin => (Progress::Begin, None), ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)), - ProjectWorkspaceProgress::End(workspaces, force_reload_crate_graph) => { - self.fetch_workspaces_queue - .op_completed(Some((workspaces, force_reload_crate_graph))); + ProjectWorkspaceProgress::End(workspaces, force_crate_graph_reload) => { + let resp = FetchWorkspaceResponse { workspaces, force_crate_graph_reload }; + self.fetch_workspaces_queue.op_completed(resp); if let Err(e) = self.fetch_workspace_error() { error!("FetchWorkspaceError: {e}"); } diff --git a/crates/rust-analyzer/src/op_queue.rs b/crates/rust-analyzer/src/op_queue.rs index 5c4c858e15..123f20605a 100644 --- a/crates/rust-analyzer/src/op_queue.rs +++ b/crates/rust-analyzer/src/op_queue.rs @@ -27,12 +27,12 @@ pub(crate) type Cause = String; pub(crate) struct OpQueue { op_requested: Option<(Cause, Args)>, op_in_progress: bool, - last_op_result: Output, + last_op_result: Option, } -impl Default for OpQueue { +impl Default for OpQueue { fn default() -> Self { - Self { op_requested: None, op_in_progress: false, last_op_result: Default::default() } + Self { op_requested: None, op_in_progress: false, last_op_result: None } } } @@ -56,12 +56,12 @@ impl OpQueue { pub(crate) fn op_completed(&mut self, result: Output) { assert!(self.op_in_progress); self.op_in_progress = false; - self.last_op_result = result; + self.last_op_result = Some(result); } /// Get the result of the last operation. - pub(crate) fn last_op_result(&self) -> &Output { - &self.last_op_result + pub(crate) fn last_op_result(&self) -> Option<&Output> { + self.last_op_result.as_ref() } // Is there an operation that has started, but hasn't yet finished? diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 7a1782e565..60ee0295a3 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -33,7 +33,7 @@ use vfs::{AbsPath, AbsPathBuf, ChangeKind}; use crate::{ config::{Config, FilesWatcher, LinkedProject}, flycheck::{FlycheckConfig, FlycheckHandle}, - global_state::{FetchWorkspaceRequest, GlobalState}, + global_state::{FetchWorkspaceRequest, FetchWorkspaceResponse, GlobalState}, lsp_ext, main_loop::{DiscoverProjectParam, Task}, op_queue::Cause, @@ -448,15 +448,15 @@ impl GlobalState { let _p = tracing::info_span!("GlobalState::switch_workspaces").entered(); tracing::info!(%cause, "will switch workspaces"); - let Some((workspaces, force_reload_crate_graph)) = + let Some(FetchWorkspaceResponse { workspaces, force_crate_graph_reload }) = self.fetch_workspaces_queue.last_op_result() else { return; }; - info!(%cause, ?force_reload_crate_graph); + info!(%cause, ?force_crate_graph_reload); if self.fetch_workspace_error().is_err() && !self.workspaces.is_empty() { - if *force_reload_crate_graph { + if *force_crate_graph_reload { self.recreate_crate_graph(cause); } // It only makes sense to switch to a partially broken workspace @@ -474,8 +474,12 @@ impl GlobalState { .all(|(l, r)| l.eq_ignore_build_data(r)); if same_workspaces { - let (workspaces, build_scripts) = self.fetch_build_data_queue.last_op_result(); - if Arc::ptr_eq(workspaces, &self.workspaces) { + let (workspaces, build_scripts) = match self.fetch_build_data_queue.last_op_result() { + Some((workspaces, build_scripts)) => (workspaces.clone(), build_scripts.as_slice()), + None => (Default::default(), Default::default()), + }; + + if Arc::ptr_eq(&workspaces, &self.workspaces) { info!("set build scripts to workspaces"); let workspaces = workspaces @@ -492,7 +496,7 @@ impl GlobalState { self.workspaces = Arc::new(workspaces); } else { info!("build scripts do not match the version of the active workspace"); - if *force_reload_crate_graph { + if *force_crate_graph_reload { self.recreate_crate_graph(cause); } @@ -739,14 +743,16 @@ impl GlobalState { pub(super) fn fetch_workspace_error(&self) -> Result<(), String> { let mut buf = String::new(); - let Some((last_op_result, _)) = self.fetch_workspaces_queue.last_op_result() else { + let Some(FetchWorkspaceResponse { workspaces, .. }) = + self.fetch_workspaces_queue.last_op_result() + else { return Ok(()); }; - if last_op_result.is_empty() && self.config.discover_workspace_config().is_none() { + if workspaces.is_empty() && self.config.discover_workspace_config().is_none() { stdx::format_to!(buf, "rust-analyzer failed to fetch workspace"); } else { - for ws in last_op_result { + for ws in workspaces { if let Err(err) = ws { stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err); } @@ -763,7 +769,11 @@ impl GlobalState { pub(super) fn fetch_build_data_error(&self) -> Result<(), String> { let mut buf = String::new(); - for ws in &self.fetch_build_data_queue.last_op_result().1 { + let Some((_, ws)) = &self.fetch_build_data_queue.last_op_result() else { + return Ok(()); + }; + + for ws in ws { match ws { Ok(data) => { if let Some(stderr) = data.error() {