]> git.proxmox.com Git - rustc.git/blame - src/doc/rustc-dev-guide/src/traits/goals-and-clauses.md
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / src / doc / rustc-dev-guide / src / traits / goals-and-clauses.md
CommitLineData
a1dfa0c6
XL
1# Goals and clauses
2
6a06907d
XL
3<!-- toc -->
4
a1dfa0c6
XL
5In logic programming terms, a **goal** is something that you must
6prove and a **clause** is something that you know is true. As
7described in the [lowering to logic](./lowering-to-logic.html)
8chapter, Rust's trait solver is based on an extension of hereditary
9harrop (HH) clauses, which extend traditional Prolog Horn clauses with
10a few new superpowers.
11
12## Goals and clauses meta structure
13
14In Rust's solver, **goals** and **clauses** have the following forms
15(note that the two definitions reference one another):
16
17```text
18Goal = DomainGoal // defined in the section below
19 | Goal && Goal
20 | Goal || Goal
21 | exists<K> { Goal } // existential quantification
22 | forall<K> { Goal } // universal quantification
23 | if (Clause) { Goal } // implication
24 | true // something that's trivially true
25 | ambiguous // something that's never provable
26
27Clause = DomainGoal
28 | Clause :- Goal // if can prove Goal, then Clause is true
29 | Clause && Clause
30 | forall<K> { Clause }
31
32K = <type> // a "kind"
33 | <lifetime>
34```
35
36The proof procedure for these sorts of goals is actually quite
37straightforward. Essentially, it's a form of depth-first search. The
38paper
39["A Proof Procedure for the Logic of Hereditary Harrop Formulas"][pphhf]
40gives the details.
41
42In terms of code, these types are defined in
6a06907d 43[`rustc_middle/src/traits/mod.rs`][traits_mod] in rustc, and in
a1dfa0c6
XL
44[`chalk-ir/src/lib.rs`][chalk_ir] in chalk.
45
6a06907d
XL
46[pphhf]: https://rust-lang.github.io/chalk/book/bibliography.html#pphhf
47[traits_mod]: https://github.com/rust-lang/rust/blob/master/compiler/rustc_middle/src/traits/mod.rs
ba9703b0 48[chalk_ir]: https://github.com/rust-lang/chalk/blob/master/chalk-ir/src/lib.rs
a1dfa0c6
XL
49
50<a name="domain-goals"></a>
51
52## Domain goals
53
54*Domain goals* are the atoms of the trait logic. As can be seen in the
55definitions given above, general goals basically consist in a combination of
56domain goals.
57
416331ca 58Moreover, flattening a bit the definition of clauses given previously, one can
a1dfa0c6
XL
59see that clauses are always of the form:
60```text
61forall<K1, ..., Kn> { DomainGoal :- Goal }
62```
63hence domain goals are in fact clauses' LHS. That is, at the most granular level,
64domain goals are what the trait solver will end up trying to prove.
65
66<a name="trait-ref"></a>
67
68To define the set of domain goals in our system, we need to first
69introduce a few simple formulations. A **trait reference** consists of
70the name of a trait along with a suitable set of inputs P0..Pn:
71
72```text
73TraitRef = P0: TraitName<P1..Pn>
74```
75
76So, for example, `u32: Display` is a trait reference, as is `Vec<T>:
77IntoIterator`. Note that Rust surface syntax also permits some extra
78things, like associated type bindings (`Vec<T>: IntoIterator<Item =
79T>`), that are not part of a trait reference.
80
81<a name="projection"></a>
82
83A **projection** consists of an associated item reference along with
84its inputs P0..Pm:
85
86```text
87Projection = <P0 as TraitName<P1..Pn>>::AssocItem<Pn+1..Pm>
88```
89
90Given these, we can define a `DomainGoal` as follows:
91
92```text
93DomainGoal = Holds(WhereClause)
94 | FromEnv(TraitRef)
95 | FromEnv(Type)
96 | WellFormed(TraitRef)
97 | WellFormed(Type)
98 | Normalize(Projection -> Type)
99
100WhereClause = Implemented(TraitRef)
101 | ProjectionEq(Projection = Type)
102 | Outlives(Type: Region)
103 | Outlives(Region: Region)
104```
105
106`WhereClause` refers to a `where` clause that a Rust user would actually be able
107to write in a Rust program. This abstraction exists only as a convenience as we
108sometimes want to only deal with domain goals that are effectively writable in
109Rust.
110
111Let's break down each one of these, one-by-one.
112
113#### Implemented(TraitRef)
114e.g. `Implemented(i32: Copy)`
115
116True if the given trait is implemented for the given input types and lifetimes.
117
118#### ProjectionEq(Projection = Type)
119e.g. `ProjectionEq<T as Iterator>::Item = u8`
120
121The given associated type `Projection` is equal to `Type`; this can be proved
122with either normalization or using placeholder associated types. See
6a06907d 123[the section on associated types in Chalk Book][at].
a1dfa0c6
XL
124
125#### Normalize(Projection -> Type)
126e.g. `ProjectionEq<T as Iterator>::Item -> u8`
127
128The given associated type `Projection` can be [normalized][n] to `Type`.
129
130As discussed in [the section on associated
6a06907d 131types in Chalk Book][at], `Normalize` implies `ProjectionEq`,
a1dfa0c6
XL
132but not vice versa. In general, proving `Normalize(<T as Trait>::Item -> U)`
133also requires proving `Implemented(T: Trait)`.
134
6a06907d
XL
135[n]: https://rust-lang.github.io/chalk/book/clauses/type_equality.html#normalize
136[at]: https://rust-lang.github.io/chalk/book/clauses/type_equality.html
a1dfa0c6
XL
137
138#### FromEnv(TraitRef)
139e.g. `FromEnv(Self: Add<i32>)`
140
141True if the inner `TraitRef` is *assumed* to be true,
142that is, if it can be derived from the in-scope where clauses.
143
144For example, given the following function:
145
146```rust
147fn loud_clone<T: Clone>(stuff: &T) -> T {
148 println!("cloning!");
149 stuff.clone()
150}
151```
152
153Inside the body of our function, we would have `FromEnv(T: Clone)`. In-scope
154where clauses nest, so a function body inside an impl body inherits the
155impl body's where clauses, too.
156
157This and the next rule are used to implement [implied bounds]. As we'll see
158in the section on lowering, `FromEnv(TraitRef)` implies `Implemented(TraitRef)`,
159but not vice versa. This distinction is crucial to implied bounds.
160
161#### FromEnv(Type)
162e.g. `FromEnv(HashSet<K>)`
163
164True if the inner `Type` is *assumed* to be well-formed, that is, if it is an
165input type of a function or an impl.
166
167For example, given the following code:
168
169```rust,ignore
170struct HashSet<K> where K: Hash { ... }
171
172fn loud_insert<K>(set: &mut HashSet<K>, item: K) {
173 println!("inserting!");
174 set.insert(item);
175}
176```
177
178`HashSet<K>` is an input type of the `loud_insert` function. Hence, we assume it
179to be well-formed, so we would have `FromEnv(HashSet<K>)` inside the body of our
180function. As we'll see in the section on lowering, `FromEnv(HashSet<K>)` implies
181`Implemented(K: Hash)` because the
182`HashSet` declaration was written with a `K: Hash` where clause. Hence, we don't
183need to repeat that bound on the `loud_insert` function: we rather automatically
184assume that it is true.
185
186#### WellFormed(Item)
187These goals imply that the given item is *well-formed*.
188
189We can talk about different types of items being well-formed:
190
191* *Types*, like `WellFormed(Vec<i32>)`, which is true in Rust, or
192 `WellFormed(Vec<str>)`, which is not (because `str` is not `Sized`.)
193
194* *TraitRefs*, like `WellFormed(Vec<i32>: Clone)`.
195
196Well-formedness is important to [implied bounds]. In particular, the reason
197it is okay to assume `FromEnv(T: Clone)` in the `loud_clone` example is that we
198_also_ verify `WellFormed(T: Clone)` for each call site of `loud_clone`.
199Similarly, it is okay to assume `FromEnv(HashSet<K>)` in the `loud_insert`
200example because we will verify `WellFormed(HashSet<K>)` for each call site of
6a06907d 201`loud_insert`.
a1dfa0c6
XL
202
203#### Outlives(Type: Region), Outlives(Region: Region)
204e.g. `Outlives(&'a str: 'b)`, `Outlives('a: 'static)`
205
206True if the given type or region on the left outlives the right-hand region.
207
208<a name="coinductive"></a>
209
210## Coinductive goals
211
212Most goals in our system are "inductive". In an inductive goal,
213circular reasoning is disallowed. Consider this example clause:
214
215```text
216 Implemented(Foo: Bar) :-
217 Implemented(Foo: Bar).
218```
219
220Considered inductively, this clause is useless: if we are trying to
221prove `Implemented(Foo: Bar)`, we would then recursively have to prove
222`Implemented(Foo: Bar)`, and that cycle would continue ad infinitum
223(the trait solver will terminate here, it would just consider that
224`Implemented(Foo: Bar)` is not known to be true).
225
226However, some goals are *co-inductive*. Simply put, this means that
227cycles are OK. So, if `Bar` were a co-inductive trait, then the rule
228above would be perfectly valid, and it would indicate that
229`Implemented(Foo: Bar)` is true.
230
231*Auto traits* are one example in Rust where co-inductive goals are used.
232Consider the `Send` trait, and imagine that we have this struct:
233
234```rust
235struct Foo {
236 next: Option<Box<Foo>>
237}
238```
239
240The default rules for auto traits say that `Foo` is `Send` if the
241types of its fields are `Send`. Therefore, we would have a rule like
242
243```text
244Implemented(Foo: Send) :-
245 Implemented(Option<Box<Foo>>: Send).
246```
247
248As you can probably imagine, proving that `Option<Box<Foo>>: Send` is
249going to wind up circularly requiring us to prove that `Foo: Send`
250again. So this would be an example where we wind up in a cycle – but
251that's ok, we *do* consider `Foo: Send` to hold, even though it
252references itself.
253
254In general, co-inductive traits are used in Rust trait solving when we
255want to enumerate a fixed set of possibilities. In the case of auto
256traits, we are enumerating the set of reachable types from a given
257starting point (i.e., `Foo` can reach values of type
258`Option<Box<Foo>>`, which implies it can reach values of type
259`Box<Foo>`, and then of type `Foo`, and then the cycle is complete).
260
261In addition to auto traits, `WellFormed` predicates are co-inductive.
262These are used to achieve a similar "enumerate all the cases" pattern,
263as described in the section on [implied bounds].
264
6a06907d 265[implied bounds]: https://rust-lang.github.io/chalk/book/clauses/implied_bounds.html#implied-bounds
a1dfa0c6
XL
266
267## Incomplete chapter
268
269Some topics yet to be written:
270
271- Elaborate on the proof procedure
272- SLG solving – introduce negative reasoning