diff --git a/Cargo.lock b/Cargo.lock index 51cf1825d6..69134b434b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -668,6 +668,7 @@ dependencies = [ name = "ra_db" version = "0.1.0" dependencies = [ + "backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "ra_editor 0.1.0", "ra_syntax 0.1.0", diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml index f316c0ab2f..4be32b5f31 100644 --- a/crates/ra_db/Cargo.toml +++ b/crates/ra_db/Cargo.toml @@ -5,6 +5,7 @@ version = "0.1.0" authors = ["Aleksey Kladov "] [dependencies] +backtrace = "0.3.1" relative-path = "0.4.0" salsa = "0.8.0" rustc-hash = "1.0" diff --git a/crates/ra_db/src/cancelation.rs b/crates/ra_db/src/cancelation.rs new file mode 100644 index 0000000000..73444b015b --- /dev/null +++ b/crates/ra_db/src/cancelation.rs @@ -0,0 +1,85 @@ +//! Utility types to support cancellation. +//! +//! In a typical IDE use-case, requests and modification happen concurrently, as +//! in the following scenario: +//! +//! * user types a character, +//! * a syntax highlighting process is started +//! * user types next character, while syntax highlighting *is still in +//! progress*. +//! +//! In this situation, we want to react to modification as quckly as possible. +//! At the same time, in-progress results are not very interesting, because they +//! are invalidated by the edit anyway. So, we first cancel all in-flight +//! requests, and then apply modification knowing that it won't intrfere with +//! any background processing (this bit is handled by salsa, see +//! `BaseDatabase::check_canceled` method). + +use std::{ + cmp, + hash::{Hash, Hasher}, + sync::Arc, +}; + +use backtrace::Backtrace; +use parking_lot::Mutex; + +/// An "error" signifing that the operation was canceled. +#[derive(Clone)] +pub struct Canceled { + backtrace: Arc>, +} + +pub type Cancelable = Result; + +impl Canceled { + pub(crate) fn new() -> Canceled { + let bt = Backtrace::new_unresolved(); + Canceled { + backtrace: Arc::new(Mutex::new(bt)), + } + } +} + +impl std::fmt::Display for Canceled { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fmt.write_str("canceled") + } +} + +impl std::fmt::Debug for Canceled { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut bt = self.backtrace.lock(); + let bt: &mut Backtrace = &mut *bt; + bt.resolve(); + write!(fmt, "canceled at:\n{:?}", bt) + } +} + +impl std::error::Error for Canceled {} + +impl PartialEq for Canceled { + fn eq(&self, _: &Canceled) -> bool { + true + } +} + +impl Eq for Canceled {} + +impl Hash for Canceled { + fn hash(&self, hasher: &mut H) { + ().hash(hasher) + } +} + +impl cmp::Ord for Canceled { + fn cmp(&self, _: &Canceled) -> cmp::Ordering { + cmp::Ordering::Equal + } +} + +impl cmp::PartialOrd for Canceled { + fn partial_cmp(&self, other: &Canceled) -> Option { + Some(self.cmp(other)) + } +} diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 78f2cbf12b..1f7c9187be 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs @@ -1,27 +1,17 @@ //! ra_db defines basic database traits. Concrete DB is defined by ra_analysis. +mod cancelation; mod syntax_ptr; mod input; mod loc2id; pub mod mock; use std::sync::Arc; + use ra_editor::LineIndex; use ra_syntax::{TextUnit, SourceFileNode}; -#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Canceled; - -pub type Cancelable = Result; - -impl std::fmt::Display for Canceled { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - fmt.write_str("canceled") - } -} - -impl std::error::Error for Canceled {} - pub use crate::{ + cancelation::{Canceled, Cancelable}, syntax_ptr::LocalSyntaxPtr, input::{ FilesDatabase, FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, @@ -48,7 +38,7 @@ macro_rules! impl_numeric_id { pub trait BaseDatabase: salsa::Database { fn check_canceled(&self) -> Cancelable<()> { if self.salsa_runtime().is_current_revision_canceled() { - Err(Canceled) + Err(Canceled::new()) } else { Ok(()) } diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 60f13267c2..1edb9fae49 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -427,7 +427,7 @@ impl<'a> PoolDispatcher<'a> { RawResponse::err( id, ErrorCode::ContentModified as i32, - format!("content modified: {}", e), + format!("content modified: {:?}", e), ) } else { RawResponse::err(