Skip to content

Commit

Permalink
Merge #8355
Browse files Browse the repository at this point in the history
8355: internal: do not drop errors from cargo metadata/check r=matklad a=matklad

Work towards #3155

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
  • Loading branch information
bors[bot] and matklad committed Apr 6, 2021
2 parents 002e72a + 8fe20b1 commit 0d49e40
Show file tree
Hide file tree
Showing 12 changed files with 272 additions and 236 deletions.
2 changes: 1 addition & 1 deletion crates/project_model/src/build_data.rs
Expand Up @@ -52,7 +52,7 @@ pub struct BuildDataCollector {
configs: FxHashMap<AbsPathBuf, BuildDataConfig>,
}

#[derive(Debug, Default, PartialEq, Eq)]
#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct BuildDataResult {
data: FxHashMap<AbsPathBuf, BuildDataMap>,
}
Expand Down
4 changes: 2 additions & 2 deletions crates/rust-analyzer/src/config.rs
Expand Up @@ -445,8 +445,8 @@ impl Config {
pub fn hover_actions(&self) -> bool {
self.experimental("hoverActions")
}
pub fn status_notification(&self) -> bool {
self.experimental("statusNotification")
pub fn server_status_notification(&self) -> bool {
self.experimental("serverStatusNotification")
}

pub fn publish_diagnostics(&self) -> bool {
Expand Down
62 changes: 33 additions & 29 deletions crates/rust-analyzer/src/global_state.rs
Expand Up @@ -23,6 +23,7 @@ use crate::{
document::DocumentData,
from_proto,
line_index::{LineEndings, LineIndex},
lsp_ext,
main_loop::Task,
op_queue::OpQueue,
reload::SourceRootConfig,
Expand All @@ -32,20 +33,6 @@ use crate::{
Result,
};

#[derive(Eq, PartialEq, Copy, Clone)]
pub(crate) enum Status {
Loading,
Ready { partial: bool },
Invalid,
NeedsReload,
}

impl Default for Status {
fn default() -> Self {
Status::Loading
}
}

// Enforces drop order
pub(crate) struct Handle<H, C> {
pub(crate) handle: H,
Expand All @@ -67,26 +54,36 @@ pub(crate) struct GlobalState {
req_queue: ReqQueue,
pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
pub(crate) vfs_config_version: u32,
pub(crate) flycheck: Vec<FlycheckHandle>,
pub(crate) flycheck_sender: Sender<flycheck::Message>,
pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
pub(crate) config: Arc<Config>,
pub(crate) analysis_host: AnalysisHost,
pub(crate) diagnostics: DiagnosticCollection,
pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>,
pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
pub(crate) shutdown_requested: bool,
pub(crate) status: Status,
pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
pub(crate) source_root_config: SourceRootConfig,
pub(crate) proc_macro_client: Option<ProcMacroClient>,

pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
pub(crate) fetch_workspaces_queue: OpQueue<(), ()>,
pub(crate) flycheck: Vec<FlycheckHandle>,
pub(crate) flycheck_sender: Sender<flycheck::Message>,
pub(crate) flycheck_receiver: Receiver<flycheck::Message>,

pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
pub(crate) vfs_config_version: u32,
pub(crate) vfs_progress_config_version: u32,
pub(crate) vfs_progress_n_total: usize,
pub(crate) vfs_progress_n_done: usize,

/// For both `workspaces` and `workspace_build_data`, the field stores the
/// data we actually use, while the `OpQueue` stores the result of the last
/// fetch.
///
/// If the fetch (partially) fails, we do not update the values.
pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
pub(crate) fetch_workspaces_queue: OpQueue<(), Vec<anyhow::Result<ProjectWorkspace>>>,
pub(crate) workspace_build_data: Option<BuildDataResult>,
pub(crate) fetch_build_data_queue: OpQueue<BuildDataCollector, ()>,
pub(crate) fetch_build_data_queue:
OpQueue<BuildDataCollector, Option<anyhow::Result<BuildDataResult>>>,

latest_requests: Arc<RwLock<LatestRequests>>,
}
Expand Down Expand Up @@ -124,25 +121,32 @@ impl GlobalState {
GlobalState {
sender,
req_queue: ReqQueue::default(),
vfs_config_version: 0,
task_pool,
loader,
flycheck: Vec::new(),
flycheck_sender,
flycheck_receiver,
config: Arc::new(config),
analysis_host,
diagnostics: Default::default(),
mem_docs: FxHashMap::default(),
semantic_tokens_cache: Arc::new(Default::default()),
vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
shutdown_requested: false,
status: Status::default(),
last_reported_status: None,
source_root_config: SourceRootConfig::default(),
proc_macro_client: None,

flycheck: Vec::new(),
flycheck_sender,
flycheck_receiver,

vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
vfs_config_version: 0,
vfs_progress_config_version: 0,
vfs_progress_n_total: 0,
vfs_progress_n_done: 0,

workspaces: Arc::new(Vec::new()),
fetch_workspaces_queue: OpQueue::default(),
workspace_build_data: None,

fetch_build_data_queue: OpQueue::default(),
latest_requests: Default::default(),
}
Expand Down
30 changes: 15 additions & 15 deletions crates/rust-analyzer/src/lsp_ext.rs
Expand Up @@ -241,26 +241,26 @@ pub struct SsrParams {
pub selections: Vec<lsp_types::Range>,
}

pub enum StatusNotification {}
pub enum ServerStatusNotification {}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum Status {
Loading,
ReadyPartial,
Ready,
NeedsReload,
Invalid,
impl Notification for ServerStatusNotification {
type Params = ServerStatusParams;
const METHOD: &'static str = "experimental/serverStatus";
}

#[derive(Deserialize, Serialize)]
pub struct StatusParams {
pub status: Status,
#[derive(Deserialize, Serialize, PartialEq, Eq, Clone)]
pub struct ServerStatusParams {
pub health: Health,
pub quiescent: bool,
pub message: Option<String>,
}

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

pub enum CodeActionRequest {}
Expand Down
101 changes: 59 additions & 42 deletions crates/rust-analyzer/src/main_loop.rs
Expand Up @@ -2,6 +2,7 @@
//! requests/replies and notifications back to the client.
use std::{
env, fmt,
sync::Arc,
time::{Duration, Instant},
};

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

use crate::{
config::Config,
dispatch::{NotificationDispatcher, RequestDispatcher},
document::DocumentData,
from_proto,
global_state::{file_id_to_url, url_to_file_id, GlobalState, Status},
global_state::{file_id_to_url, url_to_file_id, GlobalState},
handlers, lsp_ext,
lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress},
reload::{BuildDataProgress, ProjectWorkspaceProgress},
Expand Down Expand Up @@ -187,7 +189,7 @@ impl GlobalState {
log::info!("task queue len: {}", task_queue_len);
}

let mut new_status = self.status;
let was_quiescent = self.is_quiescent();
match event {
Event::Lsp(msg) => match msg {
lsp_server::Message::Request(req) => self.on_request(loop_start, req)?,
Expand Down Expand Up @@ -227,11 +229,24 @@ impl GlobalState {
(Progress::Report, Some(msg))
}
ProjectWorkspaceProgress::End(workspaces) => {
self.fetch_workspaces_completed();
self.switch_workspaces(workspaces, None);
self.fetch_workspaces_completed(workspaces);

let old = Arc::clone(&self.workspaces);
self.switch_workspaces();
let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces);

if self.config.run_build_scripts() && workspaces_updated {
let mut collector = BuildDataCollector::default();
for ws in self.workspaces.iter() {
ws.collect_build_data_configs(&mut collector);
}
self.fetch_build_data_request(collector)
}

(Progress::End, None)
}
};

self.report_progress("fetching", state, msg, None);
}
Task::FetchBuildData(progress) => {
Expand All @@ -240,19 +255,21 @@ impl GlobalState {
BuildDataProgress::Report(msg) => {
(Some(Progress::Report), Some(msg))
}
BuildDataProgress::End(collector) => {
self.fetch_build_data_completed();
let workspaces =
(*self.workspaces).clone().into_iter().map(Ok).collect();
self.switch_workspaces(workspaces, Some(collector));
BuildDataProgress::End(build_data_result) => {
self.fetch_build_data_completed(build_data_result);

self.switch_workspaces();

(Some(Progress::End), None)
}
};

if let Some(state) = state {
self.report_progress("loading", state, msg, None);
}
}
}

// Coalesce multiple task events into one loop turn
task = match self.task_pool.receiver.try_recv() {
Ok(task) => task,
Expand Down Expand Up @@ -298,30 +315,25 @@ impl GlobalState {
}
vfs::loader::Message::Progress { n_total, n_done, config_version } => {
always!(config_version <= self.vfs_config_version);
if n_total == 0 {
new_status = Status::Invalid;

self.vfs_progress_config_version = config_version;
self.vfs_progress_n_total = n_total;
self.vfs_progress_n_done = n_done;

let state = if n_done == 0 {
Progress::Begin
} else if n_done < n_total {
Progress::Report
} else {
let state = if n_done == 0 {
new_status = Status::Loading;
Progress::Begin
} else if n_done < n_total {
Progress::Report
} else {
assert_eq!(n_done, n_total);
new_status = Status::Ready {
partial: self.config.run_build_scripts()
&& self.workspace_build_data.is_none()
|| config_version < self.vfs_config_version,
};
Progress::End
};
self.report_progress(
"roots scanned",
state,
Some(format!("{}/{}", n_done, n_total)),
Some(Progress::fraction(n_done, n_total)),
)
}
assert_eq!(n_done, n_total);
Progress::End
};
self.report_progress(
"roots scanned",
state,
Some(format!("{}/{}", n_done, n_total)),
Some(Progress::fraction(n_done, n_total)),
)
}
}
// Coalesce many VFS event into a single loop turn
Expand Down Expand Up @@ -397,18 +409,14 @@ impl GlobalState {
}

let state_changed = self.process_changes();
let prev_status = self.status;
if prev_status != new_status {
self.transition(new_status);
}
let is_ready = matches!(self.status, Status::Ready { .. });
if prev_status == Status::Loading && is_ready {

if self.is_quiescent() && !was_quiescent {
for flycheck in &self.flycheck {
flycheck.update();
}
}

if is_ready && (state_changed || prev_status == Status::Loading) {
if self.is_quiescent() && (!was_quiescent || state_changed) {
self.update_file_notifications_on_threadpool();

// Refresh semantic tokens if the client supports it.
Expand Down Expand Up @@ -437,9 +445,13 @@ impl GlobalState {
}
}

self.fetch_workspaces_if_needed();
if self.config.cargo_autoreload() {
self.fetch_workspaces_if_needed();
}
self.fetch_build_data_if_needed();

self.report_new_status_if_needed();

let loop_duration = loop_start.elapsed();
if loop_duration > Duration::from_millis(100) {
log::warn!("overly long loop turn: {:?}", loop_duration);
Expand All @@ -466,7 +478,8 @@ impl GlobalState {
return Ok(());
}

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

RequestDispatcher { req: Some(req), global_state: self }
.on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces_request()))?
.on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| {
s.fetch_workspaces_request();
s.fetch_workspaces_if_needed();
Ok(())
})?
.on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))?
.on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))?
.on_sync::<lsp_types::request::Shutdown>(|s, ()| {
Expand Down

0 comments on commit 0d49e40

Please sign in to comment.