From 33debc40654be9e9061c53784f6c762b2fd21eba Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 17 May 2021 19:07:10 +0200 Subject: [PATCH] Update salsa --- Cargo.lock | 4 - Cargo.toml | 2 +- crates/base_db/src/cancellation.rs | 48 --------- crates/base_db/src/lib.rs | 45 +------- crates/hir/src/semantics.rs | 2 +- crates/hir_def/src/nameres/collector.rs | 4 +- crates/hir_ty/src/infer/expr.rs | 2 +- crates/hir_ty/src/traits.rs | 2 +- crates/ide/src/lib.rs | 128 +++++++++++++---------- crates/ide_db/src/lib.rs | 20 +--- crates/ide_db/src/symbol_index.rs | 2 +- crates/rust-analyzer/src/dispatch.rs | 4 +- crates/rust-analyzer/src/global_state.rs | 4 +- crates/rust-analyzer/src/lsp_utils.rs | 6 +- crates/rust-analyzer/src/main_loop.rs | 4 +- crates/rust-analyzer/src/to_proto.rs | 6 +- 16 files changed, 94 insertions(+), 189 deletions(-) delete mode 100644 crates/base_db/src/cancellation.rs diff --git a/Cargo.lock b/Cargo.lock index 557d5f5f32..2bc31889e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1387,8 +1387,6 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "salsa" version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b84d9f96071f3f3be0dc818eae3327625d8ebc95b58da37d6850724f31d3403" dependencies = [ "crossbeam-utils", "indexmap", @@ -1404,8 +1402,6 @@ dependencies = [ [[package]] name = "salsa-macros" version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3904a4ba0a9d0211816177fd34b04c7095443f8cdacd11175064fe541c8fe2" dependencies = [ "heck", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 498cf7d626..496264db84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,4 +38,4 @@ incremental = false # ungrammar = { path = "../ungrammar" } -# salsa = { path = "../salsa" } +salsa = { path = "../salsa" } diff --git a/crates/base_db/src/cancellation.rs b/crates/base_db/src/cancellation.rs deleted file mode 100644 index 7420a1976f..0000000000 --- a/crates/base_db/src/cancellation.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! 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 quickly 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 interfere with -//! any background processing (this bit is handled by salsa, see the -//! `BaseDatabase::check_canceled` method). - -/// An "error" signifying that the operation was canceled. -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct Canceled { - _private: (), -} - -impl Canceled { - pub(crate) fn new() -> Canceled { - Canceled { _private: () } - } - - pub fn throw() -> ! { - // We use resume and not panic here to avoid running the panic - // hook (that is, to avoid collecting and printing backtrace). - std::panic::resume_unwind(Box::new(Canceled::new())) - } -} - -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 { - write!(fmt, "Canceled") - } -} - -impl std::error::Error for Canceled {} diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs index 980a0ed985..62bf2a4b2c 100644 --- a/crates/base_db/src/lib.rs +++ b/crates/base_db/src/lib.rs @@ -1,5 +1,4 @@ //! base_db defines basic database traits. The concrete DB is defined by ide. -mod cancellation; mod input; mod change; pub mod fixture; @@ -10,14 +9,13 @@ use rustc_hash::FxHashSet; use syntax::{ast, Parse, SourceFile, TextRange, TextSize}; pub use crate::{ - cancellation::Canceled, change::Change, input::{ CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ProcMacro, ProcMacroExpander, ProcMacroId, ProcMacroKind, SourceRoot, SourceRootId, }, }; -pub use salsa; +pub use salsa::{self, Cancelled}; pub use vfs::{file_set::FileSet, AnchoredPath, AnchoredPathBuf, FileId, VfsPath}; #[macro_export] @@ -38,45 +36,6 @@ pub trait Upcast { fn upcast(&self) -> &T; } -pub trait CheckCanceled { - /// Aborts current query if there are pending changes. - /// - /// rust-analyzer needs to be able to answer semantic questions about the - /// code while the code is being modified. A common problem is that a - /// long-running query is being calculated when a new change arrives. - /// - /// We can't just apply the change immediately: this will cause the pending - /// query to see inconsistent state (it will observe an absence of - /// repeatable read). So what we do is we **cancel** all pending queries - /// before applying the change. - /// - /// We implement cancellation by panicking with a special value and catching - /// it on the API boundary. Salsa explicitly supports this use-case. - fn check_canceled(&self); - - fn catch_canceled(&self, f: F) -> Result - where - Self: Sized + panic::RefUnwindSafe, - F: FnOnce(&Self) -> T + panic::UnwindSafe, - { - // Uncomment to debug missing cancellations. - // let _span = profile::heartbeat_span(); - panic::catch_unwind(|| f(self)).map_err(|err| match err.downcast::() { - Ok(canceled) => *canceled, - Err(payload) => panic::resume_unwind(payload), - }) - } -} - -impl CheckCanceled for T { - fn check_canceled(&self) { - // profile::heartbeat(); - if self.salsa_runtime().is_current_revision_canceled() { - Canceled::throw() - } - } -} - #[derive(Clone, Copy, Debug)] pub struct FilePosition { pub file_id: FileId, @@ -101,7 +60,7 @@ pub trait FileLoader { /// Database which stores all significant input facts: source code and project /// model. Everything else in rust-analyzer is derived from these queries. #[salsa::query_group(SourceDatabaseStorage)] -pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug { +pub trait SourceDatabase: FileLoader + std::fmt::Debug { // Parses the file into the syntax tree. #[salsa::invoke(parse_query)] fn parse(&self, file_id: FileId) -> Parse; diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 8d3c43d082..c7f2c02e4c 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -361,7 +361,7 @@ impl<'db> SemanticsImpl<'db> { let sa = self.analyze(&parent); let token = successors(Some(InFile::new(sa.file_id, token)), |token| { - self.db.check_canceled(); + self.db.unwind_if_cancelled(); let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; let tt = macro_call.token_tree()?; if !tt.syntax().text_range().contains_range(token.value.text_range()) { diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 4296c63045..716dcf1f7c 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs @@ -351,7 +351,7 @@ impl DefCollector<'_> { let mut i = 0; 'outer: loop { loop { - self.db.check_canceled(); + self.db.unwind_if_cancelled(); loop { if self.resolve_imports() == ReachedFixedPoint::Yes { break; @@ -831,7 +831,7 @@ impl DefCollector<'_> { vis: Visibility, import_type: ImportType, ) { - self.db.check_canceled(); + self.db.unwind_if_cancelled(); self.update_recursive(module_id, resolutions, vis, import_type, 0) } diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index 97507305c2..41ef45326b 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs @@ -119,7 +119,7 @@ impl<'a> InferenceContext<'a> { } fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { - self.db.check_canceled(); + self.db.unwind_if_cancelled(); let body = Arc::clone(&self.body); // avoid borrow checker problem let ty = match &body[tgt_expr] { diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs index 294cb531c8..f589b314b8 100644 --- a/crates/hir_ty/src/traits.rs +++ b/crates/hir_ty/src/traits.rs @@ -112,7 +112,7 @@ fn solve( let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL); let should_continue = || { - context.db.check_canceled(); + db.unwind_if_cancelled(); let remaining = fuel.get(); fuel.set(remaining - 1); if remaining == 0 { diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index ff2a54117b..97c9e5d2b4 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -58,7 +58,7 @@ use cfg::CfgOptions; use ide_db::base_db::{ salsa::{self, ParallelDatabase}, - CheckCanceled, Env, FileLoader, FileSet, SourceDatabase, VfsPath, + Env, FileLoader, FileSet, SourceDatabase, VfsPath, }; use ide_db::{ symbol_index::{self, FileSymbol}, @@ -98,7 +98,7 @@ pub use ide_completion::{ }; pub use ide_db::{ base_db::{ - Canceled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, + Cancelled, Change, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot, SourceRootId, }, call_info::CallInfo, @@ -113,7 +113,7 @@ pub use ide_ssr::SsrError; pub use syntax::{TextRange, TextSize}; pub use text_edit::{Indel, TextEdit}; -pub type Cancelable = Result; +pub type Cancellable = Result; /// Info associated with a text range. #[derive(Debug)] @@ -227,11 +227,11 @@ impl Analysis { } /// Debug info about the current state of the analysis. - pub fn status(&self, file_id: Option) -> Cancelable { + pub fn status(&self, file_id: Option) -> Cancellable { self.with_db(|db| status::status(&*db, file_id)) } - pub fn prime_caches(&self, cb: F) -> Cancelable<()> + pub fn prime_caches(&self, cb: F) -> Cancellable<()> where F: Fn(PrimeCachesProgress) + Sync + std::panic::UnwindSafe, { @@ -239,35 +239,35 @@ impl Analysis { } /// Gets the text of the source file. - pub fn file_text(&self, file_id: FileId) -> Cancelable> { + pub fn file_text(&self, file_id: FileId) -> Cancellable> { self.with_db(|db| db.file_text(file_id)) } /// Gets the syntax tree of the file. - pub fn parse(&self, file_id: FileId) -> Cancelable { + pub fn parse(&self, file_id: FileId) -> Cancellable { self.with_db(|db| db.parse(file_id).tree()) } /// Returns true if this file belongs to an immutable library. - pub fn is_library_file(&self, file_id: FileId) -> Cancelable { + pub fn is_library_file(&self, file_id: FileId) -> Cancellable { use ide_db::base_db::SourceDatabaseExt; self.with_db(|db| db.source_root(db.file_source_root(file_id)).is_library) } /// Gets the file's `LineIndex`: data structure to convert between absolute /// offsets and line/column representation. - pub fn file_line_index(&self, file_id: FileId) -> Cancelable> { + pub fn file_line_index(&self, file_id: FileId) -> Cancellable> { self.with_db(|db| db.line_index(file_id)) } /// Selects the next syntactic nodes encompassing the range. - pub fn extend_selection(&self, frange: FileRange) -> Cancelable { + pub fn extend_selection(&self, frange: FileRange) -> Cancellable { self.with_db(|db| extend_selection::extend_selection(db, frange)) } /// Returns position of the matching brace (all types of braces are /// supported). - pub fn matching_brace(&self, position: FilePosition) -> Cancelable> { + pub fn matching_brace(&self, position: FilePosition) -> Cancellable> { self.with_db(|db| { let parse = db.parse(position.file_id); let file = parse.tree(); @@ -281,30 +281,30 @@ impl Analysis { &self, file_id: FileId, text_range: Option, - ) -> Cancelable { + ) -> Cancellable { self.with_db(|db| syntax_tree::syntax_tree(&db, file_id, text_range)) } - pub fn view_hir(&self, position: FilePosition) -> Cancelable { + pub fn view_hir(&self, position: FilePosition) -> Cancellable { self.with_db(|db| view_hir::view_hir(&db, position)) } - pub fn view_item_tree(&self, file_id: FileId) -> Cancelable { + pub fn view_item_tree(&self, file_id: FileId) -> Cancellable { self.with_db(|db| view_item_tree::view_item_tree(&db, file_id)) } /// Renders the crate graph to GraphViz "dot" syntax. - pub fn view_crate_graph(&self) -> Cancelable> { + pub fn view_crate_graph(&self) -> Cancellable> { self.with_db(|db| view_crate_graph::view_crate_graph(&db)) } - pub fn expand_macro(&self, position: FilePosition) -> Cancelable> { + pub fn expand_macro(&self, position: FilePosition) -> Cancellable> { self.with_db(|db| expand_macro::expand_macro(db, position)) } /// Returns an edit to remove all newlines in the range, cleaning up minor /// stuff like trailing commas. - pub fn join_lines(&self, frange: FileRange) -> Cancelable { + pub fn join_lines(&self, frange: FileRange) -> Cancellable { self.with_db(|db| { let parse = db.parse(frange.file_id); join_lines::join_lines(&parse.tree(), frange.range) @@ -314,7 +314,7 @@ impl Analysis { /// Returns an edit which should be applied when opening a new line, fixing /// up minor stuff like continuing the comment. /// The edit will be a snippet (with `$0`). - pub fn on_enter(&self, position: FilePosition) -> Cancelable> { + pub fn on_enter(&self, position: FilePosition) -> Cancellable> { self.with_db(|db| typing::on_enter(&db, position)) } @@ -326,7 +326,7 @@ impl Analysis { &self, position: FilePosition, char_typed: char, - ) -> Cancelable> { + ) -> Cancellable> { // Fast path to not even parse the file. if !typing::TRIGGER_CHARS.contains(char_typed) { return Ok(None); @@ -336,7 +336,7 @@ impl Analysis { /// Returns a tree representation of symbols in the file. Useful to draw a /// file outline. - pub fn file_structure(&self, file_id: FileId) -> Cancelable> { + pub fn file_structure(&self, file_id: FileId) -> Cancellable> { self.with_db(|db| file_structure::file_structure(&db.parse(file_id).tree())) } @@ -345,17 +345,17 @@ impl Analysis { &self, file_id: FileId, config: &InlayHintsConfig, - ) -> Cancelable> { + ) -> Cancellable> { self.with_db(|db| inlay_hints::inlay_hints(db, file_id, config)) } /// Returns the set of folding ranges. - pub fn folding_ranges(&self, file_id: FileId) -> Cancelable> { + pub fn folding_ranges(&self, file_id: FileId) -> Cancellable> { self.with_db(|db| folding_ranges::folding_ranges(&db.parse(file_id).tree())) } /// Fuzzy searches for a symbol. - pub fn symbol_search(&self, query: Query) -> Cancelable> { + pub fn symbol_search(&self, query: Query) -> Cancellable> { self.with_db(|db| { symbol_index::world_symbols(db, query) .into_iter() @@ -368,7 +368,7 @@ impl Analysis { pub fn goto_definition( &self, position: FilePosition, - ) -> Cancelable>>> { + ) -> Cancellable>>> { self.with_db(|db| goto_definition::goto_definition(db, position)) } @@ -376,7 +376,7 @@ impl Analysis { pub fn goto_implementation( &self, position: FilePosition, - ) -> Cancelable>>> { + ) -> Cancellable>>> { self.with_db(|db| goto_implementation::goto_implementation(db, position)) } @@ -384,7 +384,7 @@ impl Analysis { pub fn goto_type_definition( &self, position: FilePosition, - ) -> Cancelable>>> { + ) -> Cancellable>>> { self.with_db(|db| goto_type_definition::goto_type_definition(db, position)) } @@ -393,12 +393,12 @@ impl Analysis { &self, position: FilePosition, search_scope: Option, - ) -> Cancelable> { + ) -> Cancellable> { self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, search_scope)) } /// Finds all methods and free functions for the file. Does not return tests! - pub fn find_all_methods(&self, file_id: FileId) -> Cancelable> { + pub fn find_all_methods(&self, file_id: FileId) -> Cancellable> { self.with_db(|db| fn_references::find_all_methods(db, file_id)) } @@ -408,7 +408,7 @@ impl Analysis { position: FilePosition, links_in_hover: bool, markdown: bool, - ) -> Cancelable>> { + ) -> Cancellable>> { self.with_db(|db| hover::hover(db, position, links_in_hover, markdown)) } @@ -416,12 +416,12 @@ impl Analysis { pub fn external_docs( &self, position: FilePosition, - ) -> Cancelable> { + ) -> Cancellable> { self.with_db(|db| doc_links::external_docs(db, &position)) } /// Computes parameter information for the given call expression. - pub fn call_info(&self, position: FilePosition) -> Cancelable> { + pub fn call_info(&self, position: FilePosition) -> Cancellable> { self.with_db(|db| ide_db::call_info::call_info(db, position)) } @@ -429,42 +429,42 @@ impl Analysis { pub fn call_hierarchy( &self, position: FilePosition, - ) -> Cancelable>>> { + ) -> Cancellable>>> { self.with_db(|db| call_hierarchy::call_hierarchy(db, position)) } /// Computes incoming calls for the given file position. - pub fn incoming_calls(&self, position: FilePosition) -> Cancelable>> { + pub fn incoming_calls(&self, position: FilePosition) -> Cancellable>> { self.with_db(|db| call_hierarchy::incoming_calls(db, position)) } /// Computes incoming calls for the given file position. - pub fn outgoing_calls(&self, position: FilePosition) -> Cancelable>> { + pub fn outgoing_calls(&self, position: FilePosition) -> Cancellable>> { self.with_db(|db| call_hierarchy::outgoing_calls(db, position)) } /// Returns a `mod name;` declaration which created the current module. - pub fn parent_module(&self, position: FilePosition) -> Cancelable> { + pub fn parent_module(&self, position: FilePosition) -> Cancellable> { self.with_db(|db| parent_module::parent_module(db, position)) } /// Returns crates this file belongs too. - pub fn crate_for(&self, file_id: FileId) -> Cancelable> { + pub fn crate_for(&self, file_id: FileId) -> Cancellable> { self.with_db(|db| parent_module::crate_for(db, file_id)) } /// Returns the edition of the given crate. - pub fn crate_edition(&self, crate_id: CrateId) -> Cancelable { + pub fn crate_edition(&self, crate_id: CrateId) -> Cancellable { self.with_db(|db| db.crate_graph()[crate_id].edition) } /// Returns the root file of the given crate. - pub fn crate_root(&self, crate_id: CrateId) -> Cancelable { + pub fn crate_root(&self, crate_id: CrateId) -> Cancellable { self.with_db(|db| db.crate_graph()[crate_id].root_file_id) } /// Returns the set of possible targets to run for the current file. - pub fn runnables(&self, file_id: FileId) -> Cancelable> { + pub fn runnables(&self, file_id: FileId) -> Cancellable> { self.with_db(|db| runnables::runnables(db, file_id)) } @@ -473,24 +473,24 @@ impl Analysis { &self, position: FilePosition, search_scope: Option, - ) -> Cancelable> { + ) -> Cancellable> { self.with_db(|db| runnables::related_tests(db, position, search_scope)) } /// Computes syntax highlighting for the given file - pub fn highlight(&self, file_id: FileId) -> Cancelable> { + pub fn highlight(&self, file_id: FileId) -> Cancellable> { self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false)) } /// Computes syntax highlighting for the given file range. - pub fn highlight_range(&self, frange: FileRange) -> Cancelable> { + pub fn highlight_range(&self, frange: FileRange) -> Cancellable> { self.with_db(|db| { syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false) }) } /// Computes syntax highlighting for the given file. - pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancelable { + pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancellable { self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id, rainbow)) } @@ -499,7 +499,7 @@ impl Analysis { &self, config: &CompletionConfig, position: FilePosition, - ) -> Cancelable>> { + ) -> Cancellable>> { self.with_db(|db| ide_completion::completions(db, config, position).map(Into::into)) } @@ -510,7 +510,7 @@ impl Analysis { position: FilePosition, full_import_path: &str, imported_name: String, - ) -> Cancelable> { + ) -> Cancellable> { Ok(self .with_db(|db| { ide_completion::resolve_completion_edits( @@ -533,7 +533,7 @@ impl Analysis { config: &AssistConfig, resolve: AssistResolveStrategy, frange: FileRange, - ) -> Cancelable> { + ) -> Cancellable> { self.with_db(|db| { let ssr_assists = ssr::ssr_assists(db, &resolve, frange); let mut acc = Assist::get(db, config, resolve, frange); @@ -548,7 +548,7 @@ impl Analysis { config: &DiagnosticsConfig, resolve: AssistResolveStrategy, file_id: FileId, - ) -> Cancelable> { + ) -> Cancellable> { self.with_db(|db| diagnostics::diagnostics(db, config, &resolve, file_id)) } @@ -559,7 +559,7 @@ impl Analysis { diagnostics_config: &DiagnosticsConfig, resolve: AssistResolveStrategy, frange: FileRange, - ) -> Cancelable> { + ) -> Cancellable> { let include_fixes = match &assist_config.allowed { Some(it) => it.iter().any(|&it| it == AssistKind::None || it == AssistKind::QuickFix), None => true, @@ -591,14 +591,14 @@ impl Analysis { &self, position: FilePosition, new_name: &str, - ) -> Cancelable> { + ) -> Cancellable> { self.with_db(|db| references::rename::rename(db, position, new_name)) } pub fn prepare_rename( &self, position: FilePosition, - ) -> Cancelable, RenameError>> { + ) -> Cancellable, RenameError>> { self.with_db(|db| references::rename::prepare_rename(db, position)) } @@ -606,7 +606,7 @@ impl Analysis { &self, file_id: FileId, new_name_stem: &str, - ) -> Cancelable> { + ) -> Cancellable> { self.with_db(|db| references::rename::will_rename_file(db, file_id, new_name_stem)) } @@ -616,7 +616,7 @@ impl Analysis { parse_only: bool, resolve_context: FilePosition, selections: Vec, - ) -> Cancelable> { + ) -> Cancellable> { self.with_db(|db| { let rule: ide_ssr::SsrRule = query.parse()?; let mut match_finder = @@ -631,11 +631,11 @@ impl Analysis { &self, file_id: FileId, config: AnnotationConfig, - ) -> Cancelable> { + ) -> Cancellable> { self.with_db(|db| annotations::annotations(db, file_id, config)) } - pub fn resolve_annotation(&self, annotation: Annotation) -> Cancelable { + pub fn resolve_annotation(&self, annotation: Annotation) -> Cancellable { self.with_db(|db| annotations::resolve_annotation(db, annotation)) } @@ -643,16 +643,28 @@ impl Analysis { &self, range: FileRange, direction: Direction, - ) -> Cancelable> { + ) -> Cancellable> { self.with_db(|db| move_item::move_item(db, range, direction)) } - /// Performs an operation on that may be Canceled. - fn with_db(&self, f: F) -> Cancelable + /// Performs an operation on the database that may be canceled. + /// + /// rust-analyzer needs to be able to answer semantic questions about the + /// code while the code is being modified. A common problem is that a + /// long-running query is being calculated when a new change arrives. + /// + /// We can't just apply the change immediately: this will cause the pending + /// query to see inconsistent state (it will observe an absence of + /// repeatable read). So what we do is we **cancel** all pending queries + /// before applying the change. + /// + /// Salsa implements cancelation by unwinding with a special value and + /// catching it on the API boundary. + fn with_db(&self, f: F) -> Cancellable where F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe, { - self.db.catch_canceled(f) + Cancelled::catch(|| f(&self.db)) } } diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs index 88ee4a87d5..1f900aef4b 100644 --- a/crates/ide_db/src/lib.rs +++ b/crates/ide_db/src/lib.rs @@ -19,8 +19,7 @@ use std::{fmt, sync::Arc}; use base_db::{ salsa::{self, Durability}, - AnchoredPath, Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, - SourceDatabase, Upcast, + AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast, }; use hir::db::{AstDatabase, DefDatabase, HirDatabase}; use rustc_hash::FxHashSet; @@ -80,20 +79,7 @@ impl FileLoader for RootDatabase { } } -impl salsa::Database for RootDatabase { - fn on_propagated_panic(&self) -> ! { - Canceled::throw() - } - fn salsa_event(&self, event: salsa::Event) { - match event.kind { - salsa::EventKind::DidValidateMemoizedValue { .. } - | salsa::EventKind::WillExecute { .. } => { - self.check_canceled(); - } - _ => (), - } - } -} +impl salsa::Database for RootDatabase {} impl Default for RootDatabase { fn default() -> RootDatabase { @@ -126,7 +112,7 @@ impl salsa::ParallelDatabase for RootDatabase { } #[salsa::query_group(LineIndexDatabaseStorage)] -pub trait LineIndexDatabase: base_db::SourceDatabase + CheckCanceled { +pub trait LineIndexDatabase: base_db::SourceDatabase { fn line_index(&self, file_id: FileId) -> Arc; } diff --git a/crates/ide_db/src/symbol_index.rs b/crates/ide_db/src/symbol_index.rs index 0f5c4abc4b..5c372a7e5e 100644 --- a/crates/ide_db/src/symbol_index.rs +++ b/crates/ide_db/src/symbol_index.rs @@ -127,7 +127,7 @@ fn library_symbols(db: &dyn SymbolsDatabase) -> Arc Arc { - db.check_canceled(); + db.unwind_if_cancelled(); let parse = db.parse(file_id); let symbols = source_file_to_file_symbols(&parse.tree(), file_id); diff --git a/crates/rust-analyzer/src/dispatch.rs b/crates/rust-analyzer/src/dispatch.rs index baf2199d94..2011a41322 100644 --- a/crates/rust-analyzer/src/dispatch.rs +++ b/crates/rust-analyzer/src/dispatch.rs @@ -5,7 +5,7 @@ use serde::{de::DeserializeOwned, Serialize}; use crate::{ global_state::{GlobalState, GlobalStateSnapshot}, - lsp_utils::is_canceled, + lsp_utils::is_cancelled, main_loop::Task, LspError, Result, }; @@ -132,7 +132,7 @@ where Err(e) => match e.downcast::() { Ok(lsp_error) => lsp_server::Response::new_err(id, lsp_error.code, lsp_error.message), Err(e) => { - if is_canceled(&*e) { + if is_cancelled(&*e) { lsp_server::Response::new_err( id, lsp_server::ErrorCode::ContentModified as i32, diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 6a36d29d4d..ea9dbf7fcd 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -7,7 +7,7 @@ use std::{sync::Arc, time::Instant}; use crossbeam_channel::{unbounded, Receiver, Sender}; use flycheck::FlycheckHandle; -use ide::{Analysis, AnalysisHost, Cancelable, Change, FileId}; +use ide::{Analysis, AnalysisHost, Cancellable, Change, FileId}; use ide_db::base_db::{CrateId, VfsPath}; use lsp_types::{SemanticTokens, Url}; use parking_lot::{Mutex, RwLock}; @@ -280,7 +280,7 @@ impl GlobalStateSnapshot { file_id_to_url(&self.vfs.read().0, id) } - pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancelable { + pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancellable { let endings = self.vfs.read().1[&file_id]; let index = self.analysis.file_line_index(file_id)?; let res = LineIndex { index, endings, encoding: self.config.offset_encoding() }; diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index 73c4193e88..8000b5490f 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs @@ -1,7 +1,7 @@ //! Utilities for LSP-related boilerplate code. use std::{error::Error, ops::Range, sync::Arc}; -use ide_db::base_db::Canceled; +use ide_db::base_db::Cancelled; use lsp_server::Notification; use crate::{ @@ -10,8 +10,8 @@ use crate::{ line_index::{LineEndings, LineIndex, OffsetEncoding}, }; -pub(crate) fn is_canceled(e: &(dyn Error + 'static)) -> bool { - e.downcast_ref::().is_some() +pub(crate) fn is_cancelled(e: &(dyn Error + 'static)) -> bool { + e.downcast_ref::().is_some() } pub(crate) fn notification_is( diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 008758ea0d..31d8ea9e7f 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -22,7 +22,7 @@ use crate::{ from_proto, global_state::{file_id_to_url, url_to_file_id, GlobalState}, handlers, lsp_ext, - lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, + lsp_utils::{apply_document_changes, is_cancelled, notification_is, Progress}, reload::{BuildDataProgress, ProjectWorkspaceProgress}, Result, }; @@ -752,7 +752,7 @@ impl GlobalState { .filter_map(|file_id| { handlers::publish_diagnostics(&snapshot, file_id) .map_err(|err| { - if !is_canceled(&*err) { + if !is_cancelled(&*err) { log::error!("failed to compute diagnostics: {:?}", err); } () diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 6d18d0ffc1..411f6baa97 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -6,7 +6,7 @@ use std::{ }; use ide::{ - Annotation, AnnotationKind, Assist, AssistKind, CallInfo, Cancelable, CompletionItem, + Annotation, AnnotationKind, Assist, AssistKind, CallInfo, Cancellable, CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint, InlayKind, InsertTextFormat, Markup, NavigationTarget, ReferenceAccess, RenameError, Runnable, @@ -726,7 +726,7 @@ pub(crate) fn snippet_text_document_edit( pub(crate) fn snippet_text_document_ops( snap: &GlobalStateSnapshot, file_system_edit: FileSystemEdit, -) -> Cancelable> { +) -> Cancellable> { let mut ops = Vec::new(); match file_system_edit { FileSystemEdit::CreateFile { dst, initial_contents } => { @@ -756,7 +756,7 @@ pub(crate) fn snippet_text_document_ops( let new_uri = snap.anchored_path(&dst); let mut rename_file = lsp_types::RenameFile { old_uri, new_uri, options: None, annotation_id: None }; - if snap.analysis.is_library_file(src) == Ok(true) + if snap.analysis.is_library_file(src).ok() == Some(true) && snap.config.change_annotation_support() { rename_file.annotation_id = Some(outside_workspace_annotation_id())