@@ -71,22 +71,27 @@ are cheaply cloneable; insert an `Rc` if necessary).
7171
7272If, however, the query is * not* in the cache, then the compiler will
7373call 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
7879field is a function pointer to the actual provider.
7980
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.
8286
8387** Providers are defined per-crate.** The compiler maintains,
8488internally, 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* .
9095For example, when you invoke ` tcx.type_of(def_id) ` , that could be a
9196local query or an external query, depending on what crate the ` def_id `
9297is 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
119124
120125### How providers are set up
121126
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:
127129
128130``` 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,
132135}
133136```
134137
138+ Each of these provider structs is generated by the macros and contains function pointers for their respective queries.
139+
135140#### How are providers registered?
136141
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.
138143But the actual provider functions are implemented in various ` rustc_* ` crates (like ` rustc_middle ` , ` rustc_hir_analysis ` , etc).
139144
140145To register providers, each crate exposes a [ ` provide ` ] [ provide_fn ] function that looks like this:
141146
142147[ provide_fn ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/fn.provide.html
143148
144149``` 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
151159}
152160```
153161
154162- 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) .
156164
157165#### Adding a new provider
158166
@@ -164,11 +172,10 @@ Suppose you want to add a new query called `fubar`. You would:
164172 ```
1651732. Register it in the `provide` function:
166174 ```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;
172179 }
173180 ```
174181
0 commit comments