Skip to content

Commit 0765b43

Browse files
authored
Rollup merge of #147393 - Zalathar:feed, r=cjgillot
Extract most code from `define_feedable!` This PR extracts most of the non-trivial code from the `define_feedable!` macro (which defines the `TyCtxtFeed::$query` methods), and moves it to a helper function `query_feed_inner` written in ordinary non-macro code. Doing so should make that code easier to read and modify, because it now gets proper IDE support and has explicit trait bounds. --- There should be no change in compiler behaviour. I've structured the commits so that the actual extraction part is mostly just whitespace changes, making it easier to review individually with whitespace changes hidden.
2 parents b96bd11 + a282336 commit 0765b43

File tree

3 files changed

+160
-123
lines changed

3 files changed

+160
-123
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//! Helper functions that serve as the immediate implementation of
2+
//! `tcx.$query(..)` and its variations.
3+
4+
use std::fmt::Debug;
5+
6+
use rustc_data_structures::fingerprint::Fingerprint;
7+
use rustc_query_system::dep_graph::{DepKind, DepNodeParams};
8+
use rustc_query_system::ich::StableHashingContext;
9+
use rustc_query_system::query::{QueryCache, QueryMode, try_get_cached};
10+
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
11+
12+
use crate::dep_graph;
13+
use crate::query::IntoQueryParam;
14+
use crate::query::erase::{self, Erase, EraseType};
15+
use crate::ty::TyCtxt;
16+
17+
/// Shared implementation of `tcx.$query(..)` and `tcx.at(span).$query(..)`
18+
/// for all queries.
19+
#[inline(always)]
20+
pub(crate) fn query_get_at<'tcx, Cache>(
21+
tcx: TyCtxt<'tcx>,
22+
execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
23+
query_cache: &Cache,
24+
span: Span,
25+
key: Cache::Key,
26+
) -> Cache::Value
27+
where
28+
Cache: QueryCache,
29+
{
30+
let key = key.into_query_param();
31+
match try_get_cached(tcx, query_cache, &key) {
32+
Some(value) => value,
33+
None => execute_query(tcx, span, key, QueryMode::Get).unwrap(),
34+
}
35+
}
36+
37+
/// Shared implementation of `tcx.ensure_ok().$query(..)` for most queries,
38+
/// and `tcx.ensure_done().$query(..)` for all queries.
39+
#[inline]
40+
pub(crate) fn query_ensure<'tcx, Cache>(
41+
tcx: TyCtxt<'tcx>,
42+
execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
43+
query_cache: &Cache,
44+
key: Cache::Key,
45+
check_cache: bool,
46+
) where
47+
Cache: QueryCache,
48+
{
49+
let key = key.into_query_param();
50+
if try_get_cached(tcx, query_cache, &key).is_none() {
51+
execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache });
52+
}
53+
}
54+
55+
/// Shared implementation of `tcx.ensure_ok().$query(..)` for queries that
56+
/// have the `return_result_from_ensure_ok` modifier.
57+
#[inline]
58+
pub(crate) fn query_ensure_error_guaranteed<'tcx, Cache, T>(
59+
tcx: TyCtxt<'tcx>,
60+
execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
61+
query_cache: &Cache,
62+
key: Cache::Key,
63+
check_cache: bool,
64+
) -> Result<(), ErrorGuaranteed>
65+
where
66+
Cache: QueryCache<Value = Erase<Result<T, ErrorGuaranteed>>>,
67+
Result<T, ErrorGuaranteed>: EraseType,
68+
{
69+
let key = key.into_query_param();
70+
if let Some(res) = try_get_cached(tcx, query_cache, &key) {
71+
erase::restore(res).map(drop)
72+
} else {
73+
execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache })
74+
.map(erase::restore)
75+
.map(|res| res.map(drop))
76+
// Either we actually executed the query, which means we got a full `Result`,
77+
// or we can just assume the query succeeded, because it was green in the
78+
// incremental cache. If it is green, that means that the previous compilation
79+
// that wrote to the incremental cache compiles successfully. That is only
80+
// possible if the cache entry was `Ok(())`, so we emit that here, without
81+
// actually encoding the `Result` in the cache or loading it from there.
82+
.unwrap_or(Ok(()))
83+
}
84+
}
85+
86+
/// Common implementation of query feeding, used by `define_feedable!`.
87+
pub(crate) fn query_feed<'tcx, Cache, Value>(
88+
tcx: TyCtxt<'tcx>,
89+
dep_kind: DepKind,
90+
hasher: Option<fn(&mut StableHashingContext<'_>, &Value) -> Fingerprint>,
91+
cache: &Cache,
92+
key: Cache::Key,
93+
erased: Erase<Value>,
94+
) where
95+
Cache: QueryCache<Value = Erase<Value>>,
96+
Cache::Key: DepNodeParams<TyCtxt<'tcx>>,
97+
Value: EraseType + Debug,
98+
{
99+
let value = erase::restore::<Value>(erased);
100+
101+
match try_get_cached(tcx, cache, &key) {
102+
Some(old) => {
103+
let old = erase::restore::<Value>(old);
104+
if let Some(hasher) = hasher {
105+
let (value_hash, old_hash): (Fingerprint, Fingerprint) = tcx
106+
.with_stable_hashing_context(|mut hcx| {
107+
(hasher(&mut hcx, &value), hasher(&mut hcx, &old))
108+
});
109+
if old_hash != value_hash {
110+
// We have an inconsistency. This can happen if one of the two
111+
// results is tainted by errors. In this case, delay a bug to
112+
// ensure compilation is doomed, and keep the `old` value.
113+
tcx.dcx().delayed_bug(format!(
114+
"Trying to feed an already recorded value for query {dep_kind:?} key={key:?}:\n\
115+
old value: {old:?}\nnew value: {value:?}",
116+
));
117+
}
118+
} else {
119+
// The query is `no_hash`, so we have no way to perform a sanity check.
120+
// If feeding the same value multiple times needs to be supported,
121+
// the query should not be marked `no_hash`.
122+
bug!(
123+
"Trying to feed an already recorded value for query {dep_kind:?} key={key:?}:\n\
124+
old value: {old:?}\nnew value: {value:?}",
125+
)
126+
}
127+
}
128+
None => {
129+
let dep_node = dep_graph::DepNode::construct(tcx, dep_kind, &key);
130+
let dep_node_index = tcx.dep_graph.with_feed_task(dep_node, tcx, &value, hasher);
131+
cache.complete(key, erased, dep_node_index);
132+
}
133+
}
134+
}

compiler/rustc_middle/src/query/mod.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ use std::sync::Arc;
7070
use rustc_abi::Align;
7171
use rustc_arena::TypedArena;
7272
use rustc_ast::expand::allocator::AllocatorKind;
73-
use rustc_data_structures::fingerprint::Fingerprint;
7473
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
7574
use rustc_data_structures::sorted_map::SortedMap;
7675
use rustc_data_structures::steal::Steal;
@@ -88,9 +87,7 @@ use rustc_index::IndexVec;
8887
use rustc_lint_defs::LintId;
8988
use rustc_macros::rustc_queries;
9089
use rustc_query_system::ich::StableHashingContext;
91-
use rustc_query_system::query::{
92-
QueryCache, QueryMode, QueryStackDeferred, QueryState, try_get_cached,
93-
};
90+
use rustc_query_system::query::{QueryMode, QueryStackDeferred, QueryState};
9491
use rustc_session::Limits;
9592
use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
9693
use rustc_session::cstore::{
@@ -103,6 +100,8 @@ use rustc_span::{DUMMY_SP, Span, Symbol};
103100
use rustc_target::spec::{PanicStrategy, SanitizerSet};
104101
use {rustc_abi as abi, rustc_ast as ast, rustc_hir as hir};
105102

103+
pub use self::keys::{AsLocalKey, Key, LocalCrate};
104+
pub use self::plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsureDone, TyCtxtEnsureOk};
106105
use crate::infer::canonical::{self, Canonical};
107106
use crate::lint::LintExpectation;
108107
use crate::metadata::ModChild;
@@ -119,9 +118,7 @@ use crate::mir::interpret::{
119118
};
120119
use crate::mir::mono::{CodegenUnit, CollectionMode, MonoItem, MonoItemPartitions};
121120
use crate::query::erase::{Erase, erase, restore};
122-
use crate::query::plumbing::{
123-
CyclePlaceholder, DynamicQuery, query_ensure, query_ensure_error_guaranteed, query_get_at,
124-
};
121+
use crate::query::plumbing::{CyclePlaceholder, DynamicQuery};
125122
use crate::traits::query::{
126123
CanonicalAliasGoal, CanonicalDropckOutlivesGoal, CanonicalImpliedOutlivesBoundsGoal,
127124
CanonicalMethodAutoderefStepsGoal, CanonicalPredicateGoal, CanonicalTypeOpAscribeUserTypeGoal,
@@ -145,12 +142,11 @@ use crate::{dep_graph, mir, thir};
145142

146143
mod arena_cached;
147144
pub mod erase;
145+
pub(crate) mod inner;
148146
mod keys;
149-
pub use keys::{AsLocalKey, Key, LocalCrate};
150147
pub mod on_disk_cache;
151148
#[macro_use]
152149
pub mod plumbing;
153-
pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsureDone, TyCtxtEnsureOk};
154150

155151
// Each of these queries corresponds to a function pointer field in the
156152
// `Providers` struct for requesting a value of that type, and a method

compiler/rustc_middle/src/query/plumbing.rs

Lines changed: 21 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use rustc_query_system::HandleCycleError;
88
use rustc_query_system::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
99
pub(crate) use rustc_query_system::query::QueryJobId;
1010
use rustc_query_system::query::*;
11-
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
11+
use rustc_span::{ErrorGuaranteed, Span};
12+
pub use sealed::IntoQueryParam;
1213

1314
use crate::dep_graph;
1415
use crate::dep_graph::DepKind;
@@ -165,78 +166,17 @@ impl<'tcx> TyCtxt<'tcx> {
165166
}
166167
}
167168

168-
#[inline(always)]
169-
pub fn query_get_at<'tcx, Cache>(
170-
tcx: TyCtxt<'tcx>,
171-
execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
172-
query_cache: &Cache,
173-
span: Span,
174-
key: Cache::Key,
175-
) -> Cache::Value
176-
where
177-
Cache: QueryCache,
178-
{
179-
let key = key.into_query_param();
180-
match try_get_cached(tcx, query_cache, &key) {
181-
Some(value) => value,
182-
None => execute_query(tcx, span, key, QueryMode::Get).unwrap(),
183-
}
184-
}
185-
186-
#[inline]
187-
pub fn query_ensure<'tcx, Cache>(
188-
tcx: TyCtxt<'tcx>,
189-
execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
190-
query_cache: &Cache,
191-
key: Cache::Key,
192-
check_cache: bool,
193-
) where
194-
Cache: QueryCache,
195-
{
196-
let key = key.into_query_param();
197-
if try_get_cached(tcx, query_cache, &key).is_none() {
198-
execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache });
199-
}
200-
}
201-
202-
#[inline]
203-
pub fn query_ensure_error_guaranteed<'tcx, Cache, T>(
204-
tcx: TyCtxt<'tcx>,
205-
execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
206-
query_cache: &Cache,
207-
key: Cache::Key,
208-
check_cache: bool,
209-
) -> Result<(), ErrorGuaranteed>
210-
where
211-
Cache: QueryCache<Value = super::erase::Erase<Result<T, ErrorGuaranteed>>>,
212-
Result<T, ErrorGuaranteed>: EraseType,
213-
{
214-
let key = key.into_query_param();
215-
if let Some(res) = try_get_cached(tcx, query_cache, &key) {
216-
super::erase::restore(res).map(drop)
217-
} else {
218-
execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache })
219-
.map(super::erase::restore)
220-
.map(|res| res.map(drop))
221-
// Either we actually executed the query, which means we got a full `Result`,
222-
// or we can just assume the query succeeded, because it was green in the
223-
// incremental cache. If it is green, that means that the previous compilation
224-
// that wrote to the incremental cache compiles successfully. That is only
225-
// possible if the cache entry was `Ok(())`, so we emit that here, without
226-
// actually encoding the `Result` in the cache or loading it from there.
227-
.unwrap_or(Ok(()))
228-
}
229-
}
230-
231-
macro_rules! query_ensure {
169+
/// Calls either `query_ensure` or `query_ensure_error_guaranteed`, depending
170+
/// on whether the list of modifiers contains `return_result_from_ensure_ok`.
171+
macro_rules! query_ensure_select {
232172
([]$($args:tt)*) => {
233-
query_ensure($($args)*)
173+
crate::query::inner::query_ensure($($args)*)
234174
};
235175
([(return_result_from_ensure_ok) $($rest:tt)*]$($args:tt)*) => {
236-
query_ensure_error_guaranteed($($args)*).map(|_| ())
176+
crate::query::inner::query_ensure_error_guaranteed($($args)*)
237177
};
238178
([$other:tt $($modifiers:tt)*]$($args:tt)*) => {
239-
query_ensure!([$($modifiers)*]$($args)*)
179+
query_ensure_select!([$($modifiers)*]$($args)*)
240180
};
241181
}
242182

@@ -432,7 +372,7 @@ macro_rules! define_callbacks {
432372
self,
433373
key: query_helper_param_ty!($($K)*),
434374
) -> ensure_ok_result!([$($modifiers)*]) {
435-
query_ensure!(
375+
query_ensure_select!(
436376
[$($modifiers)*]
437377
self.tcx,
438378
self.tcx.query_system.fns.engine.$name,
@@ -447,7 +387,7 @@ macro_rules! define_callbacks {
447387
$($(#[$attr])*
448388
#[inline(always)]
449389
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
450-
query_ensure(
390+
crate::query::inner::query_ensure(
451391
self.tcx,
452392
self.tcx.query_system.fns.engine.$name,
453393
&self.tcx.query_system.caches.$name,
@@ -472,7 +412,7 @@ macro_rules! define_callbacks {
472412
#[inline(always)]
473413
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V
474414
{
475-
restore::<$V>(query_get_at(
415+
restore::<$V>(crate::query::inner::query_get_at(
476416
self.tcx,
477417
self.tcx.query_system.fns.engine.$name,
478418
&self.tcx.query_system.caches.$name,
@@ -565,48 +505,19 @@ macro_rules! define_feedable {
565505

566506
let tcx = self.tcx;
567507
let erased = queries::$name::provided_to_erased(tcx, value);
568-
let value = restore::<$V>(erased);
569508
let cache = &tcx.query_system.caches.$name;
570509

510+
let dep_kind: dep_graph::DepKind = dep_graph::dep_kinds::$name;
571511
let hasher: Option<fn(&mut StableHashingContext<'_>, &_) -> _> = hash_result!([$($modifiers)*]);
572-
match try_get_cached(tcx, cache, &key) {
573-
Some(old) => {
574-
let old = restore::<$V>(old);
575-
if let Some(hasher) = hasher {
576-
let (value_hash, old_hash): (Fingerprint, Fingerprint) = tcx.with_stable_hashing_context(|mut hcx|
577-
(hasher(&mut hcx, &value), hasher(&mut hcx, &old))
578-
);
579-
if old_hash != value_hash {
580-
// We have an inconsistency. This can happen if one of the two
581-
// results is tainted by errors. In this case, delay a bug to
582-
// ensure compilation is doomed, and keep the `old` value.
583-
tcx.dcx().delayed_bug(format!(
584-
"Trying to feed an already recorded value for query {} key={key:?}:\n\
585-
old value: {old:?}\nnew value: {value:?}",
586-
stringify!($name),
587-
));
588-
}
589-
} else {
590-
// The query is `no_hash`, so we have no way to perform a sanity check.
591-
// If feeding the same value multiple times needs to be supported,
592-
// the query should not be marked `no_hash`.
593-
bug!(
594-
"Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}",
595-
stringify!($name),
596-
)
597-
}
598-
}
599-
None => {
600-
let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::dep_kinds::$name, &key);
601-
let dep_node_index = tcx.dep_graph.with_feed_task(
602-
dep_node,
603-
tcx,
604-
&value,
605-
hash_result!([$($modifiers)*]),
606-
);
607-
cache.complete(key, erased, dep_node_index);
608-
}
609-
}
512+
513+
$crate::query::inner::query_feed(
514+
tcx,
515+
dep_kind,
516+
hasher,
517+
cache,
518+
key,
519+
erased,
520+
);
610521
}
611522
})*
612523
}
@@ -694,10 +605,6 @@ mod sealed {
694605
}
695606
}
696607

697-
pub use sealed::IntoQueryParam;
698-
699-
use super::erase::EraseType;
700-
701608
#[derive(Copy, Clone, Debug, HashStable)]
702609
pub struct CyclePlaceholder(pub ErrorGuaranteed);
703610

0 commit comments

Comments
 (0)