Skip to content

Commit 4414071

Browse files
bors[bot]matklad
andauthored
Merge #8355
8355: internal: do not drop errors from cargo metadata/check r=matklad a=matklad Work towards #3155 Co-authored-by: Aleksey Kladov <[email protected]>
2 parents 002e72a + ad02bfe commit 4414071

File tree

12 files changed

+272
-236
lines changed

12 files changed

+272
-236
lines changed

crates/project_model/src/build_data.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub struct BuildDataCollector {
5252
configs: FxHashMap<AbsPathBuf, BuildDataConfig>,
5353
}
5454

55-
#[derive(Debug, Default, PartialEq, Eq)]
55+
#[derive(Debug, Default, PartialEq, Eq, Clone)]
5656
pub struct BuildDataResult {
5757
data: FxHashMap<AbsPathBuf, BuildDataMap>,
5858
}

crates/rust-analyzer/src/config.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,8 +445,8 @@ impl Config {
445445
pub fn hover_actions(&self) -> bool {
446446
self.experimental("hoverActions")
447447
}
448-
pub fn status_notification(&self) -> bool {
449-
self.experimental("statusNotification")
448+
pub fn server_status_notification(&self) -> bool {
449+
self.experimental("serverStatusNotification")
450450
}
451451

452452
pub fn publish_diagnostics(&self) -> bool {

crates/rust-analyzer/src/global_state.rs

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::{
2323
document::DocumentData,
2424
from_proto,
2525
line_index::{LineEndings, LineIndex},
26+
lsp_ext,
2627
main_loop::Task,
2728
op_queue::OpQueue,
2829
reload::SourceRootConfig,
@@ -32,20 +33,6 @@ use crate::{
3233
Result,
3334
};
3435

35-
#[derive(Eq, PartialEq, Copy, Clone)]
36-
pub(crate) enum Status {
37-
Loading,
38-
Ready { partial: bool },
39-
Invalid,
40-
NeedsReload,
41-
}
42-
43-
impl Default for Status {
44-
fn default() -> Self {
45-
Status::Loading
46-
}
47-
}
48-
4936
// Enforces drop order
5037
pub(crate) struct Handle<H, C> {
5138
pub(crate) handle: H,
@@ -67,26 +54,36 @@ pub(crate) struct GlobalState {
6754
req_queue: ReqQueue,
6855
pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
6956
pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
70-
pub(crate) vfs_config_version: u32,
71-
pub(crate) flycheck: Vec<FlycheckHandle>,
72-
pub(crate) flycheck_sender: Sender<flycheck::Message>,
73-
pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
7457
pub(crate) config: Arc<Config>,
7558
pub(crate) analysis_host: AnalysisHost,
7659
pub(crate) diagnostics: DiagnosticCollection,
7760
pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>,
7861
pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
79-
pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
8062
pub(crate) shutdown_requested: bool,
81-
pub(crate) status: Status,
63+
pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
8264
pub(crate) source_root_config: SourceRootConfig,
8365
pub(crate) proc_macro_client: Option<ProcMacroClient>,
8466

85-
pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
86-
pub(crate) fetch_workspaces_queue: OpQueue<(), ()>,
67+
pub(crate) flycheck: Vec<FlycheckHandle>,
68+
pub(crate) flycheck_sender: Sender<flycheck::Message>,
69+
pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
8770

71+
pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
72+
pub(crate) vfs_config_version: u32,
73+
pub(crate) vfs_progress_config_version: u32,
74+
pub(crate) vfs_progress_n_total: usize,
75+
pub(crate) vfs_progress_n_done: usize,
76+
77+
/// For both `workspaces` and `workspace_build_data`, the field stores the
78+
/// data we actually use, while the `OpQueue` stores the result of the last
79+
/// fetch.
80+
///
81+
/// If the fetch (partially) fails, we do not update the values.
82+
pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
83+
pub(crate) fetch_workspaces_queue: OpQueue<(), Vec<anyhow::Result<ProjectWorkspace>>>,
8884
pub(crate) workspace_build_data: Option<BuildDataResult>,
89-
pub(crate) fetch_build_data_queue: OpQueue<BuildDataCollector, ()>,
85+
pub(crate) fetch_build_data_queue:
86+
OpQueue<BuildDataCollector, Option<anyhow::Result<BuildDataResult>>>,
9087

9188
latest_requests: Arc<RwLock<LatestRequests>>,
9289
}
@@ -124,25 +121,32 @@ impl GlobalState {
124121
GlobalState {
125122
sender,
126123
req_queue: ReqQueue::default(),
127-
vfs_config_version: 0,
128124
task_pool,
129125
loader,
130-
flycheck: Vec::new(),
131-
flycheck_sender,
132-
flycheck_receiver,
133126
config: Arc::new(config),
134127
analysis_host,
135128
diagnostics: Default::default(),
136129
mem_docs: FxHashMap::default(),
137130
semantic_tokens_cache: Arc::new(Default::default()),
138-
vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
139131
shutdown_requested: false,
140-
status: Status::default(),
132+
last_reported_status: None,
141133
source_root_config: SourceRootConfig::default(),
142134
proc_macro_client: None,
135+
136+
flycheck: Vec::new(),
137+
flycheck_sender,
138+
flycheck_receiver,
139+
140+
vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
141+
vfs_config_version: 0,
142+
vfs_progress_config_version: 0,
143+
vfs_progress_n_total: 0,
144+
vfs_progress_n_done: 0,
145+
143146
workspaces: Arc::new(Vec::new()),
144147
fetch_workspaces_queue: OpQueue::default(),
145148
workspace_build_data: None,
149+
146150
fetch_build_data_queue: OpQueue::default(),
147151
latest_requests: Default::default(),
148152
}

crates/rust-analyzer/src/lsp_ext.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -241,26 +241,26 @@ pub struct SsrParams {
241241
pub selections: Vec<lsp_types::Range>,
242242
}
243243

244-
pub enum StatusNotification {}
244+
pub enum ServerStatusNotification {}
245245

246-
#[derive(Serialize, Deserialize)]
247-
#[serde(rename_all = "camelCase")]
248-
pub enum Status {
249-
Loading,
250-
ReadyPartial,
251-
Ready,
252-
NeedsReload,
253-
Invalid,
246+
impl Notification for ServerStatusNotification {
247+
type Params = ServerStatusParams;
248+
const METHOD: &'static str = "experimental/serverStatus";
254249
}
255250

256-
#[derive(Deserialize, Serialize)]
257-
pub struct StatusParams {
258-
pub status: Status,
251+
#[derive(Deserialize, Serialize, PartialEq, Eq, Clone)]
252+
pub struct ServerStatusParams {
253+
pub health: Health,
254+
pub quiescent: bool,
255+
pub message: Option<String>,
259256
}
260257

261-
impl Notification for StatusNotification {
262-
type Params = StatusParams;
263-
const METHOD: &'static str = "rust-analyzer/status";
258+
#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
259+
#[serde(rename_all = "camelCase")]
260+
pub enum Health {
261+
Ok,
262+
Warning,
263+
Error,
264264
}
265265

266266
pub enum CodeActionRequest {}

crates/rust-analyzer/src/main_loop.rs

Lines changed: 59 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! requests/replies and notifications back to the client.
33
use std::{
44
env, fmt,
5+
sync::Arc,
56
time::{Duration, Instant},
67
};
78

@@ -12,14 +13,15 @@ use ide::{Canceled, FileId};
1213
use ide_db::base_db::VfsPath;
1314
use lsp_server::{Connection, Notification, Request, Response};
1415
use lsp_types::notification::Notification as _;
16+
use project_model::BuildDataCollector;
1517
use vfs::ChangeKind;
1618

1719
use crate::{
1820
config::Config,
1921
dispatch::{NotificationDispatcher, RequestDispatcher},
2022
document::DocumentData,
2123
from_proto,
22-
global_state::{file_id_to_url, url_to_file_id, GlobalState, Status},
24+
global_state::{file_id_to_url, url_to_file_id, GlobalState},
2325
handlers, lsp_ext,
2426
lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress},
2527
reload::{BuildDataProgress, ProjectWorkspaceProgress},
@@ -187,7 +189,7 @@ impl GlobalState {
187189
log::info!("task queue len: {}", task_queue_len);
188190
}
189191

190-
let mut new_status = self.status;
192+
let was_quiescent = self.is_quiescent();
191193
match event {
192194
Event::Lsp(msg) => match msg {
193195
lsp_server::Message::Request(req) => self.on_request(loop_start, req)?,
@@ -227,11 +229,24 @@ impl GlobalState {
227229
(Progress::Report, Some(msg))
228230
}
229231
ProjectWorkspaceProgress::End(workspaces) => {
230-
self.fetch_workspaces_completed();
231-
self.switch_workspaces(workspaces, None);
232+
self.fetch_workspaces_completed(workspaces);
233+
234+
let old = Arc::clone(&self.workspaces);
235+
self.switch_workspaces();
236+
let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces);
237+
238+
if self.config.run_build_scripts() && workspaces_updated {
239+
let mut collector = BuildDataCollector::default();
240+
for ws in self.workspaces.iter() {
241+
ws.collect_build_data_configs(&mut collector);
242+
}
243+
self.fetch_build_data_request(collector)
244+
}
245+
232246
(Progress::End, None)
233247
}
234248
};
249+
235250
self.report_progress("fetching", state, msg, None);
236251
}
237252
Task::FetchBuildData(progress) => {
@@ -240,19 +255,21 @@ impl GlobalState {
240255
BuildDataProgress::Report(msg) => {
241256
(Some(Progress::Report), Some(msg))
242257
}
243-
BuildDataProgress::End(collector) => {
244-
self.fetch_build_data_completed();
245-
let workspaces =
246-
(*self.workspaces).clone().into_iter().map(Ok).collect();
247-
self.switch_workspaces(workspaces, Some(collector));
258+
BuildDataProgress::End(build_data_result) => {
259+
self.fetch_build_data_completed(build_data_result);
260+
261+
self.switch_workspaces();
262+
248263
(Some(Progress::End), None)
249264
}
250265
};
266+
251267
if let Some(state) = state {
252268
self.report_progress("loading", state, msg, None);
253269
}
254270
}
255271
}
272+
256273
// Coalesce multiple task events into one loop turn
257274
task = match self.task_pool.receiver.try_recv() {
258275
Ok(task) => task,
@@ -298,30 +315,25 @@ impl GlobalState {
298315
}
299316
vfs::loader::Message::Progress { n_total, n_done, config_version } => {
300317
always!(config_version <= self.vfs_config_version);
301-
if n_total == 0 {
302-
new_status = Status::Invalid;
318+
319+
self.vfs_progress_config_version = config_version;
320+
self.vfs_progress_n_total = n_total;
321+
self.vfs_progress_n_done = n_done;
322+
323+
let state = if n_done == 0 {
324+
Progress::Begin
325+
} else if n_done < n_total {
326+
Progress::Report
303327
} else {
304-
let state = if n_done == 0 {
305-
new_status = Status::Loading;
306-
Progress::Begin
307-
} else if n_done < n_total {
308-
Progress::Report
309-
} else {
310-
assert_eq!(n_done, n_total);
311-
new_status = Status::Ready {
312-
partial: self.config.run_build_scripts()
313-
&& self.workspace_build_data.is_none()
314-
|| config_version < self.vfs_config_version,
315-
};
316-
Progress::End
317-
};
318-
self.report_progress(
319-
"roots scanned",
320-
state,
321-
Some(format!("{}/{}", n_done, n_total)),
322-
Some(Progress::fraction(n_done, n_total)),
323-
)
324-
}
328+
assert_eq!(n_done, n_total);
329+
Progress::End
330+
};
331+
self.report_progress(
332+
"roots scanned",
333+
state,
334+
Some(format!("{}/{}", n_done, n_total)),
335+
Some(Progress::fraction(n_done, n_total)),
336+
)
325337
}
326338
}
327339
// Coalesce many VFS event into a single loop turn
@@ -397,18 +409,14 @@ impl GlobalState {
397409
}
398410

399411
let state_changed = self.process_changes();
400-
let prev_status = self.status;
401-
if prev_status != new_status {
402-
self.transition(new_status);
403-
}
404-
let is_ready = matches!(self.status, Status::Ready { .. });
405-
if prev_status == Status::Loading && is_ready {
412+
413+
if self.is_quiescent() && !was_quiescent {
406414
for flycheck in &self.flycheck {
407415
flycheck.update();
408416
}
409417
}
410418

411-
if is_ready && (state_changed || prev_status == Status::Loading) {
419+
if self.is_quiescent() && (!was_quiescent || state_changed) {
412420
self.update_file_notifications_on_threadpool();
413421

414422
// Refresh semantic tokens if the client supports it.
@@ -437,9 +445,13 @@ impl GlobalState {
437445
}
438446
}
439447

440-
self.fetch_workspaces_if_needed();
448+
if self.config.cargo_autoreload() {
449+
self.fetch_workspaces_if_needed();
450+
}
441451
self.fetch_build_data_if_needed();
442452

453+
self.report_new_status_if_needed();
454+
443455
let loop_duration = loop_start.elapsed();
444456
if loop_duration > Duration::from_millis(100) {
445457
log::warn!("overly long loop turn: {:?}", loop_duration);
@@ -466,7 +478,8 @@ impl GlobalState {
466478
return Ok(());
467479
}
468480

469-
if self.status == Status::Loading && req.method != "shutdown" {
481+
// Avoid flashing a bunch of unresolved references during initial load.
482+
if self.workspaces.is_empty() && !self.is_quiescent() {
470483
self.respond(lsp_server::Response::new_err(
471484
req.id,
472485
// FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion)
@@ -477,7 +490,11 @@ impl GlobalState {
477490
}
478491

479492
RequestDispatcher { req: Some(req), global_state: self }
480-
.on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces_request()))?
493+
.on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| {
494+
s.fetch_workspaces_request();
495+
s.fetch_workspaces_if_needed();
496+
Ok(())
497+
})?
481498
.on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))?
482499
.on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))?
483500
.on_sync::<lsp_types::request::Shutdown>(|s, ()| {

0 commit comments

Comments
 (0)