Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

internal: port rust-analyzer to new Salsa #18964

Draft
wants to merge 25 commits into
base: master
Choose a base branch
from

Conversation

davidbarsky
Copy link
Contributor

This PR ports rust-analyzer to the new Salsa. It is big, partially incomplete, and best reviewed commit-by-commit. I will be rebasing often.

(Why new Salsa? It unblocks a lot of work described in #17491.)

Migration Approach

To get rust-analyzer compiling and passing tests, this PR did the following:

With these changes, all tests were passing (no correctness issues!), analysis-stats produced the same results as rust-analyzer on the old Salsa, and—critically—the new Salsa-powered rust-analyzer was usable as my daily driver. Unfortunately, memory usage was too high. I'm really grateful to the following folks who helped fix that regression:

Performance

  • On rust-analyzer analysis-stats, new Salsa is slightly slower and uses slightly more memory.
    • On bfb8127, new Salsa uses 2201mb of memory, whereas old Salsa uses ~2000 megabytes.
  • On crates/rust-analyzer/src/integrated_benchmarks.rs, new Salsa is slightly faster on both cold and warm updates. These benchmarks should probably be more rigorous, but new Salsa was consistently faster.

Things to Fix Before to Merging

There's a few things to do before this change is merged:

  1. Reintroduce debug item printing. However, this is blocked on feature: Add support for dumping database contents salsa-rs/salsa#640 and some additional changes inside of rust-analyzer, but they're not complicated changes.
  2. Figure out why the changes in the enum/#[salsa::supertype] commit cause tests to fail to type confusion in the underlying Salsa pages. Chayim is working on root-causing this, but if he's unable to determine the cause, I can make the enum changes a separate pull request.
  3. Release db-ext-macro.
    1. I'd like to rename db-ext-macro to something else, or have it live in Salsa. I'm unsure which option I'd prefer right now.
  4. Release the new Salsa to crates.io.

Acknowledgements

This wouldn't have been possible without the assistance of many folks including @ChayimFriedman2, @ShoyuVanilla, @nikomatsakis, and @Veykril. I'm sure I'm forgetting some people, to whom I apologize.

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jan 17, 2025
@davidbarsky davidbarsky force-pushed the davidbarsky/port-rust-analyzer-to-new-salsa branch 2 times, most recently from e2767ec to 3a7fd79 Compare January 20, 2025 22:54
@davidbarsky
Copy link
Contributor Author

Chayim fixed the test failures: this was due us mixing and matching Salsa interning with rust-analyzer's own, home-grown interning. He put it succinctly here:

My macro also implements traits like Eq and Hash. And it implements them by hashing the ID only, because I thought it will be more efficient.
But have we global, unrelated to salsa, interning. For example, that's how we intern Tys. And this global interning will persist even after we switch dbs. But in different dbs, different IDs can map to different kinds!
So we might switch the type of an AdtId, for example, because we mapped it to the incorrect interned key!

As a short-term fix, he's required interned values to implement PartialEq and friends. Longer-term, we'll move this interner into new Salsa.

@davidbarsky davidbarsky force-pushed the davidbarsky/port-rust-analyzer-to-new-salsa branch 2 times, most recently from c85177e to c762e4e Compare January 24, 2025 21:19
@the8472
Copy link
Member

the8472 commented Jan 25, 2025

reduced rust-analyzer's memory usage on analysis-stats from 8 gigabytes to 4 gigabytes by through https://lgithub.com/salsa-rs/salsa/pull/614/.

contains a typo in the link

@Veykril
Copy link
Member

Veykril commented Jan 25, 2025

Regarding db-ext-macro's home, we could also consider placing it in-tree here. That might be easiest tbh.

Copy link
Member

@Veykril Veykril left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(partial review)

@@ -11,7 +11,7 @@ authors = ["rust-analyzer team"]
repository = "https://github.com/rust-lang/rust-analyzer"

[profile.dev]
debug = 1
debug = 2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
debug = 2
debug = 1

(reminder)

@@ -27,7 +27,7 @@ miniz_oxide.opt-level = 3
[profile.release]
incremental = true
# Set this to 1 or 2 to get more useful backtraces in debugger.
debug = 0
debug = 2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
debug = 2
debug = 0

(reminder)
also for this you could use the dev-rel profile

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how come that there are formatting changes in here (without CI ever complaining about them) 🤨

Comment on lines -58 to +64
#[cfg(not(feature = "cpu_profiler"))]
#[allow(clippy::print_stderr)]
{
eprintln!(
r#"cpu profiling is disabled, uncomment `default = [ "cpu_profiler" ]` in Cargo.toml to enable."#
);
}
// #[cfg(not(feature = "cpu_profiler"))]
// #[allow(clippy::print_stderr)]
// {
// eprintln!(
// r#"cpu profiling is disabled, uncomment `default = [ "cpu_profiler" ]` in Cargo.toml to enable."#
// );
// }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whats up with this

Comment on lines -4 to -6
#[cfg(feature = "ra-salsa")]
use ra_salsa::InternId;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we re-introduce this cfg'ing for the new salsa? The point of that is that the proc-macro server has no need to depend on salsa

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whats up with the changes here?


#[salsa::interned(no_lifetime)]
pub struct EditionedFileId {
pub file_id: FileText,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub file_id: FileText,
pub file_id: vfs::FileId,

@davidbarsky
Copy link
Contributor Author

@Veykril Regarding crates/rust-analyzer/src/cli/rustc_tests.rs, it looks like some parts of new Salsa—namely, (dyn salsa::accumulator::accumulated::AnyAccumulated + 'static)—don't implement UnwindSafe. Here's the error:

error[E0277]: the type `(dyn salsa::accumulator::accumulated::AnyAccumulated + 'static)` may not be safely transferred across an unwind boundary
    --> crates/rust-analyzer/src/cli/rustc_tests.rs:163:60
     |
163  |                           let res = std::panic::catch_unwind(move || {
     |  ___________________________________------------------------_^
     | |                                   |
     | |                                   required by a bound introduced by this call
164  | |                             analysis.full_diagnostics(
165  | |                                 diagnostic_config,
166  | |                                 ide::AssistResolveStrategy::None,
...    |
169  | |                         });
     | |_________________________^ `(dyn salsa::accumulator::accumulated::AnyAccumulated + 'static)` may not be safely transferred across an unwind boundary
     |
     = help: the trait `UnwindSafe` is not implemented for `(dyn salsa::accumulator::accumulated::AnyAccumulated + 'static)`
     = note: required for `std::ptr::Unique<(dyn salsa::accumulator::accumulated::AnyAccumulated + 'static)>` to implement `UnwindSafe`
note: required because it appears within the type `std::boxed::Box<(dyn salsa::accumulator::accumulated::AnyAccumulated + 'static)>`
    --> /Users/dbarsky/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/boxed.rs:231:12
     |
231  | pub struct Box<
     |            ^^^
     = note: required for `HashMap<IngredientIndex, std::boxed::Box<(dyn salsa::accumulator::accumulated::AnyAccumulated + 'static)>, FxBuildHasher>` to implement `UnwindSafe`
note: required because it appears within the type `salsa::accumulator::accumulated_map::AccumulatedMap`
    --> /Users/dbarsky/.cargo/git/checkouts/salsa-deab236162935b01/592552b/src/accumulator/accumulated_map.rs:10:12
     |
10   | pub struct AccumulatedMap {
     |            ^^^^^^^^^^^^^^
note: required because it appears within the type `salsa::active_query::ActiveQuery`
    --> /Users/dbarsky/.cargo/git/checkouts/salsa-deab236162935b01/592552b/src/active_query.rs:17:19
     |
17   | pub(crate) struct ActiveQuery {
     |                   ^^^^^^^^^^^
note: required because it appears within the type `std::marker::PhantomData<salsa::active_query::ActiveQuery>`
    --> /Users/dbarsky/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/marker.rs:757:12
     |
757  | pub struct PhantomData<T: ?Sized>;
     |            ^^^^^^^^^^^
note: required because it appears within the type `alloc::raw_vec::RawVec<salsa::active_query::ActiveQuery>`
    --> /Users/dbarsky/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/raw_vec.rs:70:19
     |
70   | pub(crate) struct RawVec<T, A: Allocator = Global> {
     |                   ^^^^^^
note: required because it appears within the type `Vec<salsa::active_query::ActiveQuery>`
    --> /Users/dbarsky/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs:397:12
     |
397  | pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
     |            ^^^
note: required because it appears within the type `std::cell::UnsafeCell<Vec<salsa::active_query::ActiveQuery>>`
    --> /Users/dbarsky/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/cell.rs:2076:12
     |
2076 | pub struct UnsafeCell<T: ?Sized> {
     |            ^^^^^^^^^^
note: required because it appears within the type `RefCell<Vec<salsa::active_query::ActiveQuery>>`
    --> /Users/dbarsky/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/cell.rs:730:12
     |
730  | pub struct RefCell<T: ?Sized> {
     |            ^^^^^^^
note: required because it appears within the type `ZalsaLocal`
    --> /Users/dbarsky/.cargo/git/checkouts/salsa-deab236162935b01/592552b/src/zalsa_local.rs:30:12
     |
30   | pub struct ZalsaLocal {
     |            ^^^^^^^^^^
note: required because it appears within the type `Storage<RootDatabase>`
    --> /Users/dbarsky/.cargo/git/checkouts/salsa-deab236162935b01/592552b/src/storage.rs:25:12
     |
25   | pub struct Storage<Db: Database> {
     |            ^^^^^^^
note: required because it appears within the type `std::mem::ManuallyDrop<Storage<RootDatabase>>`
    --> /Users/dbarsky/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/mem/manually_drop.rs:157:12
     |
157  | pub struct ManuallyDrop<T: ?Sized> {
     |            ^^^^^^^^^^^^
note: required because it appears within the type `RootDatabase`
    --> /Users/dbarsky/Developer/rust-analyzer/crates/ide-db/src/lib.rs:79:12
     |
79   | pub struct RootDatabase {
     |            ^^^^^^^^^^^^
note: required because it appears within the type `Analysis`
    --> /Users/dbarsky/Developer/rust-analyzer/crates/ide/src/lib.rs:219:12
     |
219  | pub struct Analysis {
     |            ^^^^^^^^
note: required because it's used within this closure
    --> crates/rust-analyzer/src/cli/rustc_tests.rs:163:60
     |
163  |                         let res = std::panic::catch_unwind(move || {
     |                                                            ^^^^^^^
note: required by a bound in `std::panic::catch_unwind`
    --> /Users/dbarsky/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/panic.rs:357:40
     |
357  | pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
     |                                        ^^^^^^^^^^ required by this bound in `catch_unwind`

I think that #19093 is also slightly problematic from a "get rust-analyzer to compile" standpoint, but I don't know enough about unwind safety to say whether I should wrap analysis— and therefore, accumulators—in a AssertUnwindSafe as the documentation points out. Put differently, if rust-analyzer was to make more pervasive use of accumulators, would we risk getting incorrect results, or...?

@davidbarsky davidbarsky force-pushed the davidbarsky/port-rust-analyzer-to-new-salsa branch from 54ef4ea to 83fe206 Compare February 5, 2025 18:45
@davidbarsky
Copy link
Contributor Author

I decided to wrap some Analysis calls in AssertUnwindSafe, as we're not really using accumulators in rust-analyzer. Once we do, I think it might be a good idea to revisit that usage.

@Veykril
Copy link
Member

Veykril commented Feb 5, 2025

That's fine, the problematic type only appears within ActiveQuery, the query stack of the runtime which is always empty at this point. So AssertUnwindSafe is okay to be used here

@davidbarsky
Copy link
Contributor Author

Alright, few updates:

Debug Printing

I put up salsa-rs/salsa#676, which makes it possible for us to access the underlying data without involving a salsa::Database's storage (which may not be accessible!). I've used this to port over dump_syntax_contexts in crates/hir-expand/src/hygiene.rs locally, but I haven't pushed yet—I will, though.

Unfortunately, the approach is not applicable to debug printing in crates/ide/src/status.rs, as we'd need to access a tracked function's memos and it's not immediately obvious to me how to do that. Given that it's a single-digit number of queries1, I think I'd prefer to accept a regression in the quality of debug output and prioritize porting those queries over to idiomatic Salsa (c.f., #19098), especially since we've blocked landing any database changes until this PR lands.

Enums

I've also opened salsa-rs/salsa#677, which mostly just publishes @ChayimFriedman2's #[salsa::enum]/#[salsa::supertype] work.

Footnotes

  1. The queries in question are SourceDatabase::file_text, RootQueryDb::parse, ExpandDatabase::parse_macro_expansion, SymbolsDatabase::module_symbols, SymbolsDatabase::library_symbols, ExpandDatabase::ast_id_map, and DefDatabase::block_def_map.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants