From 33debc40654be9e9061c53784f6c762b2fd21eba Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 17 May 2021 19:07:10 +0200 Subject: Update salsa --- crates/ide/src/lib.rs | 128 +++++++++++++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 58 deletions(-) (limited to 'crates/ide') diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index ff2a54117..97c9e5d2b 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)) } } -- cgit v1.2.3