]> git.proxmox.com Git - rustc.git/blame - src/doc/rustc-guide/src/traits/lowering-rules.md
New upstream version 1.42.0+dfsg1
[rustc.git] / src / doc / rustc-guide / src / traits / lowering-rules.md
CommitLineData
a1dfa0c6
XL
1# Lowering rules
2
3This section gives the complete lowering rules for Rust traits into
4[program clauses][pc]. It is a kind of reference. These rules
5reference the [domain goals][dg] defined in an earlier section.
6
7[pc]: ./goals-and-clauses.html
8[dg]: ./goals-and-clauses.html#domain-goals
9
10## Notation
11
12The nonterminal `Pi` is used to mean some generic *parameter*, either a
13named lifetime like `'a` or a type parameter like `A`.
14
15The nonterminal `Ai` is used to mean some generic *argument*, which
16might be a lifetime like `'a` or a type like `Vec<A>`.
17
18When defining the lowering rules, we will give goals and clauses in
19the [notation given in this section](./goals-and-clauses.html).
20We sometimes insert "macros" like `LowerWhereClause!` into these
21definitions; these macros reference other sections within this chapter.
22
23## Rule names and cross-references
24
25Each of these lowering rules is given a name, documented with a
26comment like so:
27
28 // Rule Foo-Bar-Baz
29
30The reference implementation of these rules is to be found in
48663c56
XL
31[`chalk/chalk-solve/src/clauses.rs`][chalk_rules]. They are also ported in
32rustc in the [`librustc_traits`][librustc_traits] crate.
a1dfa0c6 33
48663c56 34[chalk_rules]: https://github.com/rust-lang/chalk/blob/master/chalk-solve/src/clauses.rs
a1dfa0c6
XL
35[librustc_traits]: https://github.com/rust-lang/rust/tree/master/src/librustc_traits
36
37## Lowering where clauses
38
39When used in a goal position, where clauses can be mapped directly to
40the `Holds` variant of [domain goals][dg], as follows:
41
42- `A0: Foo<A1..An>` maps to `Implemented(A0: Foo<A1..An>)`
43- `T: 'r` maps to `Outlives(T, 'r)`
44- `'a: 'b` maps to `Outlives('a, 'b)`
45- `A0: Foo<A1..An, Item = T>` is a bit special and expands to two distinct
46 goals, namely `Implemented(A0: Foo<A1..An>)` and
47 `ProjectionEq(<A0 as Foo<A1..An>>::Item = T)`
48
49In the rules below, we will use `WC` to indicate where clauses that
50appear in Rust syntax; we will then use the same `WC` to indicate
51where those where clauses appear as goals in the program clauses that
52we are producing. In that case, the mapping above is used to convert
53from the Rust syntax into goals.
54
55### Transforming the lowered where clauses
56
57In addition, in the rules below, we sometimes do some transformations
58on the lowered where clauses, as defined here:
59
60- `FromEnv(WC)` – this indicates that:
61 - `Implemented(TraitRef)` becomes `FromEnv(TraitRef)`
62 - other where-clauses are left intact
63- `WellFormed(WC)` – this indicates that:
64 - `Implemented(TraitRef)` becomes `WellFormed(TraitRef)`
65 - other where-clauses are left intact
66
67*TODO*: I suspect that we want to alter the outlives relations too,
68but Chalk isn't modeling those right now.
69
70## Lowering traits
71
72Given a trait definition
73
74```rust,ignore
75trait Trait<P1..Pn> // P0 == Self
76where WC
77{
78 // trait items
79}
80```
81
82we will produce a number of declarations. This section is focused on
83the program clauses for the trait header (i.e., the stuff outside the
84`{}`); the [section on trait items](#trait-items) covers the stuff
85inside the `{}`.
86
87### Trait header
88
89From the trait itself we mostly make "meta" rules that setup the
90relationships between different kinds of domain goals. The first such
91rule from the trait header creates the mapping between the `FromEnv`
92and `Implemented` predicates:
93
94```text
95// Rule Implemented-From-Env
96forall<Self, P1..Pn> {
97 Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)
98}
99```
100
101<a name="implied-bounds"></a>
102
103#### Implied bounds
104
105The next few clauses have to do with implied bounds (see also
106[RFC 2089] and the [implied bounds][implied_bounds] chapter for a more in depth
107cover). For each trait, we produce two clauses:
108
109[RFC 2089]: https://rust-lang.github.io/rfcs/2089-implied-bounds.html
110[implied_bounds]: ./implied-bounds.md
111
112```text
113// Rule Implied-Bound-From-Trait
114//
115// For each where clause WC:
116forall<Self, P1..Pn> {
e1599b0c 117 FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)
a1dfa0c6
XL
118}
119```
120
121This clause says that if we are assuming that the trait holds, then we can also
122assume that its where-clauses hold. It's perhaps useful to see an example:
123
124```rust,ignore
125trait Eq: PartialEq { ... }
126```
127
128In this case, the `PartialEq` supertrait is equivalent to a `where
129Self: PartialEq` where clause, in our simplified model. The program
130clause above therefore states that if we can prove `FromEnv(T: Eq)` –
131e.g., if we are in some function with `T: Eq` in its where clauses –
132then we also know that `FromEnv(T: PartialEq)`. Thus the set of things
133that follow from the environment are not only the **direct where
134clauses** but also things that follow from them.
135
136The next rule is related; it defines what it means for a trait reference
137to be **well-formed**:
138
139```text
140// Rule WellFormed-TraitRef
141forall<Self, P1..Pn> {
142 WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)
143}
144```
145
146This `WellFormed` rule states that `T: Trait` is well-formed if (a)
147`T: Trait` is implemented and (b) all the where-clauses declared on
148`Trait` are well-formed (and hence they are implemented). Remember
149that the `WellFormed` predicate is
150[coinductive](./goals-and-clauses.html#coinductive); in this
151case, it is serving as a kind of "carrier" that allows us to enumerate
152all the where clauses that are transitively implied by `T: Trait`.
153
154An example:
155
156```rust,ignore
157trait Foo: A + Bar { }
158trait Bar: B + Foo { }
159trait A { }
160trait B { }
161```
162
163Here, the transitive set of implications for `T: Foo` are `T: A`, `T: Bar`, and
164`T: B`. And indeed if we were to try to prove `WellFormed(T: Foo)`, we would
165have to prove each one of those:
166
167- `WellFormed(T: Foo)`
168 - `Implemented(T: Foo)`
169 - `WellFormed(T: A)`
170 - `Implemented(T: A)`
171 - `WellFormed(T: Bar)`
172 - `Implemented(T: Bar)`
173 - `WellFormed(T: B)`
174 - `Implemented(T: Bar)`
175 - `WellFormed(T: Foo)` -- cycle, true coinductively
176
177This `WellFormed` predicate is only used when proving that impls are
178well-formed – basically, for each impl of some trait ref `TraitRef`,
179we must show that `WellFormed(TraitRef)`. This in turn justifies the
180implied bounds rules that allow us to extend the set of `FromEnv`
181items.
182
183## Lowering type definitions
184
185We also want to have some rules which define when a type is well-formed.
186For example, given this type:
187
188```rust,ignore
189struct Set<K> where K: Hash { ... }
190```
191
192then `Set<i32>` is well-formed because `i32` implements `Hash`, but
193`Set<NotHash>` would not be well-formed. Basically, a type is well-formed
194if its parameters verify the where clauses written on the type definition.
195
196Hence, for every type definition:
197
198```rust, ignore
199struct Type<P1..Pn> where WC { ... }
200```
201
202we produce the following rule:
203
204```text
205// Rule WellFormed-Type
206forall<P1..Pn> {
207 WellFormed(Type<P1..Pn>) :- WC
208}
209```
210
211Note that we use `struct` for defining a type, but this should be understood
212as a general type definition (it could be e.g. a generic `enum`).
213
214Conversely, we define rules which say that if we assume that a type is
215well-formed, we can also assume that its where clauses hold. That is,
216we produce the following family of rules:
217
218```text
219// Rule Implied-Bound-From-Type
220//
221// For each where clause `WC`
222forall<P1..Pn> {
223 FromEnv(WC) :- FromEnv(Type<P1..Pn>)
224}
225```
226
227As for the implied bounds RFC, functions will *assume* that their arguments
228are well-formed. For example, suppose we have the following bit of code:
229
230```rust,ignore
231trait Hash: Eq { }
232struct Set<K: Hash> { ... }
233
234fn foo<K>(collection: Set<K>, x: K, y: K) {
235 // `x` and `y` can be equalized even if we did not explicitly write
236 // `where K: Eq`
237 if x == y {
238 ...
239 }
240}
241```
242
243In the `foo` function, we assume that `Set<K>` is well-formed, i.e. we have
244`FromEnv(Set<K>)` in our environment. Because of the previous rule, we get
245 `FromEnv(K: Hash)` without needing an explicit where clause. And because
246of the `Hash` trait definition, there also exists a rule which says:
247
248```text
249forall<K> {
250 FromEnv(K: Eq) :- FromEnv(K: Hash)
251}
252```
253
254which means that we finally get `FromEnv(K: Eq)` and then can compare `x`
255and `y` without needing an explicit where clause.
256
257<a name="trait-items"></a>
258
259## Lowering trait items
260
261### Associated type declarations
262
263Given a trait that declares a (possibly generic) associated type:
264
265```rust,ignore
266trait Trait<P1..Pn> // P0 == Self
267where WC
268{
269 type AssocType<Pn+1..Pm>: Bounds where WC1;
270}
271```
272
273We will produce a number of program clauses. The first two define
274the rules by which `ProjectionEq` can succeed; these two clauses are discussed
275in detail in the [section on associated types](./associated-types.html),
276but reproduced here for reference:
277
278```text
279// Rule ProjectionEq-Normalize
280//
281// ProjectionEq can succeed by normalizing:
282forall<Self, P1..Pn, Pn+1..Pm, U> {
283 ProjectionEq(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> = U) :-
284 Normalize(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> -> U)
285}
286```
287
288```text
289// Rule ProjectionEq-Placeholder
290//
291// ProjectionEq can succeed through the placeholder associated type,
292// see "associated type" chapter for more:
293forall<Self, P1..Pn, Pn+1..Pm> {
294 ProjectionEq(
295 <Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> =
296 (Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>
297 )
298}
299```
300
301The next rule covers implied bounds for the projection. In particular,
302the `Bounds` declared on the associated type must have been proven to hold
303to show that the impl is well-formed, and hence we can rely on them
304elsewhere.
305
306```text
307// Rule Implied-Bound-From-AssocTy
308//
309// For each `Bound` in `Bounds`:
310forall<Self, P1..Pn, Pn+1..Pm> {
311 FromEnv(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm>>: Bound) :-
312 FromEnv(Self: Trait<P1..Pn>) && WC1
313}
314```
315
316Next, we define the requirements for an instantiation of our associated
317type to be well-formed...
318
319```text
320// Rule WellFormed-AssocTy
321forall<Self, P1..Pn, Pn+1..Pm> {
322 WellFormed((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>) :-
323 Implemented(Self: Trait<P1..Pn>) && WC1
324}
325```
326
327...along with the reverse implications, when we can assume that it is
328well-formed.
329
330```text
331// Rule Implied-WC-From-AssocTy
332//
333// For each where clause WC1:
334forall<Self, P1..Pn, Pn+1..Pm> {
335 FromEnv(WC1) :- FromEnv((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
336}
337```
338
339```text
340// Rule Implied-Trait-From-AssocTy
341forall<Self, P1..Pn, Pn+1..Pm> {
342 FromEnv(Self: Trait<P1..Pn>) :-
343 FromEnv((Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>)
344}
345```
346
347### Lowering function and constant declarations
348
349Chalk didn't model functions and constants, but I would eventually like to
350treat them exactly like normalization. See [the section on function/constant
351values below](#constant-vals) for more details.
352
353## Lowering impls
354
355Given an impl of a trait:
356
357```rust,ignore
358impl<P0..Pn> Trait<A1..An> for A0
359where WC
360{
361 // zero or more impl items
362}
363```
364
365Let `TraitRef` be the trait reference `A0: Trait<A1..An>`. Then we
366will create the following rules:
367
368```text
369// Rule Implemented-From-Impl
370forall<P0..Pn> {
371 Implemented(TraitRef) :- WC
372}
373```
374
375In addition, we will lower all of the *impl items*.
376
377## Lowering impl items
378
379### Associated type values
380
381Given an impl that contains:
382
383```rust,ignore
384impl<P0..Pn> Trait<P1..Pn> for P0
385where WC_impl
386{
387 type AssocType<Pn+1..Pm> = T;
388}
389```
390
391and our where clause `WC1` on the trait associated type from above, we
392produce the following rule:
393
394```text
395// Rule Normalize-From-Impl
396forall<P0..Pm> {
397 forall<Pn+1..Pm> {
398 Normalize(<P0 as Trait<P1..Pn>>::AssocType<Pn+1..Pm> -> T) :-
399 Implemented(P0 as Trait) && WC1
400 }
401}
402```
403
404Note that `WC_impl` and `WC1` both encode where-clauses that the impl can
405rely on. (`WC_impl` is not used here, because it is implied by
406`Implemented(P0 as Trait)`.)
407
408<a name="constant-vals"></a>
409
410### Function and constant values
411
412Chalk didn't model functions and constants, but I would eventually
413like to treat them exactly like normalization. This presumably
414involves adding a new kind of parameter (constant), and then having a
415`NormalizeValue` domain goal. This is *to be written* because the
416details are a bit up in the air.