Skip to content

Commit c97b539

Browse files
committed
Auto merge of #104940 - cjgillot:query-feed-simple, r=oli-obk
Allow to feed a value in another query's cache Restricted version of #96840 A query can create new definitions. If those definitions are created after HIR lowering, they do not appear in the initial HIR map, and information for them cannot be provided in the normal pull-based way. In order to make those definitions useful, we allow to feed values as query results for the newly created definition. The API is as follows: ```rust let feed = tcx.create_def(<parent def id>, <DefPathData>); // `feed` is a TyCtxtFeed<'tcx>. // Access the created definition. let def_id: LocalDefId = feed.def_id; // Assign `my_query(def_id) := my_value`. feed.my_query(my_value). ``` This PR keeps the consistency checks introduced by #96840, even if they are not reachable. This allows to extend the behaviour later without forgetting them. cc `@oli-obk` `@spastorino`
2 parents 90711a8 + 6477fd8 commit c97b539

File tree

11 files changed

+298
-53
lines changed

11 files changed

+298
-53
lines changed

compiler/rustc_ast_lowering/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
497497
self.tcx.hir().def_key(self.local_def_id(node_id)),
498498
);
499499

500-
let def_id = self.tcx.create_def(parent, data);
500+
let def_id = self.tcx.create_def(parent, data).def_id();
501501

502502
debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
503503
self.resolver.node_id_to_def_id.insert(node_id, def_id);

compiler/rustc_hir/src/definitions.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -368,10 +368,6 @@ impl Definitions {
368368
LocalDefId { local_def_index: self.table.allocate(key, def_path_hash) }
369369
}
370370

371-
pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ {
372-
self.table.def_path_hashes.indices().map(|local_def_index| LocalDefId { local_def_index })
373-
}
374-
375371
#[inline(always)]
376372
pub fn local_def_path_hash_to_def_id(
377373
&self,
@@ -389,6 +385,10 @@ impl Definitions {
389385
pub fn def_path_hash_to_def_index_map(&self) -> &DefPathHashMap {
390386
&self.table.def_path_hash_to_index
391387
}
388+
389+
pub fn num_definitions(&self) -> usize {
390+
self.table.def_path_hashes.len()
391+
}
392392
}
393393

394394
#[derive(Copy, Clone, PartialEq, Debug)]

compiler/rustc_macros/src/query.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ struct QueryModifiers {
114114

115115
/// Always remap the ParamEnv's constness before hashing.
116116
remap_env_constness: Option<Ident>,
117+
118+
/// Generate a `feed` method to set the query's value from another query.
119+
feedable: Option<Ident>,
117120
}
118121

119122
fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
@@ -128,6 +131,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
128131
let mut depth_limit = None;
129132
let mut separate_provide_extern = None;
130133
let mut remap_env_constness = None;
134+
let mut feedable = None;
131135

132136
while !input.is_empty() {
133137
let modifier: Ident = input.parse()?;
@@ -187,6 +191,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
187191
try_insert!(separate_provide_extern = modifier);
188192
} else if modifier == "remap_env_constness" {
189193
try_insert!(remap_env_constness = modifier);
194+
} else if modifier == "feedable" {
195+
try_insert!(feedable = modifier);
190196
} else {
191197
return Err(Error::new(modifier.span(), "unknown query modifier"));
192198
}
@@ -206,6 +212,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
206212
depth_limit,
207213
separate_provide_extern,
208214
remap_env_constness,
215+
feedable,
209216
})
210217
}
211218

@@ -296,6 +303,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
296303
let mut query_stream = quote! {};
297304
let mut query_description_stream = quote! {};
298305
let mut query_cached_stream = quote! {};
306+
let mut feedable_queries = quote! {};
299307

300308
for query in queries.0 {
301309
let Query { name, arg, modifiers, .. } = &query;
@@ -350,6 +358,22 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
350358
[#attribute_stream] fn #name(#arg) #result,
351359
});
352360

361+
if modifiers.feedable.is_some() {
362+
assert!(modifiers.anon.is_none(), "Query {name} cannot be both `feedable` and `anon`.");
363+
assert!(
364+
modifiers.eval_always.is_none(),
365+
"Query {name} cannot be both `feedable` and `eval_always`."
366+
);
367+
assert!(
368+
modifiers.no_hash.is_none(),
369+
"Query {name} cannot be both `feedable` and `no_hash`."
370+
);
371+
feedable_queries.extend(quote! {
372+
#(#doc_comments)*
373+
[#attribute_stream] fn #name(#arg) #result,
374+
});
375+
}
376+
353377
add_query_desc_cached_impl(&query, &mut query_description_stream, &mut query_cached_stream);
354378
}
355379

@@ -363,7 +387,11 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
363387
}
364388
}
365389
}
366-
390+
macro_rules! rustc_feedable_queries {
391+
( $macro:ident! ) => {
392+
$macro!(#feedable_queries);
393+
}
394+
}
367395
pub mod descs {
368396
use super::*;
369397
#query_description_stream

compiler/rustc_middle/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@
3030
#![feature(core_intrinsics)]
3131
#![feature(discriminant_kind)]
3232
#![feature(exhaustive_patterns)]
33+
#![feature(generators)]
3334
#![feature(get_mut_unchecked)]
3435
#![feature(if_let_guard)]
36+
#![feature(iter_from_generator)]
3537
#![feature(negative_impls)]
3638
#![feature(never_type)]
3739
#![feature(extern_types)]

compiler/rustc_middle/src/ty/context.rs

+44-10
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ use rustc_hir::{
5353
use rustc_index::vec::{Idx, IndexVec};
5454
use rustc_macros::HashStable;
5555
use rustc_middle::mir::FakeReadCause;
56+
use rustc_query_system::dep_graph::DepNodeIndex;
5657
use rustc_query_system::ich::StableHashingContext;
5758
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
5859
use rustc_session::config::{CrateType, OutputFilenames};
@@ -1031,6 +1032,21 @@ pub struct FreeRegionInfo {
10311032
pub is_impl_item: bool,
10321033
}
10331034

1035+
/// This struct should only be created by `create_def`.
1036+
#[derive(Copy, Clone)]
1037+
pub struct TyCtxtFeed<'tcx> {
1038+
pub tcx: TyCtxt<'tcx>,
1039+
// Do not allow direct access, as downstream code must not mutate this field.
1040+
def_id: LocalDefId,
1041+
}
1042+
1043+
impl<'tcx> TyCtxtFeed<'tcx> {
1044+
#[inline(always)]
1045+
pub fn def_id(&self) -> LocalDefId {
1046+
self.def_id
1047+
}
1048+
}
1049+
10341050
/// The central data structure of the compiler. It stores references
10351051
/// to the various **arenas** and also houses the results of the
10361052
/// various **compiler queries** that have been performed. See the
@@ -1493,12 +1509,15 @@ impl<'tcx> TyCtxt<'tcx> {
14931509
}
14941510

14951511
/// Create a new definition within the incr. comp. engine.
1496-
pub fn create_def(self, parent: LocalDefId, data: hir::definitions::DefPathData) -> LocalDefId {
1512+
pub fn create_def(
1513+
self,
1514+
parent: LocalDefId,
1515+
data: hir::definitions::DefPathData,
1516+
) -> TyCtxtFeed<'tcx> {
14971517
// This function modifies `self.definitions` using a side-effect.
14981518
// We need to ensure that these side effects are re-run by the incr. comp. engine.
14991519
// Depending on the forever-red node will tell the graph that the calling query
15001520
// needs to be re-evaluated.
1501-
use rustc_query_system::dep_graph::DepNodeIndex;
15021521
self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE);
15031522

15041523
// The following call has the side effect of modifying the tables inside `definitions`.
@@ -1515,23 +1534,38 @@ impl<'tcx> TyCtxt<'tcx> {
15151534
// This is fine because:
15161535
// - those queries are `eval_always` so we won't miss their result changing;
15171536
// - this write will have happened before these queries are called.
1518-
self.definitions.write().create_def(parent, data)
1537+
let def_id = self.definitions.write().create_def(parent, data);
1538+
1539+
TyCtxtFeed { tcx: self, def_id }
15191540
}
15201541

15211542
pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + 'tcx {
1522-
// Create a dependency to the crate to be sure we re-execute this when the amount of
1543+
// Create a dependency to the red node to be sure we re-execute this when the amount of
15231544
// definitions change.
1524-
self.ensure().hir_crate(());
1525-
// Leak a read lock once we start iterating on definitions, to prevent adding new ones
1526-
// while iterating. If some query needs to add definitions, it should be `ensure`d above.
1527-
let definitions = self.definitions.leak();
1528-
definitions.iter_local_def_id()
1545+
self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE);
1546+
1547+
let definitions = &self.definitions;
1548+
std::iter::from_generator(|| {
1549+
let mut i = 0;
1550+
1551+
// Recompute the number of definitions each time, because our caller may be creating
1552+
// new ones.
1553+
while i < { definitions.read().num_definitions() } {
1554+
let local_def_index = rustc_span::def_id::DefIndex::from_usize(i);
1555+
yield LocalDefId { local_def_index };
1556+
i += 1;
1557+
}
1558+
1559+
// Leak a read lock once we finish iterating on definitions, to prevent adding new ones.
1560+
definitions.leak();
1561+
})
15291562
}
15301563

15311564
pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable {
15321565
// Create a dependency to the crate to be sure we re-execute this when the amount of
15331566
// definitions change.
1534-
self.ensure().hir_crate(());
1567+
self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE);
1568+
15351569
// Leak a read lock once we start iterating on definitions, to prevent adding new ones
15361570
// while iterating. If some query needs to add definitions, it should be `ensure`d above.
15371571
let definitions = self.definitions.leak();

compiler/rustc_middle/src/ty/query.rs

+42
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use crate::traits::query::{
2828
};
2929
use crate::traits::specialization_graph;
3030
use crate::traits::{self, ImplSource};
31+
use crate::ty::context::TyCtxtFeed;
3132
use crate::ty::fast_reject::SimplifiedType;
3233
use crate::ty::layout::TyAndLayout;
3334
use crate::ty::subst::{GenericArg, SubstsRef};
@@ -327,6 +328,46 @@ macro_rules! define_callbacks {
327328
};
328329
}
329330

331+
macro_rules! define_feedable {
332+
($($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
333+
impl<'tcx> TyCtxtFeed<'tcx> {
334+
$($(#[$attr])*
335+
#[inline(always)]
336+
pub fn $name(self, value: $V) -> query_stored::$name<'tcx> {
337+
let key = self.def_id().into_query_param();
338+
opt_remap_env_constness!([$($modifiers)*][key]);
339+
340+
let tcx = self.tcx;
341+
let cache = &tcx.query_caches.$name;
342+
343+
let cached = try_get_cached(tcx, cache, &key, copy);
344+
345+
match cached {
346+
Ok(old) => {
347+
assert_eq!(
348+
value, old,
349+
"Trying to feed an already recorded value for query {} key={key:?}",
350+
stringify!($name),
351+
);
352+
return old;
353+
}
354+
Err(()) => (),
355+
}
356+
357+
let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::DepKind::$name, &key);
358+
let dep_node_index = tcx.dep_graph.with_feed_task(
359+
dep_node,
360+
tcx,
361+
key,
362+
&value,
363+
dep_graph::hash_result,
364+
);
365+
cache.complete(key, value, dep_node_index)
366+
})*
367+
}
368+
}
369+
}
370+
330371
// Each of these queries corresponds to a function pointer field in the
331372
// `Providers` struct for requesting a value of that type, and a method
332373
// on `tcx: TyCtxt` (and `tcx.at(span)`) for doing that request in a way
@@ -340,6 +381,7 @@ macro_rules! define_callbacks {
340381
// as they will raise an fatal error on query cycles instead.
341382

342383
rustc_query_append! { define_callbacks! }
384+
rustc_feedable_queries! { define_feedable! }
343385

344386
mod sealed {
345387
use super::{DefId, LocalDefId, OwnerId};

compiler/rustc_query_impl/src/plumbing.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,18 @@ macro_rules! depth_limit {
252252
};
253253
}
254254

255+
macro_rules! feedable {
256+
([]) => {{
257+
false
258+
}};
259+
([(feedable) $($rest:tt)*]) => {{
260+
true
261+
}};
262+
([$other:tt $($modifiers:tt)*]) => {
263+
feedable!([$($modifiers)*])
264+
};
265+
}
266+
255267
macro_rules! hash_result {
256268
([]) => {{
257269
Some(dep_graph::hash_result)
@@ -309,7 +321,7 @@ pub(crate) fn create_query_frame<
309321
ty::print::with_forced_impl_filename_line!(do_describe(tcx.tcx, key))
310322
);
311323
let description =
312-
if tcx.sess.verbose() { format!("{} [{}]", description, name) } else { description };
324+
if tcx.sess.verbose() { format!("{} [{:?}]", description, name) } else { description };
313325
let span = if kind == dep_graph::DepKind::def_span {
314326
// The `def_span` query is used to calculate `default_span`,
315327
// so exit to avoid infinite recursion.
@@ -491,6 +503,7 @@ macro_rules! define_queries {
491503
anon: is_anon!([$($modifiers)*]),
492504
eval_always: is_eval_always!([$($modifiers)*]),
493505
depth_limit: depth_limit!([$($modifiers)*]),
506+
feedable: feedable!([$($modifiers)*]),
494507
dep_kind: dep_graph::DepKind::$name,
495508
hash_result: hash_result!([$($modifiers)*]),
496509
handle_cycle_error: handle_cycle_error!([$($modifiers)*]),

0 commit comments

Comments
 (0)