Skip to content

internal: Migrate HirDatabase away from #[query_group]; remove the latter#22831

Open
ada4a wants to merge 5 commits into
rust-lang:masterfrom
ada4a:unquerygroup-hirdatabase
Open

internal: Migrate HirDatabase away from #[query_group]; remove the latter#22831
ada4a wants to merge 5 commits into
rust-lang:masterfrom
ada4a:unquerygroup-hirdatabase

Conversation

@ada4a

@ada4a ada4a commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Resolves #22657 🎉

See #t-compiler/rust-analyzer > Migrating `HirDatabase` for discussion, and individual commits for details.

ada4a added 3 commits July 15, 2026 21:28
- don't `push_ty_diagnostics` with an empty list
- use `lookup_resolver`
The next commit would require us to `impl HirDatabase for dyn
SourceDatabase + Debug`, but that wouldn't work, as trait objects can't
specify multiple (non-auto) traits. Since we're going to change all the
users of `dyn HirDatabase` to `dyn SourceDatabase` anyway, we can push
the `Debug` bound down to the latter.
@ada4a ada4a changed the title Migrate HirDatabase away from #[query_group]; remove the latter internal: Migrate HirDatabase away from #[query_group]; remove the latter Jul 16, 2026
@ada4a
ada4a marked this pull request as ready for review July 16, 2026 08:17
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jul 16, 2026

@ChayimFriedman2 ChayimFriedman2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't like the many places that need to explicitly coerce to &dyn SourceDatabase. I think a better solution is to add fn as_dyn(&self) -> &dyn SourceDatabase to RootDatabase and TestDB. Maybe even implement Deref, although that's probably a bad idea.

View changes since this review

ada4a added 2 commits July 17, 2026 10:36
The remaining methods in the query group didn't really have a good place
to migrate them to, as they were all defined on `hir-def` types.
Therefore, we basically left them inside `HirDatabase`, but changed the
latter from a `#[query_group]` to an extension trait on
`SourceDatabase`.

This means that, in order to use its queries, one needs to bring it into
scope. In particular, when working with a concrete
`TestDB`/`RootDatabase`, one needs to first explicitly cast it to a
`&dyn SourceDatabase`, so that the compiler can then cast it to `&dyn
HirDatabase` as needed. To make this more ergonomic, we introduce the
`as_dyn` method on `TestDB` and `RootDatabase`.
@ada4a
ada4a force-pushed the unquerygroup-hirdatabase branch from 5b54e09 to c110819 Compare July 17, 2026 08:37
@ada4a

ada4a commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

Done. Though I worry that future contributors will have a hard time discovering as_dyn, and may end up doing the cast explicitly. Honestly even that I'm not sure about -- one'd need to come up with casting to &dyn SourceDatabase just to let the compiler see the HirDatabase impl on that (db as &dyn SourceDatabase as &dyn HirDatabase doesn't even work)

Comment thread crates/hir-ty/src/db.rs
Comment on lines +39 to +48
pub trait HirDatabase: SourceDatabase {
fn as_dyn_source_database(&self) -> &dyn SourceDatabase;

// region:mir

// FIXME: Collapse `mir_body_for_closure` into `mir_body`
// and `monomorphized_mir_body_for_closure` into `monomorphized_mir_body`
#[salsa::transparent]
fn mir_body(&self, def: InferBodyId) -> Result<&MirBody, MirLowerError> {
crate::mir::mir_body_query(self, def).map_err(|err| err.clone())
let db = self.as_dyn_source_database();
crate::mir::mir_body_query(db, def).map_err(|err| err.clone())

@Veykril Veykril Jul 17, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Given we are keeping the database trait, why do we even need to swap all the trait objects from HirDatabase to SourceDatabase?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Wouldn't doing otherwise lead to circular reasoning? mir_body_query would require the caller to be &dyn HirDatabase, but we'd want to call it inside HirDatabase::mir_body, which.. doesn't yet know that the caller implements HirDatabase, as we're in the process of implementing it.

Besides, it looks like I can't annotate functions taking db: &dyn HirDatabase with #[salsa::tracked], probably because the it's no longer a salsa db:

error[E0576]: cannot find method or associated constant `zalsa_register_downcaster` in trait `HirDatabase`
    --> crates/hir-ty/src/mir/lower.rs:2285:1
     |
2285 | #[salsa_macros::tracked(returns(as_ref), cycle_result = mir_body_cycle_result)]
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in `HirDatabase`
     |
     = note: this error originates in the macro `salsa::plumbing::setup_tracked_fn` which comes from the expansion of the attribute macro `salsa_macros::tracked` (in Nightly builds, run with -Z macro-backtrace for more info)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That salsa error is because you need to annotate the trait with #[salsa::database] (or some attribute name).

I don't see a circular reasoning here. Sure, things can end up recursive in calls (with different function arguments etc) but thats the case already today. In general in Rust inside of trait definitions the Self generic argument is assumed to implement the trait itself so you can use that fact just fine.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If I remove the let db = self.as_dyn_source_database(); line and try to pass self directly, I get back to this error:

error[E0277]: the size for values of type `Self` cannot be known at compilation time
  --> crates/hir-ty/src/db.rs:48:36
   |
48 |         crate::mir::mir_body_query(self, def).map_err(|err| err.clone())
   |                                    ^^^^ doesn't have a size known at compile-time
   |
   = note: required for the cast from `&Self` to `&(dyn HirDatabase + 'static)`
help: consider further restricting `Self`
   |
47 |     fn mir_body(&self, def: InferBodyId) -> Result<&MirBody, MirLowerError> where Self: std::marker::Sized {
   | 

Do you know how I'd solve that?...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we need a 'static super trait bound? That is trait HirDatabase: SourceDatabase + 'static

@ada4a ada4a Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

But that would require the implementer to be dyn SourceDatabase + 'static, which doesn't sound right? Well, it didn't work anyway...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It looks like I can fix this by, once again, moving the method definitions from the trait definition to the impl. But that's ugly...

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.

Tracking issue for migrating away from #[query_group]

4 participants