Refinement of Providers into Providers and ExternProviders
Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
This commit is contained in:
parent
59756939d5
commit
07e05bbc46
71
src/query.md
71
src/query.md
|
|
@ -71,22 +71,27 @@ are cheaply cloneable; insert an `Rc` if necessary).
|
||||||
|
|
||||||
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
|
||||||
call the corresponding **provider** function. A provider is a function
|
call the corresponding **provider** function. A provider is a function
|
||||||
implemented in a specific module and **manually registered** into the
|
implemented in a specific module and **manually registered** into either
|
||||||
[`Providers`][providers_struct] struct during compiler initialization.
|
the [`Providers`][providers_struct] struct (for local crate queries) or
|
||||||
The macro system generates the [`Providers`][providers_struct] struct,
|
the [`ExternProviders`][extern_providers_struct] struct (for external crate queries)
|
||||||
which acts as a function table for all query implementations, where each
|
during compiler initialization. The macro system generates both structs,
|
||||||
|
which act as function tables for all query implementations, where each
|
||||||
field is a function pointer to the actual provider.
|
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.
|
[providers_struct]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.Providers.html
|
||||||
It is **not** a Rust trait, but a plain struct with function pointer fields.
|
[extern_providers_struct]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.ExternProviders.html
|
||||||
|
|
||||||
|
**Note:** Both the `Providers` and `ExternProviders` structs are generated by macros and act as function tables for all query implementations.
|
||||||
|
They are **not** Rust traits, but plain structs 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
|
||||||
conceptually. Right now, there are really two sets: the providers for
|
conceptually. There are two sets of providers:
|
||||||
queries about the **local crate** (that is, the one being compiled)
|
- The `Providers` struct for queries about the **local crate** (that is, the one being compiled)
|
||||||
and providers for queries about **external crates** (that is,
|
- The `ExternProviders` struct for queries about **external crates** (that is,
|
||||||
dependencies of the local crate). Note that what determines the crate
|
dependencies of the local crate)
|
||||||
that a query is targeting is not the *kind* of query, but the *key*.
|
|
||||||
|
Note that what determines the crate that a query is targeting is not the *kind* of query, but the *key*.
|
||||||
For example, when you invoke `tcx.type_of(def_id)`, that could be a
|
For example, when you invoke `tcx.type_of(def_id)`, that could be a
|
||||||
local query or an external query, depending on what crate the `def_id`
|
local query or an external query, depending on what crate the `def_id`
|
||||||
is referring to (see the [`self::keys::Key`][Key] trait for more
|
is referring to (see the [`self::keys::Key`][Key] trait for more
|
||||||
|
|
@ -119,22 +124,22 @@ they define both a `provide` and a `provide_extern` function, through
|
||||||
|
|
||||||
### How providers are set up
|
### How providers are set up
|
||||||
|
|
||||||
When the tcx is created, it is given the providers by its creator using
|
When the tcx is created, it is given both the local and external providers by its creator using
|
||||||
the [`Providers`][providers_struct] struct. This struct is generated by
|
the `Providers` struct from `rustc_middle::util`. This struct contains both the local and external providers:
|
||||||
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
|
```rust,ignore
|
||||||
struct Providers {
|
pub struct Providers {
|
||||||
type_of: for<'tcx> fn(TyCtxt<'tcx>, DefId) -> Ty<'tcx>,
|
pub queries: crate::query::Providers, // Local crate providers
|
||||||
// ... one field for each query
|
pub extern_queries: crate::query::ExternProviders, // External crate providers
|
||||||
|
pub hooks: crate::hooks::Providers,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Each of these provider structs is generated by the macros and contains function pointers for their respective queries.
|
||||||
|
|
||||||
#### How are providers registered?
|
#### How are providers registered?
|
||||||
|
|
||||||
The `Providers` struct is filled in during compiler initialization, mainly by the `rustc_driver` crate.
|
The provider structs are 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).
|
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:
|
To register providers, each crate exposes a [`provide`][provide_fn] function that looks like this:
|
||||||
|
|
@ -142,17 +147,20 @@ To register providers, each crate exposes a [`provide`][provide_fn] function tha
|
||||||
[provide_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/fn.provide.html
|
[provide_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/fn.provide.html
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
pub fn provide(providers: &mut Providers) {
|
pub fn provide(providers: &mut rustc_middle::util::Providers) {
|
||||||
*providers = Providers {
|
providers.queries.type_of = type_of;
|
||||||
type_of,
|
// ... add more local providers here
|
||||||
// ... add more providers here
|
|
||||||
..*providers
|
providers.extern_queries.type_of = extern_type_of;
|
||||||
};
|
// ... add more external providers here
|
||||||
|
|
||||||
|
providers.hooks.some_hook = some_hook;
|
||||||
|
// ... add more hooks here
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- This function takes a mutable reference to the `Providers` struct and sets the fields to point to the correct provider functions.
|
- 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;`.
|
- You can assign fields individually for each provider type (local, external, and hooks).
|
||||||
|
|
||||||
#### Adding a new provider
|
#### Adding a new provider
|
||||||
|
|
||||||
|
|
@ -164,11 +172,10 @@ Suppose you want to add a new query called `fubar`. You would:
|
||||||
```
|
```
|
||||||
2. Register it in the `provide` function:
|
2. Register it in the `provide` function:
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
pub fn provide(providers: &mut Providers) {
|
pub fn provide(providers: &mut rustc_middle::util::Providers) {
|
||||||
*providers = Providers {
|
providers.queries.fubar = fubar;
|
||||||
fubar,
|
// If you need an external provider:
|
||||||
..*providers
|
providers.extern_queries.fubar = extern_fubar;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue