Skip to content

Commit 4f5c7aa

Browse files
committed
Auto merge of #12431 - Veykril:request-retry, r=Veykril
fix: Fix completions disappearing when typing two keys in quick succession With this PR we now retry requests if they get cancelled due to document changes. This fixes the completions problem we have where completions seem to randomly disappear, see https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer/topic/Completions.20not.20always.20appearing Fixes #10187 Fixes #7560 Fixes #12153
2 parents 30672cb + d88ae66 commit 4f5c7aa

File tree

6 files changed

+70
-71
lines changed

6 files changed

+70
-71
lines changed

crates/rust-analyzer/src/bin/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ fn run_server() -> Result<()> {
157157
let (initialize_id, initialize_params) = connection.initialize_start()?;
158158
tracing::info!("InitializeParams: {}", initialize_params);
159159
let initialize_params =
160-
from_json::<lsp_types::InitializeParams>("InitializeParams", initialize_params)?;
160+
from_json::<lsp_types::InitializeParams>("InitializeParams", &initialize_params)?;
161161

162162
let root_path = match initialize_params
163163
.root_uri

crates/rust-analyzer/src/dispatch.rs

Lines changed: 48 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//! See [RequestDispatcher].
22
use std::{fmt, panic, thread};
33

4+
use ide::Cancelled;
45
use lsp_server::ExtractError;
56
use serde::{de::DeserializeOwned, Serialize};
67

78
use crate::{
89
global_state::{GlobalState, GlobalStateSnapshot},
9-
lsp_utils::is_cancelled,
1010
main_loop::Task,
1111
LspError, Result,
1212
};
@@ -37,49 +37,53 @@ impl<'a> RequestDispatcher<'a> {
3737
pub(crate) fn on_sync_mut<R>(
3838
&mut self,
3939
f: fn(&mut GlobalState, R::Params) -> Result<R::Result>,
40-
) -> Result<&mut Self>
40+
) -> &mut Self
4141
where
4242
R: lsp_types::request::Request,
4343
R::Params: DeserializeOwned + panic::UnwindSafe + fmt::Debug,
4444
R::Result: Serialize,
4545
{
46-
let (id, params, panic_context) = match self.parse::<R>() {
46+
let (req, params, panic_context) = match self.parse::<R>() {
4747
Some(it) => it,
48-
None => return Ok(self),
48+
None => return self,
4949
};
50-
let _pctx = stdx::panic_context::enter(panic_context);
51-
52-
let result = f(self.global_state, params);
53-
let response = result_to_response::<R>(id, result);
50+
let result = {
51+
let _pctx = stdx::panic_context::enter(panic_context);
52+
f(self.global_state, params)
53+
};
54+
if let Ok(response) = result_to_response::<R>(req.id.clone(), result) {
55+
self.global_state.respond(response);
56+
}
5457

55-
self.global_state.respond(response);
56-
Ok(self)
58+
self
5759
}
5860

5961
/// Dispatches the request onto the current thread.
6062
pub(crate) fn on_sync<R>(
6163
&mut self,
6264
f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
63-
) -> Result<&mut Self>
65+
) -> &mut Self
6466
where
65-
R: lsp_types::request::Request + 'static,
67+
R: lsp_types::request::Request,
6668
R::Params: DeserializeOwned + panic::UnwindSafe + fmt::Debug,
6769
R::Result: Serialize,
6870
{
69-
let (id, params, panic_context) = match self.parse::<R>() {
71+
let (req, params, panic_context) = match self.parse::<R>() {
7072
Some(it) => it,
71-
None => return Ok(self),
73+
None => return self,
7274
};
7375
let global_state_snapshot = self.global_state.snapshot();
7476

7577
let result = panic::catch_unwind(move || {
7678
let _pctx = stdx::panic_context::enter(panic_context);
7779
f(global_state_snapshot, params)
7880
});
79-
let response = thread_result_to_response::<R>(id, result);
8081

81-
self.global_state.respond(response);
82-
Ok(self)
82+
if let Ok(response) = thread_result_to_response::<R>(req.id.clone(), result) {
83+
self.global_state.respond(response);
84+
}
85+
86+
self
8387
}
8488

8589
/// Dispatches the request onto thread pool
@@ -92,7 +96,7 @@ impl<'a> RequestDispatcher<'a> {
9296
R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
9397
R::Result: Serialize,
9498
{
95-
let (id, params, panic_context) = match self.parse::<R>() {
99+
let (req, params, panic_context) = match self.parse::<R>() {
96100
Some(it) => it,
97101
None => return self,
98102
};
@@ -104,8 +108,10 @@ impl<'a> RequestDispatcher<'a> {
104108
let _pctx = stdx::panic_context::enter(panic_context);
105109
f(world, params)
106110
});
107-
let response = thread_result_to_response::<R>(id, result);
108-
Task::Response(response)
111+
match thread_result_to_response::<R>(req.id.clone(), result) {
112+
Ok(response) => Task::Response(response),
113+
Err(_) => Task::Retry(req),
114+
}
109115
}
110116
});
111117

@@ -124,7 +130,7 @@ impl<'a> RequestDispatcher<'a> {
124130
}
125131
}
126132

127-
fn parse<R>(&mut self) -> Option<(lsp_server::RequestId, R::Params, String)>
133+
fn parse<R>(&mut self) -> Option<(lsp_server::Request, R::Params, String)>
128134
where
129135
R: lsp_types::request::Request,
130136
R::Params: DeserializeOwned + fmt::Debug,
@@ -134,12 +140,12 @@ impl<'a> RequestDispatcher<'a> {
134140
_ => return None,
135141
};
136142

137-
let res = crate::from_json(R::METHOD, req.params);
143+
let res = crate::from_json(R::METHOD, &req.params);
138144
match res {
139145
Ok(params) => {
140146
let panic_context =
141147
format!("\nversion: {}\nrequest: {} {:#?}", env!("REV"), R::METHOD, params);
142-
Some((req.id, params, panic_context))
148+
Some((req, params, panic_context))
143149
}
144150
Err(err) => {
145151
let response = lsp_server::Response::new_err(
@@ -157,7 +163,7 @@ impl<'a> RequestDispatcher<'a> {
157163
fn thread_result_to_response<R>(
158164
id: lsp_server::RequestId,
159165
result: thread::Result<Result<R::Result>>,
160-
) -> lsp_server::Response
166+
) -> Result<lsp_server::Response, Cancelled>
161167
where
162168
R: lsp_types::request::Request,
163169
R::Params: DeserializeOwned,
@@ -166,53 +172,50 @@ where
166172
match result {
167173
Ok(result) => result_to_response::<R>(id, result),
168174
Err(panic) => {
169-
let mut message = "request handler panicked".to_string();
170-
171175
let panic_message = panic
172176
.downcast_ref::<String>()
173177
.map(String::as_str)
174178
.or_else(|| panic.downcast_ref::<&str>().copied());
175179

180+
let mut message = "request handler panicked".to_string();
176181
if let Some(panic_message) = panic_message {
177182
message.push_str(": ");
178183
message.push_str(panic_message)
179184
};
180185

181-
lsp_server::Response::new_err(id, lsp_server::ErrorCode::InternalError as i32, message)
186+
Ok(lsp_server::Response::new_err(
187+
id,
188+
lsp_server::ErrorCode::InternalError as i32,
189+
message,
190+
))
182191
}
183192
}
184193
}
185194

186195
fn result_to_response<R>(
187196
id: lsp_server::RequestId,
188197
result: Result<R::Result>,
189-
) -> lsp_server::Response
198+
) -> Result<lsp_server::Response, Cancelled>
190199
where
191200
R: lsp_types::request::Request,
192201
R::Params: DeserializeOwned,
193202
R::Result: Serialize,
194203
{
195-
match result {
204+
let res = match result {
196205
Ok(resp) => lsp_server::Response::new_ok(id, &resp),
197206
Err(e) => match e.downcast::<LspError>() {
198207
Ok(lsp_error) => lsp_server::Response::new_err(id, lsp_error.code, lsp_error.message),
199-
Err(e) => {
200-
if is_cancelled(&*e) {
201-
lsp_server::Response::new_err(
202-
id,
203-
lsp_server::ErrorCode::ContentModified as i32,
204-
"content modified".to_string(),
205-
)
206-
} else {
207-
lsp_server::Response::new_err(
208-
id,
209-
lsp_server::ErrorCode::InternalError as i32,
210-
e.to_string(),
211-
)
212-
}
213-
}
208+
Err(e) => match e.downcast::<Cancelled>() {
209+
Ok(cancelled) => return Err(*cancelled),
210+
Err(e) => lsp_server::Response::new_err(
211+
id,
212+
lsp_server::ErrorCode::InternalError as i32,
213+
e.to_string(),
214+
),
215+
},
214216
},
215-
}
217+
};
218+
Ok(res)
216219
}
217220

218221
pub(crate) struct NotificationDispatcher<'a> {

crates/rust-analyzer/src/from_proto.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ pub(crate) fn annotation(
9191
) -> Result<Annotation> {
9292
let data =
9393
code_lens.data.ok_or_else(|| invalid_params_error("code lens without data".to_string()))?;
94-
let resolve = from_json::<lsp_ext::CodeLensResolveData>("CodeLensResolveData", data)?;
94+
let resolve = from_json::<lsp_ext::CodeLensResolveData>("CodeLensResolveData", &data)?;
9595

9696
match resolve {
9797
lsp_ext::CodeLensResolveData::Impls(params) => {

crates/rust-analyzer/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ pub use crate::{caps::server_capabilities, main_loop::main_loop};
4949
pub type Error = Box<dyn std::error::Error + Send + Sync>;
5050
pub type Result<T, E = Error> = std::result::Result<T, E>;
5151

52-
pub fn from_json<T: DeserializeOwned>(what: &'static str, json: serde_json::Value) -> Result<T> {
52+
pub fn from_json<T: DeserializeOwned>(what: &'static str, json: &serde_json::Value) -> Result<T> {
5353
let res = serde_json::from_value(json.clone())
5454
.map_err(|e| format!("Failed to deserialize {}: {}; {}", what, e, json))?;
5555
Ok(res)

crates/rust-analyzer/src/lsp_utils.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! Utilities for LSP-related boilerplate code.
2-
use std::{error::Error, ops::Range, sync::Arc};
2+
use std::{ops::Range, sync::Arc};
33

4-
use ide_db::base_db::Cancelled;
54
use lsp_server::Notification;
65

76
use crate::{
@@ -15,10 +14,6 @@ pub(crate) fn invalid_params_error(message: String) -> LspError {
1514
LspError { code: lsp_server::ErrorCode::InvalidParams as i32, message }
1615
}
1716

18-
pub(crate) fn is_cancelled(e: &(dyn Error + 'static)) -> bool {
19-
e.downcast_ref::<Cancelled>().is_some()
20-
}
21-
2217
pub(crate) fn notification_is<N: lsp_types::notification::Notification>(
2318
notification: &Notification,
2419
) -> bool {

crates/rust-analyzer/src/main_loop.rs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::{
88

99
use always_assert::always;
1010
use crossbeam_channel::{select, Receiver};
11-
use ide_db::base_db::{SourceDatabaseExt, VfsPath};
11+
use ide_db::base_db::{Cancelled, SourceDatabaseExt, VfsPath};
1212
use lsp_server::{Connection, Notification, Request};
1313
use lsp_types::notification::Notification as _;
1414
use vfs::{ChangeKind, FileId};
@@ -19,7 +19,7 @@ use crate::{
1919
from_proto,
2020
global_state::{file_id_to_url, url_to_file_id, GlobalState},
2121
handlers, lsp_ext,
22-
lsp_utils::{apply_document_changes, is_cancelled, notification_is, Progress},
22+
lsp_utils::{apply_document_changes, notification_is, Progress},
2323
mem_docs::DocumentData,
2424
reload::{self, BuildDataProgress, ProjectWorkspaceProgress},
2525
Result,
@@ -60,6 +60,7 @@ enum Event {
6060
#[derive(Debug)]
6161
pub(crate) enum Task {
6262
Response(lsp_server::Response),
63+
Retry(lsp_server::Request),
6364
Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
6465
PrimeCaches(PrimeCachesProgress),
6566
FetchWorkspace(ProjectWorkspaceProgress),
@@ -196,7 +197,7 @@ impl GlobalState {
196197
let was_quiescent = self.is_quiescent();
197198
match event {
198199
Event::Lsp(msg) => match msg {
199-
lsp_server::Message::Request(req) => self.on_request(loop_start, req)?,
200+
lsp_server::Message::Request(req) => self.on_request(loop_start, req),
200201
lsp_server::Message::Notification(not) => {
201202
self.on_notification(not)?;
202203
}
@@ -208,6 +209,7 @@ impl GlobalState {
208209
loop {
209210
match task {
210211
Task::Response(response) => self.respond(response),
212+
Task::Retry(req) => self.on_request(loop_start, req),
211213
Task::Diagnostics(diagnostics_per_file) => {
212214
for (file_id, diagnostics) in diagnostics_per_file {
213215
self.diagnostics.set_native_diagnostics(file_id, diagnostics)
@@ -553,7 +555,7 @@ impl GlobalState {
553555
Ok(())
554556
}
555557

556-
fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> {
558+
fn on_request(&mut self, request_received: Instant, req: Request) {
557559
self.register_request(&req, request_received);
558560

559561
if self.shutdown_requested {
@@ -562,8 +564,7 @@ impl GlobalState {
562564
lsp_server::ErrorCode::InvalidRequest as i32,
563565
"Shutdown already requested.".to_owned(),
564566
));
565-
566-
return Ok(());
567+
return;
567568
}
568569

569570
// Avoid flashing a bunch of unresolved references during initial load.
@@ -573,21 +574,21 @@ impl GlobalState {
573574
lsp_server::ErrorCode::ContentModified as i32,
574575
"waiting for cargo metadata or cargo check".to_owned(),
575576
));
576-
return Ok(());
577+
return;
577578
}
578579

579580
RequestDispatcher { req: Some(req), global_state: self }
580581
.on_sync_mut::<lsp_types::request::Shutdown>(|s, ()| {
581582
s.shutdown_requested = true;
582583
Ok(())
583-
})?
584-
.on_sync_mut::<lsp_ext::ReloadWorkspace>(handlers::handle_workspace_reload)?
585-
.on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage)?
586-
.on_sync_mut::<lsp_ext::ShuffleCrateGraph>(handlers::handle_shuffle_crate_graph)?
587-
.on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)?
588-
.on_sync::<lsp_ext::OnEnter>(handlers::handle_on_enter)?
589-
.on_sync::<lsp_types::request::SelectionRangeRequest>(handlers::handle_selection_range)?
590-
.on_sync::<lsp_ext::MatchingBrace>(handlers::handle_matching_brace)?
584+
})
585+
.on_sync_mut::<lsp_ext::ReloadWorkspace>(handlers::handle_workspace_reload)
586+
.on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage)
587+
.on_sync_mut::<lsp_ext::ShuffleCrateGraph>(handlers::handle_shuffle_crate_graph)
588+
.on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)
589+
.on_sync::<lsp_ext::OnEnter>(handlers::handle_on_enter)
590+
.on_sync::<lsp_types::request::SelectionRangeRequest>(handlers::handle_selection_range)
591+
.on_sync::<lsp_ext::MatchingBrace>(handlers::handle_matching_brace)
591592
.on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
592593
.on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
593594
.on::<lsp_ext::ViewHir>(handlers::handle_view_hir)
@@ -644,8 +645,8 @@ impl GlobalState {
644645
.on::<lsp_types::request::WillRenameFiles>(handlers::handle_will_rename_files)
645646
.on::<lsp_ext::Ssr>(handlers::handle_ssr)
646647
.finish();
647-
Ok(())
648648
}
649+
649650
fn on_notification(&mut self, not: Notification) -> Result<()> {
650651
NotificationDispatcher { not: Some(not), global_state: self }
651652
.on::<lsp_types::notification::Cancel>(|this, params| {
@@ -792,7 +793,7 @@ impl GlobalState {
792793
.filter_map(|file_id| {
793794
handlers::publish_diagnostics(&snapshot, file_id)
794795
.map_err(|err| {
795-
if !is_cancelled(&*err) {
796+
if err.is::<Cancelled>() {
796797
tracing::error!("failed to compute diagnostics: {:?}", err);
797798
}
798799
})

0 commit comments

Comments
 (0)