Skip to content

Conversation

@Zalathar
Copy link
Member

@Zalathar Zalathar commented Jan 24, 2026

In order to reduce compile times and code size for the compiler itself, the query system has a mechanism for “erasing” and ”restoring” query values in certain contexts. See #109333 for the original implementation.

Unfortunately, the erasure system has very little documentation, and involves a dizzying assortment of similarly-named types, traits, and functions.

This PR therefore renames several parts of the erasure API and implementation to hopefully be clearer, and adds comments to better explain the purpose and mechanism behind value erasure.

Summary of renames:

  • fn eraseerase_val (avoiding ambiguity with module erase)
  • fn restorerestore_val
  • type Erase<T>Erased<T> (for actual erased values of T)
  • trait EraseTypeErasable (for types that can be erased and restored)
  • associated type EraseType::ResultErasable::Storage
  • implementation-detail struct Erased<T>ErasedData<Storage>

There should be no change to compiler behaviour.

@rustbot rustbot added A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jan 24, 2026
@rustbot
Copy link
Collaborator

rustbot commented Jan 24, 2026

r? @SparrowLii

rustbot has assigned @SparrowLii.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

/// Trait for types that can be erased into [`Erased<Self>`].
///
/// Erasing and unerasing values is performed by [`erase_val`] and [`restore_val`].
pub trait Erasable: Copy {
Copy link
Member Author

@Zalathar Zalathar Jan 24, 2026

Choose a reason for hiding this comment

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

Erasable goes against the notional convention of naming traits after verbs rather than adjectives, but in this case I find erasable so much clearer that I think it's justified.

Copy link
Member

@workingjubilee workingjubilee Jan 24, 2026

Choose a reason for hiding this comment

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

certainly can't be worse the status quo, since it wasn't Erase before. what does "EraseType" mean? "you can erase this type"? yeah it implements the trait, doesn't it?

( type Erase simply doesn't make much sense to me. )

@rust-bors

This comment has been minimized.

@rustbot
Copy link
Collaborator

rustbot commented Jan 25, 2026

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@petrochenkov
Copy link
Contributor

r? @petrochenkov

@rustbot rustbot assigned petrochenkov and unassigned SparrowLii Jan 26, 2026
const {
if size_of::<T>() != size_of::<T::Result>() {
if size_of::<T>() != size_of::<T::Storage>() {
panic!("size of T must match erased type T::Result")
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
panic!("size of T must match erased type T::Result")
panic!("size of T must match erased type T::Storage")

Erased::<<T as EraseType>::Result> {
ErasedData::<<T as Erasable>::Storage> {
// `transmute_unchecked` is needed here because it does not have `transmute`'s size check
// (and thus allows to transmute between `T` and `MaybeUninit<T::Result>`) (we do the size
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// (and thus allows to transmute between `T` and `MaybeUninit<T::Result>`) (we do the size
// (and thus allows to transmute between `T` and `MaybeUninit<T::Storage>`) (we do the size

$(
impl<'tcx> EraseType for $($fake_path)::+<'tcx> {
type Result = [u8; size_of::<$($fake_path)::+<'static>>()];
impl<'tcx> Erasable for $($fake_path)::+<'tcx> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
impl<'tcx> Erasable for $($fake_path)::+<'tcx> {
impl Erasable for $($fake_path)::+<'_> {

I think this will work for any paths with one lifetime argument at the end, not just 'tcx.
A number of explicit impls from the above can probably be merged into this macro too.

let key = key.into_query_param();
if let Some(res) = try_get_cached(tcx, query_cache, &key) {
erase::restore(res).map(drop)
erase::restore_val(res).map(drop)
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, why drop?
Erasable types are Copy, they cannot have any nontrivial drop.

queries::$name::Key<'tcx>,
QueryMode,
) -> Option<Erase<$V>>,)*
) -> Option<::rustc_middle::query::erase::Erased<$V>>,)*
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
) -> Option<::rustc_middle::query::erase::Erased<$V>>,)*
) -> Option<$crate::query::erase::Erased<$V>>,)*

And two more instances above.

We are in rustc_middle, so this looks a bit weird in declarative macros, but it's a matter of style. Other code above uses $crate though.

@petrochenkov petrochenkov added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 26, 2026
Copy link
Contributor

@zetanumbers zetanumbers left a comment

Choose a reason for hiding this comment

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

I don't find these changes to be useful or clarifying.

View changes since this review

Comment on lines +1 to +3
//! To improve compile times and code size for the compiler itself, query
//! values are "erased" in some contexts (e.g. inside in-memory cache types),
//! to reduce the number of generic instantiations created during codegen.
Copy link
Contributor

@zetanumbers zetanumbers Jan 26, 2026

Choose a reason for hiding this comment

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

Source of this statement needs clarification. Benchmarks on the original PR (#109333 (comment)) do not seem to have introduced improvements.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, it would be good to check if it's still necessary.
#108638 says "The compile time of rustc_query_impl is reduced by 27%" which by itself doesn't sound like a convincing reason to complicate the query system, but pictures like #65031 (comment) make it more convincing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-query-system Area: The rustc query system (https://rustc-dev-guide.rust-lang.org/query.html) S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants