@@ -71,22 +71,27 @@ are cheaply cloneable; insert an `Rc` if necessary).
71
71
72
72
If, however, the query is * not* in the cache, then the compiler will
73
73
call the corresponding ** provider** function. A provider is a function
74
- implemented in a specific module and ** manually registered** into the
75
- [ ` Providers ` ] [ providers_struct ] struct during compiler initialization.
76
- The macro system generates the [ ` Providers ` ] [ providers_struct ] struct,
77
- which acts as a function table for all query implementations, where each
74
+ implemented in a specific module and ** manually registered** into either
75
+ the [ ` Providers ` ] [ providers_struct ] struct (for local crate queries) or
76
+ the [ ` ExternProviders ` ] [ extern_providers_struct ] struct (for external crate queries)
77
+ during compiler initialization. The macro system generates both structs,
78
+ which act as function tables for all query implementations, where each
78
79
field is a function pointer to the actual provider.
79
80
80
- ** Note:** The ` Providers ` struct is generated by macros and acts as a function table for all query implementations.
81
- It is ** not** a Rust trait, but a plain struct with function pointer fields.
81
+ [ providers_struct ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.Providers.html
82
+ [ extern_providers_struct ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.ExternProviders.html
83
+
84
+ ** Note:** Both the ` Providers ` and ` ExternProviders ` structs are generated by macros and act as function tables for all query implementations.
85
+ They are ** not** Rust traits, but plain structs with function pointer fields.
82
86
83
87
** Providers are defined per-crate.** The compiler maintains,
84
88
internally, a table of providers for every crate, at least
85
- conceptually. Right now, there are really two sets: the providers for
86
- queries about the ** local crate** (that is, the one being compiled)
87
- and providers for queries about ** external crates** (that is,
88
- dependencies of the local crate). Note that what determines the crate
89
- that a query is targeting is not the * kind* of query, but the * key* .
89
+ conceptually. There are two sets of providers:
90
+ - The ` Providers ` struct for queries about the ** local crate** (that is, the one being compiled)
91
+ - The ` ExternProviders ` struct for queries about ** external crates** (that is,
92
+ dependencies of the local crate)
93
+
94
+ Note that what determines the crate that a query is targeting is not the * kind* of query, but the * key* .
90
95
For example, when you invoke ` tcx.type_of(def_id) ` , that could be a
91
96
local query or an external query, depending on what crate the ` def_id `
92
97
is referring to (see the [ ` self::keys::Key ` ] [ Key ] trait for more
@@ -119,40 +124,43 @@ they define both a `provide` and a `provide_extern` function, through
119
124
120
125
### How providers are set up
121
126
122
- When the tcx is created, it is given the providers by its creator using
123
- the [ ` Providers ` ] [ providers_struct ] struct. This struct is generated by
124
- the macros here, but it is basically a big list of function pointers:
125
-
126
- [ providers_struct ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/query/struct.Providers.html
127
+ When the tcx is created, it is given both the local and external providers by its creator using
128
+ the ` Providers ` struct from ` rustc_middle::util ` . This struct contains both the local and external providers:
127
129
128
130
``` rust,ignore
129
- struct Providers {
130
- type_of: for<'tcx> fn(TyCtxt<'tcx>, DefId) -> Ty<'tcx>,
131
- // ... one field for each query
131
+ pub struct Providers {
132
+ pub queries: crate::query::Providers, // Local crate providers
133
+ pub extern_queries: crate::query::ExternProviders, // External crate providers
134
+ pub hooks: crate::hooks::Providers,
132
135
}
133
136
```
134
137
138
+ Each of these provider structs is generated by the macros and contains function pointers for their respective queries.
139
+
135
140
#### How are providers registered?
136
141
137
- The ` Providers ` struct is filled in during compiler initialization, mainly by the ` rustc_driver ` crate.
142
+ The provider structs are filled in during compiler initialization, mainly by the ` rustc_driver ` crate.
138
143
But the actual provider functions are implemented in various ` rustc_* ` crates (like ` rustc_middle ` , ` rustc_hir_analysis ` , etc).
139
144
140
145
To register providers, each crate exposes a [ ` provide ` ] [ provide_fn ] function that looks like this:
141
146
142
147
[ provide_fn ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/fn.provide.html
143
148
144
149
``` rust,ignore
145
- pub fn provide(providers: &mut Providers) {
146
- *providers = Providers {
147
- type_of,
148
- // ... add more providers here
149
- ..*providers
150
- };
150
+ pub fn provide(providers: &mut rustc_middle::util::Providers) {
151
+ providers.queries.type_of = type_of;
152
+ // ... add more local providers here
153
+
154
+ providers.extern_queries.type_of = extern_type_of;
155
+ // ... add more external providers here
156
+
157
+ providers.hooks.some_hook = some_hook;
158
+ // ... add more hooks here
151
159
}
152
160
```
153
161
154
162
- This function takes a mutable reference to the ` Providers ` struct and sets the fields to point to the correct provider functions.
155
- - You can also assign fields individually, e.g. ` providers.type_of = type_of; ` .
163
+ - You can assign fields individually for each provider type (local, external, and hooks) .
156
164
157
165
#### Adding a new provider
158
166
@@ -164,11 +172,10 @@ Suppose you want to add a new query called `fubar`. You would:
164
172
```
165
173
2. Register it in the `provide` function:
166
174
```rust,ignore
167
- pub fn provide(providers: &mut Providers) {
168
- *providers = Providers {
169
- fubar,
170
- ..*providers
171
- };
175
+ pub fn provide(providers: &mut rustc_middle::util::Providers) {
176
+ providers.queries.fubar = fubar;
177
+ // If you need an external provider:
178
+ providers.extern_queries.fubar = extern_fubar;
172
179
}
173
180
```
174
181
0 commit comments