diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 5de08313f418..ec0723c3f8c3 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -1625,7 +1625,7 @@ impl<'db> Evaluator<'db> { }; match target_ty { rustc_type_ir::FloatTy::F32 => Owned((value as f32).to_le_bytes().to_vec()), - rustc_type_ir::FloatTy::F64 => Owned((value as f64).to_le_bytes().to_vec()), + rustc_type_ir::FloatTy::F64 => Owned(value.to_le_bytes().to_vec()), rustc_type_ir::FloatTy::F16 | rustc_type_ir::FloatTy::F128 => { not_supported!("unstable floating point type f16 and f128"); } diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index afd4162de622..5dfa854e4ef5 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -52,6 +52,7 @@ use crate::{ pub(crate) struct FetchWorkspaceRequest { pub(crate) path: Option, pub(crate) force_crate_graph_reload: bool, + pub(crate) config_generation: u64, } pub(crate) struct FetchWorkspaceResponse { @@ -102,6 +103,8 @@ pub(crate) struct GlobalState { // status pub(crate) shutdown_requested: bool, pub(crate) last_reported_status: lsp_ext::ServerStatusParams, + pub(crate) config_generation: u64, + pub(crate) last_workspace_fetch_generation: Option, // proc macros pub(crate) proc_macro_clients: Arc<[Option>]>, @@ -277,6 +280,8 @@ impl GlobalState { quiescent: true, message: None, }, + config_generation: 0, + last_workspace_fetch_generation: None, source_root_config: SourceRootConfig::default(), local_roots_parent_map: Arc::new(FxHashMap::default()), config_errors: Default::default(), @@ -721,7 +726,11 @@ impl GlobalState { self.fetch_ws_receiver = Some(( crossbeam_channel::after(Duration::from_millis(100)), - FetchWorkspaceRequest { path: Some(path), force_crate_graph_reload }, + FetchWorkspaceRequest { + path: Some(path), + force_crate_graph_reload, + config_generation: self.config_generation, + }, )); } diff --git a/crates/rust-analyzer/src/handlers/notification.rs b/crates/rust-analyzer/src/handlers/notification.rs index 138310b78f62..a0ee8bd66481 100644 --- a/crates/rust-analyzer/src/handlers/notification.rs +++ b/crates/rust-analyzer/src/handlers/notification.rs @@ -183,6 +183,7 @@ pub(crate) fn handle_did_save_text_document( FetchWorkspaceRequest { path: Some(path.to_owned()), force_crate_graph_reload: false, + config_generation: state.config_generation, }, ); } else if state.detached_files.contains(path) { @@ -191,6 +192,7 @@ pub(crate) fn handle_did_save_text_document( FetchWorkspaceRequest { path: Some(path.to_owned()), force_crate_graph_reload: false, + config_generation: state.config_generation, }, ); } @@ -278,7 +280,11 @@ pub(crate) fn handle_did_change_workspace_folders( if !config.has_linked_projects() && config.detached_files().is_empty() { config.rediscover_workspaces(); - let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false }; + let req = FetchWorkspaceRequest { + path: None, + force_crate_graph_reload: false, + config_generation: state.config_generation, + }; state.fetch_workspaces_queue.request_op("client workspaces changed".to_owned(), req); } diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs index ad07da77597d..ce8922f549be 100644 --- a/crates/rust-analyzer/src/handlers/request.rs +++ b/crates/rust-analyzer/src/handlers/request.rs @@ -61,7 +61,11 @@ pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> anyhow: state.proc_macro_clients = Arc::from_iter([]); state.build_deps_changed = false; - let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false }; + let req = FetchWorkspaceRequest { + path: None, + force_crate_graph_reload: false, + config_generation: state.config_generation, + }; state.fetch_workspaces_queue.request_op("reload workspace request".to_owned(), req); Ok(()) } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 62a3b3a17bdf..99308756f508 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -192,12 +192,18 @@ impl GlobalState { if self.config.discover_workspace_config().is_none() { self.fetch_workspaces_queue.request_op( "startup".to_owned(), - FetchWorkspaceRequest { path: None, force_crate_graph_reload: false }, + FetchWorkspaceRequest { + path: None, + force_crate_graph_reload: false, + config_generation: self.config_generation, + }, ); - if let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) = - self.fetch_workspaces_queue.should_start_op() + if let Some(( + cause, + FetchWorkspaceRequest { path, force_crate_graph_reload, config_generation }, + )) = self.fetch_workspaces_queue.should_start_op() { - self.fetch_workspaces(cause, path, force_crate_graph_reload); + self.fetch_workspaces(cause, path, force_crate_graph_reload, config_generation); } } @@ -564,10 +570,12 @@ impl GlobalState { if (self.config.cargo_autoreload_config(None) || self.config.discover_workspace_config().is_some()) - && let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) = - self.fetch_workspaces_queue.should_start_op() + && let Some(( + cause, + FetchWorkspaceRequest { path, force_crate_graph_reload, config_generation }, + )) = self.fetch_workspaces_queue.should_start_op() { - self.fetch_workspaces(cause, path, force_crate_graph_reload); + self.fetch_workspaces(cause, path, force_crate_graph_reload, config_generation); } if !self.fetch_workspaces_queue.op_in_progress() { @@ -809,9 +817,14 @@ impl GlobalState { let (state, msg) = match progress { ProjectWorkspaceProgress::Begin => (Progress::Begin, None), ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)), - ProjectWorkspaceProgress::End(workspaces, force_crate_graph_reload) => { + ProjectWorkspaceProgress::End( + workspaces, + force_crate_graph_reload, + config_generation, + ) => { let resp = FetchWorkspaceResponse { workspaces, force_crate_graph_reload }; self.fetch_workspaces_queue.op_completed(resp); + self.last_workspace_fetch_generation = Some(config_generation); if let Err(e) = self.fetch_workspace_error() { error!("FetchWorkspaceError: {e}"); } diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 83f4a19b39fa..4d45a7db5591 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -44,11 +44,19 @@ use crate::{ }; use tracing::{debug, info}; +fn should_warn_missing_workspace( + has_projects: bool, + has_detached_files: bool, + fetch_done_for_current_config: bool, +) -> bool { + fetch_done_for_current_config && !has_projects && !has_detached_files +} + #[derive(Debug)] pub(crate) enum ProjectWorkspaceProgress { Begin, Report(String), - End(Vec>, bool), + End(Vec>, bool, u64), } #[derive(Debug)] @@ -91,6 +99,7 @@ impl GlobalState { pub(crate) fn update_configuration(&mut self, config: Config) { let _p = tracing::info_span!("GlobalState::update_configuration").entered(); + self.config_generation = self.config_generation.wrapping_add(1); let old_config = mem::replace(&mut self.config, Arc::new(config)); if self.config.lru_parse_query_capacity() != old_config.lru_parse_query_capacity() { self.analysis_host.update_lru_capacity(self.config.lru_parse_query_capacity()); @@ -103,7 +112,11 @@ impl GlobalState { if self.config.linked_or_discovered_projects() != old_config.linked_or_discovered_projects() { - let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false }; + let req = FetchWorkspaceRequest { + path: None, + force_crate_graph_reload: false, + config_generation: self.config_generation, + }; self.fetch_workspaces_queue.request_op("discovered projects changed".to_owned(), req) } else if self.config.flycheck(None) != old_config.flycheck(None) { self.reload_flycheck(); @@ -119,12 +132,20 @@ impl GlobalState { } if self.config.cargo(None) != old_config.cargo(None) { - let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false }; + let req = FetchWorkspaceRequest { + path: None, + force_crate_graph_reload: false, + config_generation: self.config_generation, + }; self.fetch_workspaces_queue.request_op("cargo config changed".to_owned(), req) } if self.config.cfg_set_test(None) != old_config.cfg_set_test(None) { - let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false }; + let req = FetchWorkspaceRequest { + path: None, + force_crate_graph_reload: false, + config_generation: self.config_generation, + }; self.fetch_workspaces_queue.request_op("cfg_set_test config changed".to_owned(), req) } } @@ -169,9 +190,11 @@ impl GlobalState { message.push('\n'); } - if self.config.linked_or_discovered_projects().is_empty() - && self.config.detached_files().is_empty() - { + if should_warn_missing_workspace( + self.config.linked_or_discovered_projects().is_empty(), + self.config.detached_files().is_empty(), + self.last_workspace_fetch_generation == Some(self.config_generation), + ) { status.health |= lsp_ext::Health::Warning; message.push_str("Failed to discover workspace.\n"); message.push_str("Consider adding the `Cargo.toml` of the workspace to the [`linkedProjects`](https://rust-analyzer.github.io/book/configuration.html#linkedProjects) setting.\n\n"); @@ -284,6 +307,7 @@ impl GlobalState { cause: Cause, path: Option, force_crate_graph_reload: bool, + config_generation: u64, ) { info!(%cause, "will fetch workspaces"); @@ -380,6 +404,7 @@ impl GlobalState { .send(Task::FetchWorkspace(ProjectWorkspaceProgress::End( workspaces, force_crate_graph_reload, + config_generation, ))) .unwrap(); } @@ -472,7 +497,7 @@ impl GlobalState { let _p = tracing::info_span!("GlobalState::switch_workspaces").entered(); tracing::info!(%cause, "will switch workspaces"); - let Some(FetchWorkspaceResponse { workspaces, force_crate_graph_reload }) = + let Some(FetchWorkspaceResponse { workspaces, force_crate_graph_reload, .. }) = self.fetch_workspaces_queue.last_op_result() else { return; @@ -1038,3 +1063,16 @@ fn eq_ignore_underscore(s1: &str, s2: &str) -> bool { c1 == c2 || (c1_underscore && c2_underscore) }) } + +#[cfg(test)] +mod tests { + use super::should_warn_missing_workspace; + + #[test] + fn missing_workspace_warning_is_gated_by_fetch_completion() { + assert!(!should_warn_missing_workspace(false, false, false)); + assert!(should_warn_missing_workspace(false, false, true)); + assert!(!should_warn_missing_workspace(true, false, true)); + assert!(!should_warn_missing_workspace(false, true, true)); + } +}