Merge pull request #2465 from xizheyin/rustc-query
Adjust some doc for Query System
This commit is contained in:
commit
91ede12d31
125
src/query.md
125
src/query.md
|
|
@ -67,9 +67,15 @@ are cheaply cloneable; insert an `Rc` if necessary).
|
||||||
### Providers
|
### Providers
|
||||||
|
|
||||||
If, however, the query is *not* in the cache, then the compiler will
|
If, however, the query is *not* in the cache, then the compiler will
|
||||||
try to find a suitable **provider**. A provider is a function that has
|
call the corresponding **provider** function. A provider is a function
|
||||||
been defined and linked into the compiler somewhere that contains the
|
implemented in a specific module and **manually registered** into the
|
||||||
code to compute the result of the query.
|
[`Providers`][providers_struct] struct during compiler initialization.
|
||||||
|
The macro system generates the [`Providers`][providers_struct] struct,
|
||||||
|
which acts as a function table for all query implementations, where each
|
||||||
|
field is a function pointer to the actual provider.
|
||||||
|
|
||||||
|
**Note:** The `Providers` struct is generated by macros and acts as a function table for all query implementations.
|
||||||
|
It is **not** a Rust trait, but a plain struct with function pointer fields.
|
||||||
|
|
||||||
**Providers are defined per-crate.** The compiler maintains,
|
**Providers are defined per-crate.** The compiler maintains,
|
||||||
internally, a table of providers for every crate, at least
|
internally, a table of providers for every crate, at least
|
||||||
|
|
@ -97,62 +103,6 @@ fn provider<'tcx>(
|
||||||
Providers take two arguments: the `tcx` and the query key.
|
Providers take two arguments: the `tcx` and the query key.
|
||||||
They return the result of the query.
|
They return the result of the query.
|
||||||
|
|
||||||
### How providers are setup
|
|
||||||
|
|
||||||
When the tcx is created, it is given the providers by its creator using
|
|
||||||
the [`Providers`][providers_struct] struct. This struct is generated by
|
|
||||||
the macros here, but it is basically a big list of function pointers:
|
|
||||||
|
|
||||||
[providers_struct]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.Providers.html
|
|
||||||
|
|
||||||
```rust,ignore
|
|
||||||
struct Providers {
|
|
||||||
type_of: for<'tcx> fn(TyCtxt<'tcx>, DefId) -> Ty<'tcx>,
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
At present, we have one copy of the struct for local crates, and one
|
|
||||||
for external crates, though the plan is that we may eventually have
|
|
||||||
one per crate.
|
|
||||||
|
|
||||||
These `Providers` structs are ultimately created and populated by
|
|
||||||
`rustc_driver`, but it does this by distributing the work
|
|
||||||
throughout the other `rustc_*` crates. This is done by invoking
|
|
||||||
various [`provide`][provide_fn] functions. These functions tend to look
|
|
||||||
something like this:
|
|
||||||
|
|
||||||
[provide_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/fn.provide.html
|
|
||||||
|
|
||||||
```rust,ignore
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
|
||||||
*providers = Providers {
|
|
||||||
type_of,
|
|
||||||
..*providers
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
That is, they take an `&mut Providers` and mutate it in place. Usually
|
|
||||||
we use the formulation above just because it looks nice, but you could
|
|
||||||
as well do `providers.type_of = type_of`, which would be equivalent.
|
|
||||||
(Here, `type_of` would be a top-level function, defined as we saw
|
|
||||||
before.) So, if we want to add a provider for some other query,
|
|
||||||
let's call it `fubar`, into the crate above, we might modify the `provide()`
|
|
||||||
function like so:
|
|
||||||
|
|
||||||
```rust,ignore
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
|
||||||
*providers = Providers {
|
|
||||||
type_of,
|
|
||||||
fubar,
|
|
||||||
..*providers
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fubar<'tcx>(tcx: TyCtxt<'tcx>, key: DefId) -> Fubar<'tcx> { ... }
|
|
||||||
```
|
|
||||||
|
|
||||||
N.B. Most of the `rustc_*` crates only provide **local
|
N.B. Most of the `rustc_*` crates only provide **local
|
||||||
providers**. Almost all **extern providers** wind up going through the
|
providers**. Almost all **extern providers** wind up going through the
|
||||||
[`rustc_metadata` crate][rustc_metadata], which loads the information
|
[`rustc_metadata` crate][rustc_metadata], which loads the information
|
||||||
|
|
@ -164,6 +114,63 @@ they define both a `provide` and a `provide_extern` function, through
|
||||||
[rustc_metadata]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/index.html
|
[rustc_metadata]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/index.html
|
||||||
[wasm_import_module_map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/back/symbol_export/fn.wasm_import_module_map.html
|
[wasm_import_module_map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/back/symbol_export/fn.wasm_import_module_map.html
|
||||||
|
|
||||||
|
### How providers are set up
|
||||||
|
|
||||||
|
When the tcx is created, it is given the providers by its creator using
|
||||||
|
the [`Providers`][providers_struct] struct. This struct is generated by
|
||||||
|
the macros here, but it is basically a big list of function pointers:
|
||||||
|
|
||||||
|
[providers_struct]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.Providers.html
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
struct Providers {
|
||||||
|
type_of: for<'tcx> fn(TyCtxt<'tcx>, DefId) -> Ty<'tcx>,
|
||||||
|
// ... one field for each query
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### How are providers registered?
|
||||||
|
|
||||||
|
The `Providers` struct is filled in during compiler initialization, mainly by the `rustc_driver` crate.
|
||||||
|
But the actual provider functions are implemented in various `rustc_*` crates (like `rustc_middle`, `rustc_hir_analysis`, etc).
|
||||||
|
|
||||||
|
To register providers, each crate exposes a [`provide`][provide_fn] function that looks like this:
|
||||||
|
|
||||||
|
[provide_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/fn.provide.html
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
pub fn provide(providers: &mut Providers) {
|
||||||
|
*providers = Providers {
|
||||||
|
type_of,
|
||||||
|
// ... add more providers here
|
||||||
|
..*providers
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- This function takes a mutable reference to the `Providers` struct and sets the fields to point to the correct provider functions.
|
||||||
|
- You can also assign fields individually, e.g. `providers.type_of = type_of;`.
|
||||||
|
|
||||||
|
#### Adding a new provider
|
||||||
|
|
||||||
|
Suppose you want to add a new query called `fubar`. You would:
|
||||||
|
|
||||||
|
1. Implement the provider function:
|
||||||
|
```rust,ignore
|
||||||
|
fn fubar<'tcx>(tcx: TyCtxt<'tcx>, key: DefId) -> Fubar<'tcx> { ... }
|
||||||
|
```
|
||||||
|
2. Register it in the `provide` function:
|
||||||
|
```rust,ignore
|
||||||
|
pub fn provide(providers: &mut Providers) {
|
||||||
|
*providers = Providers {
|
||||||
|
fubar,
|
||||||
|
..*providers
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Adding a new query
|
## Adding a new query
|
||||||
|
|
||||||
How do you add a new query?
|
How do you add a new query?
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue