Skip to content

Commit 306686d

Browse files
committed
sembr src/query.md
1 parent 9bccc26 commit 306686d

File tree

1 file changed

+55
-49
lines changed

1 file changed

+55
-49
lines changed

src/query.md

Lines changed: 55 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,35 @@
22

33
As described in [Overview of the compiler], the Rust compiler
44
is still (as of <!-- date-check --> July 2021) transitioning from a
5-
traditional "pass-based" setup to a "demand-driven" system. The compiler query
6-
system is the key to rustc's demand-driven organization.
7-
The idea is pretty simple. Instead of entirely independent passes
5+
traditional "pass-based" setup to a "demand-driven" system.
6+
The compiler query system is the key to rustc's demand-driven organization.
7+
The idea is pretty simple.
8+
Instead of entirely independent passes
89
(parsing, type-checking, etc.), a set of function-like *queries*
9-
compute information about the input source. For example,
10+
compute information about the input source.
11+
For example,
1012
there is a query called `type_of` that, given the [`DefId`] of
1113
some item, will compute the type of that item and return it to you.
1214

1315
[`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_span/def_id/struct.DefId.html
1416
[Overview of the compiler]: overview.md#queries
1517

1618
Query execution is *memoized*. The first time you invoke a
17-
query, it will go do the computation, but the next time, the result is
18-
returned from a hashtable. Moreover, query execution fits nicely into
19+
query, it will go do the computation, but the next time, the result is returned from a hashtable.
20+
Moreover, query execution fits nicely into
1921
*incremental computation*; the idea is roughly that, when you invoke a
20-
query, the result *may* be returned to you by loading stored data
21-
from disk.[^incr-comp-detail]
22+
query, the result *may* be returned to you by loading stored data from disk.[^incr-comp-detail]
2223

23-
Eventually, we want the entire compiler
24-
control-flow to be query driven. There will effectively be one
25-
top-level query (`compile`) that will run compilation on a crate; this
26-
will in turn demand information about that crate, starting from the
27-
*end*. For example:
24+
Eventually, we want the entire compiler control-flow to be query driven.
25+
There will effectively be one top-level query (`compile`) that will run compilation on a crate; this
26+
will in turn demand information about that crate, starting from the *end*. For example:
2827

2928
- The `compile` query might demand to get a list of codegen-units
3029
(i.e. modules that need to be compiled by LLVM).
3130
- But computing the list of codegen-units would invoke some subquery
3231
that returns the list of all modules defined in the Rust source.
3332
- That query in turn would invoke something asking for the HIR.
34-
- This keeps going further and further back until we wind up doing the
35-
actual parsing.
33+
- This keeps going further and further back until we wind up doing the actual parsing.
3634

3735
Although this vision is not fully realized, large sections of the
3836
compiler (for example, generating [MIR]) currently work exactly like this.
@@ -46,9 +44,9 @@ If you intend to write a query of your own, this is a good read.
4644

4745
## Invoking queries
4846

49-
Invoking a query is simple. The [`TyCtxt`] ("type context") struct offers a method
50-
for each defined query. For example, to invoke the `type_of`
51-
query, you would just do this:
47+
Invoking a query is simple.
48+
The [`TyCtxt`] ("type context") struct offers a method for each defined query.
49+
For example, to invoke the `type_of` query, you would just do this:
5250

5351
```rust,ignore
5452
let ty = tcx.type_of(some_def_id);
@@ -58,8 +56,8 @@ let ty = tcx.type_of(some_def_id);
5856

5957
## How the compiler executes a query
6058

61-
So you may be wondering what happens when you invoke a query
62-
method. The answer is that, for each query, the compiler maintains a
59+
So you may be wondering what happens when you invoke a query method.
60+
The answer is that, for each query, the compiler maintains a
6361
cache – if your query has already been executed, then, the answer is
6462
simple: we clone the return value out of the cache and return it
6563
(therefore, you should try to ensure that the return types of queries
@@ -68,29 +66,29 @@ are cheaply cloneable; insert an `Rc` if necessary).
6866
### Providers
6967

7068
If, however, the query is *not* in the cache, then the compiler will
71-
call the corresponding **provider** function. A provider is a function
72-
implemented in a specific module and **manually registered** into either
69+
call the corresponding **provider** function.
70+
A provider is a function implemented in a specific module and **manually registered** into either
7371
the [`Providers`][providers_struct] struct (for local crate queries) or
7472
the [`ExternProviders`][extern_providers_struct] struct (for external crate queries)
75-
during compiler initialization. The macro system generates both structs,
73+
during compiler initialization.
74+
The macro system generates both structs,
7675
which act as function tables for all query implementations, where each
7776
field is a function pointer to the actual provider.
7877

7978
**Note:** Both the `Providers` and `ExternProviders` structs are generated by macros and act as function tables for all query implementations.
8079
They are **not** Rust traits, but plain structs with function pointer fields.
8180

8281
**Providers are defined per-crate.** The compiler maintains,
83-
internally, a table of providers for every crate, at least
84-
conceptually. There are two sets of providers:
82+
internally, a table of providers for every crate, at least conceptually.
83+
There are two sets of providers:
8584
- The `Providers` struct for queries about the **local crate** (that is, the one being compiled)
8685
- The `ExternProviders` struct for queries about **external crates** (that is,
8786
dependencies of the local crate)
8887

8988
Note that what determines the crate that a query is targeting is not the *kind* of query, but the *key*.
9089
For example, when you invoke `tcx.type_of(def_id)`, that could be a
9190
local query or an external query, depending on what crate the `def_id`
92-
is referring to (see the [`self::keys::Key`][Key] trait for more
93-
information on how that works).
91+
is referring to (see the [`self::keys::Key`][Key] trait for more information on how that works).
9492

9593
Providers always have the same signature:
9694

@@ -106,10 +104,11 @@ fn provider<'tcx>(
106104
Providers take two arguments: the `tcx` and the query key.
107105
They return the result of the query.
108106

109-
N.B. Most of the `rustc_*` crates only provide **local
107+
N.B.
108+
Most of the `rustc_*` crates only provide **local
110109
providers**. Almost all **extern providers** wind up going through the
111-
[`rustc_metadata` crate][rustc_metadata], which loads the information
112-
from the crate metadata. But in some cases there are crates that
110+
[`rustc_metadata` crate][rustc_metadata], which loads the information from the crate metadata.
111+
But in some cases there are crates that
113112
provide queries for *both* local and external crates, in which case
114113
they define both a `provide` and a `provide_extern` function, through
115114
[`wasm_import_module_map`][wasm_import_module_map], that `rustc_driver` can invoke.
@@ -120,7 +119,8 @@ they define both a `provide` and a `provide_extern` function, through
120119
### How providers are set up
121120

122121
When the tcx is created, it is given both the local and external providers by its creator using
123-
the `Providers` struct from `rustc_middle::util`. This struct contains both the local and external providers:
122+
the `Providers` struct from `rustc_middle::util`.
123+
This struct contains both the local and external providers:
124124

125125
```rust,ignore
126126
pub struct Providers {
@@ -134,7 +134,7 @@ Each of these provider structs is generated by the macros and contains function
134134

135135
#### How are providers registered?
136136

137-
The `util::Providers` struct is filled in during compiler initialization, by the `rustc_interface` crate from the `DEFAULT_QUERY_PROVIDERS` static.
137+
The `util::Providers` struct is filled in during compiler initialization, by the `rustc_interface` crate from the `DEFAULT_QUERY_PROVIDERS` static.
138138
The actual provider functions are defined across various `rustc_*` crates (like `rustc_middle`, `rustc_hir_analysis`, etc).
139139

140140
To register providers, each crate exposes a [`provide`][provide_fn] function that looks like this:
@@ -151,7 +151,9 @@ pub fn provide(providers: &mut query::Providers) {
151151
}
152152
```
153153

154-
Note that this function accepts `query::Providers` not `util::Providers`. It is exceedingly rare to need a `provide` function that doesn't just accept `query::Providers`. If more than the `queries` field of `util::Providers` is being updated then `util::Providers` can be accepted instead:
154+
Note that this function accepts `query::Providers` not `util::Providers`.
155+
It is exceedingly rare to need a `provide` function that doesn't just accept `query::Providers`.
156+
If more than the `queries` field of `util::Providers` is being updated then `util::Providers` can be accepted instead:
155157
```rust,ignore
156158
pub fn provide(providers: &mut rustc_middle::util::Providers) {
157159
providers.queries.type_of = type_of;
@@ -173,7 +175,8 @@ Note that `util::Providers` implements `DerefMut` to `query::Providers` so calle
173175

174176
#### Adding a new provider
175177

176-
Suppose you want to add a new query called `fubar`. This section focuses on wiring up the providers; for how to declare the query itself in the big `rustc_queries!` macro, see [Adding a new query](#adding-a-new-query) below.
178+
Suppose you want to add a new query called `fubar`.
179+
This section focuses on wiring up the providers; for how to declare the query itself in the big `rustc_queries!` macro, see [Adding a new query](#adding-a-new-query) below.
177180

178181
In practice you usually:
179182

@@ -184,7 +187,8 @@ In practice you usually:
184187
// existing assignments
185188
}
186189
```
187-
If it exists, you will extend it to set the field for your new query. If the crate does not yet have a `provide` function, add one and make sure it is included in `DEFAULT_QUERY_PROVIDERS` in the `rustc_interface` crate so that it actually gets called during initialization (see the discussion above).
190+
If it exists, you will extend it to set the field for your new query.
191+
If the crate does not yet have a `provide` function, add one and make sure it is included in `DEFAULT_QUERY_PROVIDERS` in the `rustc_interface` crate so that it actually gets called during initialization (see the discussion above).
188192
3. Implement the provider function itself:
189193
```rust,ignore
190194
fn fubar<'tcx>(tcx: TyCtxt<'tcx>, key: LocalDefId) -> Fubar<'tcx> { ... }
@@ -210,7 +214,8 @@ The process works like this:
210214
This determines whether to use the local provider from [`Providers`][providers_struct] or the external provider from [`ExternProviders`][extern_providers_struct].
211215
212216
2. For external crates, the query system will look for a provider in the [`ExternProviders`][extern_providers_struct] struct.
213-
The `rustc_metadata` crate registers these external providers through the `provide_extern` function in `rustc_metadata/src/rmeta/decoder/cstore_impl.rs`. Just like:
217+
The `rustc_metadata` crate registers these external providers through the `provide_extern` function in `rustc_metadata/src/rmeta/decoder/cstore_impl.rs`.
218+
Just like:
214219
```rust
215220
pub fn provide_extern(providers: &mut ExternProviders) {
216221
providers.foo = |tcx, def_id| {
@@ -222,7 +227,8 @@ The process works like this:
222227
}
223228
```
224229
225-
3. The metadata is stored in a binary format in `.rmeta` files that contains pre-computed information about the external crate, such as types, function signatures, trait implementations, and other information needed by the compiler. When an external query is made, the `rustc_metadata` crate:
230+
3. The metadata is stored in a binary format in `.rmeta` files that contains pre-computed information about the external crate, such as types, function signatures, trait implementations, and other information needed by the compiler.
231+
When an external query is made, the `rustc_metadata` crate:
226232
- Loads the `.rmeta` file for the external crate
227233
- Decodes the metadata using the `Decodable` trait
228234
- Returns the decoded information to the query system
@@ -234,10 +240,11 @@ Here is a simplified example, when you call `tcx.type_of(def_id)` for a type def
234240
3. The provider will load and decode the type information from the external crate's metadata
235241
4. Return the decoded type to the caller
236242
237-
This is why most `rustc_*` crates only need to provide local providers - the external providers are handled by the metadata system.
243+
This is why most `rustc_*` crates only need to provide local providers - the external providers are handled by the metadata system.
238244
The only exception is when a crate needs to provide special handling for external queries, in which case it would implement both local and external providers.
239245
240-
When we define a new query that should work across crates, it does not automatically become cross-crate just because it is listed in `rustc_queries!`. You will typically need to:
246+
When we define a new query that should work across crates, it does not automatically become cross-crate just because it is listed in `rustc_queries!`.
247+
You will typically need to:
241248
242249
- Add the query to `rustc_queries!` with appropriate modifiers (for example whether it is cached on disk).
243250
- Implement a local provider in the owning crate and register it via that crate's `provide` function.
@@ -296,17 +303,16 @@ query keyword
296303
Let's go over these elements one by one:
297304

298305
- **Query keyword:** indicates a start of a query definition.
299-
- **Name of query:** the name of the query method
300-
(`tcx.type_of(..)`). Also used as the name of a struct
301-
(`ty::queries::type_of`) that will be generated to represent
306+
- **Name of query:** the name of the query method (`tcx.type_of(..)`).
307+
Also used as the name of a struct (`ty::queries::type_of`) that will be generated to represent
302308
this query.
303309
- **Query key type:** the type of the argument to this query.
304310
This type must implement the [`ty::query::keys::Key`][Key] trait, which
305311
defines (for example) how to map it to a crate, and so forth.
306-
- **Result type of query:** the type produced by this query. This type
307-
should (a) not use `RefCell` or other interior mutability and (b) be
308-
cheaply cloneable. Interning or using `Rc` or `Arc` is recommended for
309-
non-trivial data types.[^steal]
312+
- **Result type of query:** the type produced by this query.
313+
This type should (a) not use `RefCell` or other interior mutability and (b) be
314+
cheaply cloneable.
315+
Interning or using `Rc` or `Arc` is recommended for non-trivial data types.[^steal]
310316
- **Query modifiers:** various flags and options that customize how the
311317
query is processed (mostly with respect to [incremental compilation][incrcomp]).
312318

@@ -320,9 +326,9 @@ So, to add a query:
320326
or add a new one if needed and ensure that `rustc_driver` is invoking it.
321327

322328
[^steal]: The one exception to those rules is the `ty::steal::Steal` type,
323-
which is used to cheaply modify MIR in place. See the definition
324-
of `Steal` for more details. New uses of `Steal` should **not** be
325-
added without alerting `@rust-lang/compiler`.
329+
which is used to cheaply modify MIR in place.
330+
See the definition of `Steal` for more details.
331+
New uses of `Steal` should **not** be added without alerting `@rust-lang/compiler`.
326332

327333
## External links
328334

0 commit comments

Comments
 (0)