Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--Cargo.lock12
-rw-r--r--crates/ide/src/lib.rs6
-rw-r--r--crates/rust-analyzer/src/global_state.rs8
-rw-r--r--crates/rust-analyzer/src/handlers/dispatch.rs17
4 files changed, 40 insertions, 3 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9c98e05020..12a6c09b8d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3754,3 +3754,15 @@ dependencies = [
"memchr",
"time",
]
+
+[[patch.unused]]
+name = "salsa"
+version = "0.25.2"
+
+[[patch.unused]]
+name = "salsa-macro-rules"
+version = "0.25.2"
+
+[[patch.unused]]
+name = "salsa-macros"
+version = "0.25.2"
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 930eaf2262..2e618550f9 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -67,7 +67,7 @@ use ide_db::{
FxHashMap, FxIndexSet, LineIndexDatabase,
base_db::{
CrateOrigin, CrateWorkspaceData, Env, FileSet, RootQueryDb, SourceDatabase, VfsPath,
- salsa::{Cancelled, Database},
+ salsa::{CancellationToken, Cancelled, Database},
},
prime_caches, symbol_index,
};
@@ -947,6 +947,10 @@ impl Analysis {
// We use `attach_db_allow_change()` and not `attach_db()` because fixture injection can change the database.
hir::attach_db_allow_change(&self.db, || Cancelled::catch(|| f(&self.db)))
}
+
+ pub fn cancellation_token(&self) -> CancellationToken {
+ self.db.cancellation_token()
+ }
}
#[test]
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index afd4162de6..1462727df4 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -14,7 +14,7 @@ use hir::ChangeWithProcMacros;
use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId};
use ide_db::{
MiniCore,
- base_db::{Crate, ProcMacroPaths, SourceDatabase, salsa::Revision},
+ base_db::{Crate, ProcMacroPaths, SourceDatabase, salsa::CancellationToken, salsa::Revision},
};
use itertools::Itertools;
use load_cargo::SourceRootConfig;
@@ -88,6 +88,7 @@ pub(crate) struct GlobalState {
pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
pub(crate) fmt_pool: Handle<TaskPool<Task>, Receiver<Task>>,
pub(crate) cancellation_pool: thread::Pool,
+ pub(crate) cancellation_tokens: FxHashMap<lsp_server::RequestId, CancellationToken>,
pub(crate) config: Arc<Config>,
pub(crate) config_errors: Option<ConfigErrors>,
@@ -265,6 +266,7 @@ impl GlobalState {
task_pool,
fmt_pool,
cancellation_pool,
+ cancellation_tokens: Default::default(),
loader,
config: Arc::new(config.clone()),
analysis_host,
@@ -617,6 +619,7 @@ impl GlobalState {
}
pub(crate) fn respond(&mut self, response: lsp_server::Response) {
+ self.cancellation_tokens.remove(&response.id);
if let Some((method, start)) = self.req_queue.incoming.complete(&response.id) {
if let Some(err) = &response.error
&& err.message.starts_with("server panicked")
@@ -631,6 +634,9 @@ impl GlobalState {
}
pub(crate) fn cancel(&mut self, request_id: lsp_server::RequestId) {
+ if let Some(token) = self.cancellation_tokens.remove(&request_id) {
+ token.cancel();
+ }
if let Some(response) = self.req_queue.incoming.cancel(request_id) {
self.send(response.into());
}
diff --git a/crates/rust-analyzer/src/handlers/dispatch.rs b/crates/rust-analyzer/src/handlers/dispatch.rs
index 90deae2d90..63b4e6430c 100644
--- a/crates/rust-analyzer/src/handlers/dispatch.rs
+++ b/crates/rust-analyzer/src/handlers/dispatch.rs
@@ -253,6 +253,9 @@ impl RequestDispatcher<'_> {
tracing::debug!(?params);
let world = self.global_state.snapshot();
+ self.global_state
+ .cancellation_tokens
+ .insert(req.id.clone(), world.analysis.cancellation_token());
if RUSTFMT {
&mut self.global_state.fmt_pool.handle
} else {
@@ -265,7 +268,19 @@ impl RequestDispatcher<'_> {
});
match thread_result_to_response::<R>(req.id.clone(), result) {
Ok(response) => Task::Response(response),
- Err(_cancelled) if ALLOW_RETRYING => Task::Retry(req),
+ Err(HandlerCancelledError::Inner(
+ Cancelled::PendingWrite | Cancelled::PropagatedPanic,
+ )) if ALLOW_RETRYING => Task::Retry(req),
+ // Note: Technically the return value here does not matter as we have already responded to the client with this error.
+ Err(HandlerCancelledError::Inner(Cancelled::Local)) => Task::Response(Response {
+ id: req.id,
+ result: None,
+ error: Some(ResponseError {
+ code: lsp_server::ErrorCode::RequestCanceled as i32,
+ message: "canceled by client".to_owned(),
+ data: None,
+ }),
+ }),
Err(_cancelled) => {
let error = on_cancelled();
Task::Response(Response { id: req.id, result: None, error: Some(error) })