# Injecting query results * [WIP PR](https://github.com/rust-lang/rust/pull/96840) ## High level desired feature We would like to be able to fill in the result-cache of a query `X` while computing another query `Y`. This is important if `X` depends on `Y`, but to compute `Y` we need a (part) of `X`. To break such cycles, we could not call `Y` at all from `X`, but compute `Y`'s value within `X`. From the outside this effectively makes computing `X` magically "compute" `Y`, too. ## What the PR does The PR allows a query `Y` to feed a value `x` as the output of query `X`. The dependencies of `X` are set as the recorded dependencies of `Y` up to the moment the value is fed. The PR introduces several checks around the feeding: 1. If there is already a value in cache, we check for equality; 2. If the `DepNode` for `X` is already green, we check that `x`'s fingerprint matches the `DepNode`'s. 3. If a "regular" query call to `X` completes after we fed `x` in cache, we check that the fingerprints match (this may happen if computing `X` calls `Y` which sets `X := x`). ## Issues with the PRs feature We need to limit is so that you cannot "feed" a value from one query to another *unless* the first query created the key used by the second query. Otherwise, you run the very real risk of non-deterministic results if the query order changes. The danger is something like this: * Query A(X) sets the result of B(X). * Query C(X) reads B(X). * Query D(X) first executes A(X) and then C(X). Now if you start by invoking `C`, you get one value (whatever `B(X)` computes). But if you start by invoking `D`, you get a different value (whatever `A(X)` stored). The PR works by setting the "inputs" for `B(X)` to be the inputs that `A(X)` has observed thus far, but that's not enough to prevent the above problem. While this works for the `typeck` <-> `typeof(anon_const)` cycle and is sound (says @oli-obk), it would be a footgun to leave it like that as other queries will definitely cause problems. Fingerprint check #1 will detect the `C` then `D` case, and ICE in case of inconsistency. In the `D` then `C` case, `B` won't be computed. ## More salsa-like scheme One way for making this robust is to have [TyCtxt::create_def](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.create_def) return a `NewDefId` wrapper type that can only be created by `create_def`. Then `tcx.feed().query_name` would only accept arguments of type `NewDefId` where they currently require `DefId`. You can always `NewDefId::into_inner` to use it normally, but for feeding you'll need the `NewDefId`. Then we just need to make sure no one returns `NewDefId` from a query, but that seems doable (just implement no traits at all for it). For this PR that would mean to stop generating `DefId`s for `AnonConst` in AST->HIR lowering and instead leave that to typeck of the owner of the anon const. Delaying the creation of the `DefId` after HIR creates an inconsistency in HIR-based `HirId <-> LocalDefId` bidirectional map. The `LocalDefId -> HirId` mapping can be amended by feeding the query `local_def_id_to_hir_id(NewDefId) := anon_const.hir_id`. The `HirId -> LocalDefId` mapping cannot be modified because another query might have relied on `tcx.hir().opt_local_def_id(anon_const.hir_id)` being `None`. # Question/Topic Queue ## What is cost of not doing this? pnkfelix: From reading the description, I am assuming that if we do not add this feature, then the main cost is that instead of structuring things with just two queries X and Y, one would have to instead break the query X up into two pieces, X1 and X2, such that the stuff from X that depends on Y now lives in X2, and the stuff in X that was used to compute Y now lives in X1, so that you end up with a dependence graph like the following? ``` X2 -> X1 X2 -> Y Y -> X1 ``` cjgillot: that's one way to do it. The other way is what we have right now: `WithOptConstParam`, ie. piggy-back the required information to the dependents of `X` so they do not depend on `Y`. ## Queries that are only provided by another query wesleywiser: The situation described above where query A sometimes provides the result of query B seems to imply that query B has its own implementation. Would it be practical for query B to not have an implementation and soley rely on query A to provide the appropriate results? That would remove the possibilty of queries being called in a different order and seeing different results causing non-determinism. I think it would also prevent the implementations of query A and query B from diverging and causing different results depending on if query A provided query B's result or if query B itself was executed to compute the result.