Skip to content

Commit 95f9957

Browse files
committed
numerous edits
1 parent 5311531 commit 95f9957

6 files changed

+53
-34
lines changed

src/SUMMARY.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424
- [Trait solving (new-style)](./traits.md)
2525
- [Lowering to logic](./traits-lowering-to-logic.md)
2626
- [Goals and clauses](./traits-goals-and-clauses.md)
27-
- [Lowering rules](./traits-lowering-rules.md)
27+
- [Equality and associated types](./traits-associated-types.md)
28+
- [Region constraints](./traits-regions.md)
2829
- [Canonical queries](./traits-canonical-queries.md)
2930
- [Canonicalization](./traits-canonicalization.md)
30-
- [Equality and associated types](./traits-associated-types.md)
31-
- [Region constraints](./traits-regions.md)
31+
- [Lowering rules](./traits-lowering-rules.md)
3232
- [Well-formedness checking](./traits-wf.md)
3333
- [The SLG solver](./traits-slg.md)
3434
- [Bibliography](./traits-bibliography.md)

src/glossary.md

+3
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@ LTO | Link-Time Optimizations. A set of optimizations offer
3131
[LLVM] | (actually not an acronym :P) an open-source compiler backend. It accepts LLVM IR and outputs native binaries. Various languages (e.g. Rust) can then implement a compiler front-end that output LLVM IR and use LLVM to compile to all the platforms LLVM supports.
3232
MIR | the Mid-level IR that is created after type-checking for use by borrowck and trans ([see more](./mir.html))
3333
miri | an interpreter for MIR used for constant evaluation ([see more](./miri.html))
34+
normalize | a general term for converting to a more canonical form, but in the case of rustc typically refers to [associated type normalization](./traits-associated-types.html#normalize)
3435
newtype | a "newtype" is a wrapper around some other type (e.g., `struct Foo(T)` is a "newtype" for `T`). This is commonly used in Rust to give a stronger type for indices.
3536
NLL | [non-lexical lifetimes](./mir-regionck.html), an extension to Rust's borrowing system to make it be based on the control-flow graph.
3637
node-id or NodeId | an index identifying a particular node in the AST or HIR; gradually being phased out and replaced with `HirId`.
3738
obligation | something that must be proven by the trait system ([see more](trait-resolution.html))
39+
projection | a general term for a "relative path", e.g. `x.f` is a "field projection", and `T::Item` is an ["associated type projection"](./traits-goals-and-clauses.html#trait-ref)
3840
promoted constants | constants extracted from a function and lifted to static scope; see [this section](./mir.html#promoted) for more details.
3941
provider | the function that executes a query ([see more](query.html))
4042
quantified | in math or logic, existential and universal quantification are used to ask questions like "is there any type T for which is true?" or "is this true for all types T?"; see [the background chapter for more](./background.html#quantified)
@@ -49,6 +51,7 @@ span | a location in the user's source code, used for error
4951
substs | the substitutions for a given generic type or item (e.g. the `i32`, `u32` in `HashMap<i32, u32>`)
5052
tcx | the "typing context", main data structure of the compiler ([see more](ty.html))
5153
'tcx | the lifetime of the currently active inference context ([see more](ty.html))
54+
trait reference | the name of a trait along with a suitable set of input type/lifetimes ([see more](./traits-goals-and-clauses.html#trait-ref))
5255
token | the smallest unit of parsing. Tokens are produced after lexing ([see more](the-parser.html)).
5356
[TLS] | Thread-Local Storage. Variables may be defined so that each thread has its own copy (rather than all threads sharing the variable). This has some interactions with LLVM. Not all platforms support TLS.
5457
trans | the code to translate MIR into LLVM IR.

src/traits-associated-types.md

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ that syntax is expanded during
2020
["type collection"](./type-checking.html) into the explicit form,
2121
though that is something we may want to change in the future.)
2222

23+
<a name=normalize>
24+
2325
In some cases, associated type projections can be **normalized** --
2426
that is, simplified -- based on the types given in an impl. So, to
2527
continue with our example, the impl of `IntoIterator` for `Option<T>`

src/traits-goals-and-clauses.md

+14-4
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ a few new superpowers.
1212
In Rust's solver, **goals** and **clauses** have the following forms
1313
(note that the two definitions reference one another):
1414

15-
Goal = DomainGoal
15+
Goal = DomainGoal // defined in the section below
1616
| Goal && Goal
1717
| Goal || Goal
1818
| exists<K> { Goal } // existential quantification
1919
| forall<K> { Goal } // universal quantification
2020
| if (Clause) { Goal } // implication
21+
| true // something that's trivially true
22+
| ambiguous // something that's never provable
2123

2224
Clause = DomainGoal
2325
| Clause :- Goal // if can prove Goal, then Clause is true
@@ -39,9 +41,11 @@ gives the details.
3941

4042
## Domain goals
4143

44+
<a name=trait-ref>
45+
4246
To define the set of *domain goals* in our system, we need to first
4347
introduce a few simple formulations. A **trait reference** consists of
44-
the name of a trait allow with a suitable set of inputs P0..Pn:
48+
the name of a trait along with a suitable set of inputs P0..Pn:
4549

4650
TraitRef = P0: TraitName<P1..Pn>
4751

@@ -50,7 +54,9 @@ IntoIterator`. Note that Rust surface syntax also permits some extra
5054
things, like associated type bindings (`Vec<T>: IntoIterator<Item =
5155
T>`), that are not part of a trait reference.
5256

53-
A **projection** consists of a an associated item reference along with
57+
<a name=projection>
58+
59+
A **projection** consists of an associated item reference along with
5460
its inputs P0..Pm:
5561

5662
Projection = <P0 as TraitName<P1..Pn>>::AssocItem<Pn+1..Pm>
@@ -77,14 +83,18 @@ Given that, we can define a `DomainGoal` as follows:
7783
to [implied bounds].
7884
- `ProjectionEq(Projection = Type)` -- the given associated type `Projection` is equal
7985
to `Type`; see [the section on associated types](./traits-associated-types.html)
80-
- `Normalize(Projection -> Type)` -- the given associated type `Projection` can be normalized
86+
- in general, proving `ProjectionEq(TraitRef::Item = Type)` also
87+
requires proving `Implemented(TraitRef)`
88+
- `Normalize(Projection -> Type)` -- the given associated type `Projection` can be [normalized][n]
8189
to `Type`
8290
- as discussed in [the section on associated types](./traits-associated-types.html),
8391
`Normalize` implies `ProjectionEq` but not vice versa
8492
- `WellFormed(..)` -- these goals imply that the given item is
8593
*well-formed*
8694
- well-formedness is important to [implied bounds].
8795

96+
[n]: ./traits-associated-types.html#normalize
97+
8898
<a name=coinductive>
8999

90100
## Coinductive goals

src/traits-lowering-rules.md

+18-17
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Lowering rules
22

33
This section gives the complete lowering rules for Rust traits into
4-
[program clauses][pc]. These rules reference the [domain goals][dg] defined in
5-
an earlier section.
4+
[program clauses][pc]. It is a kind of reference. These rules
5+
reference the [domain goals][dg] defined in an earlier section.
66

77
[pc]: ./traits-goals-and-clauses.html
88
[dg]: ./traits-goals-and-clauses.html#domain-goals
@@ -22,7 +22,7 @@ definitions; these macros reference other sections within this chapter.
2222

2323
## Lowering where clauses
2424

25-
When used in a goal position, where clauses can be mapped directly
25+
When used in a goal position, where clauses can be mapped directly to
2626
[domain goals][dg], as follows:
2727

2828
- `A0: Foo<A1..An>` maps to `Implemented(A0: Foo<A1..An>)`.
@@ -72,12 +72,12 @@ inside the `{}`.
7272
### Trait header
7373

7474
From the trait itself we mostly make "meta" rules that setup the
75-
relationships between different kinds of domain goals. The first dush
75+
relationships between different kinds of domain goals. The first such
7676
rule from the trait header creates the mapping between the `FromEnv`
7777
and `Implemented` predicates:
7878

7979
forall<Self, P1..Pn> {
80-
Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn)
80+
Implemented(Self: Trait<P1..Pn>) :- FromEnv(Self: Trait<P1..Pn>)
8181
}
8282

8383
<a name="implied-bounds">
@@ -114,7 +114,7 @@ to be **well-formed**:
114114

115115
// For each where clause WC:
116116
forall<Self, P1..Pn> {
117-
WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>), WellFormed(WC)
117+
WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)
118118
}
119119

120120
This `WellFormed` rule states that `T: Trait` is well-formed if (a)
@@ -150,7 +150,7 @@ one of those:
150150

151151
This `WellFormed` predicate is only used when proving that impls are
152152
well-formed -- basically, for each impl of some trait ref `TraitRef`,
153-
we must that `WellFormed(TraitRef)`. This in turn justifies the
153+
we must show that `WellFormed(TraitRef)`. This in turn justifies the
154154
implied bounds rules that allow us to extend the set of `FromEnv`
155155
items.
156156

@@ -170,31 +170,33 @@ where WC
170170
}
171171
```
172172

173-
We will produce a number of program clases. The first two define
173+
We will produce a number of program clauses. The first two define
174174
the rules by which `ProjectionEq` can succeed; these two clauses are discussed
175-
in detail in the [section on associated types](./traits-associated-types.html).
175+
in detail in the [section on associated types](./traits-associated-types.html),,
176+
but reproduced here for reference:
176177

177178
// ProjectionEq can succeed by normalizing:
178179
forall<Self, P1..Pn, Pn+1..Pm, U> {
179180
ProjectionEq(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> = U) :-
180181
Normalize(<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> -> U)
181182
}
182183

183-
// ProjectionEq can succeed by skolemizing:
184+
// ProjectionEq can succeed by skolemizing, see "associated type"
185+
// chapter for more:
184186
forall<Self, P1..Pn, Pn+1..Pm> {
185187
ProjectionEq(
186188
<Self as Trait<P1..Pn>>::AssocType<Pn+1..Pm> =
187189
(Trait::AssocType)<Self, P1..Pn, Pn+1..Pm>
188190
) :-
189191
// But only if the trait is implemented, and the conditions from
190192
// the associated type are met as well:
191-
Implemented(Self: Trait<P1..Pn>),
192-
WC1
193+
Implemented(Self: Trait<P1..Pn>)
194+
&& WC1
193195
}
194196

195197
The next rule covers implied bounds for the projection. In particular,
196198
the `Bounds` declared on the associated type must be proven to hold to
197-
show that the impl is well-formed, and hence we can rely on them from
199+
show that the impl is well-formed, and hence we can rely on them
198200
elsewhere.
199201

200202
// XXX how exactly should we set this up? Have to be careful;
@@ -237,7 +239,7 @@ Given an impl that contains:
237239
impl<P0..Pn> Trait<A1..An> for A0
238240
where WC
239241
{
240-
type AssocType<Pn+1..Pm>: Bounds where WC1 = T;
242+
type AssocType<Pn+1..Pm> where WC1 = T;
241243
}
242244
```
243245

@@ -246,13 +248,12 @@ We produce the following rule:
246248
forall<P0..Pm> {
247249
forall<Pn+1..Pm> {
248250
Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T) :-
249-
WC, WC1
251+
WC && WC1
250252
}
251253
}
252254

253255
Note that `WC` and `WC1` both encode where-clauses that the impl can
254-
rely on, whereas the bounds `Bounds` on the associated type are things
255-
that the impl must prove (see the well-formedness checking).
256+
rely on.
256257

257258
<a name=constant-vals>
258259

src/traits-lowering-to-logic.md

+13-10
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ Prolog-like notation, as follows:
3333
```
3434
Clone(usize).
3535
Clone(Vec<?T>) :- Clone(?T).
36+
37+
// The notation `A :- B` means "A is true if B is true".
38+
// Or, put another way, B implies A.
3639
```
3740

3841
In Prolog terms, we might say that `Clone(Foo)` -- where `Foo` is some
@@ -82,28 +85,28 @@ let's turn our focus a bit towards **type-checking**. Type-checking is
8285
interesting because it is what gives us the goals that we need to
8386
prove. That is, everything we've seen so far has been about how we
8487
derive the rules by which we can prove goals from the traits and impls
85-
in the program; but we are also interesting in how derive the goals
88+
in the program; but we are also interested in how to derive the goals
8689
that we need to prove, and those come from type-checking.
8790

8891
Consider type-checking the function `foo()` here:
8992

9093
```rust
9194
fn foo() { bar::<usize>() }
92-
fn bar<U: Eq>() { }
95+
fn bar<U: Eq<U>>() { }
9396
```
9497

9598
This function is very simple, of course: all it does is to call
9699
`bar::<usize>()`. Now, looking at the definition of `bar()`, we can see
97-
that it has one where-clause `U: Eq`. So, that means that `foo()` will
98-
have to prove that `usize: Eq` in order to show that it can call `bar()`
100+
that it has one where-clause `U: Eq<U>`. So, that means that `foo()` will
101+
have to prove that `usize: Eq<usize>` in order to show that it can call `bar()`
99102
with `usize` as the type argument.
100103

101104
If we wanted, we could write a Prolog predicate that defines the
102105
conditions under which `bar()` can be called. We'll say that those
103106
conditions are called being "well-formed":
104107

105108
```
106-
barWellFormed(?U) :- Eq(?U).
109+
barWellFormed(?U) :- Eq(?U, ?U).
107110
```
108111

109112
Then we can say that `foo()` type-checks if the reference to
@@ -118,7 +121,7 @@ If we try to prove the goal `fooTypeChecks`, it will succeed:
118121

119122
- `fooTypeChecks` is provable if:
120123
- `barWellFormed(usize)`, which is provable if:
121-
- `Eq(usize)`, which is provable because of an impl.
124+
- `Eq(usize, usize)`, which is provable because of an impl.
122125

123126
Ok, so far so good. Let's move on to type-checking a more complex function.
124127

@@ -132,8 +135,8 @@ can be provide. To see what I'm talking about, let's revamp our previous
132135
example to make `foo` generic:
133136

134137
```rust
135-
fn foo<T: Eq>() { bar::<T>() }
136-
fn bar<U: Eq>() { }
138+
fn foo<T: Eq<T>>() { bar::<T>() }
139+
fn bar<U: Eq<U>>() { }
137140
```
138141

139142
To type-check the body of `foo`, we need to be able to hold the type
@@ -145,8 +148,8 @@ this like so:
145148
fooTypeChecks :-
146149
// for all types T...
147150
forall<T> {
148-
// ...if we assume that Eq(T) is provable...
149-
if (Eq(T)) {
151+
// ...if we assume that Eq(T, T) is provable...
152+
if (Eq(T, T)) {
150153
// ...then we can prove that `barWellFormed(T)` holds.
151154
barWellFormed(T)
152155
}

0 commit comments

Comments
 (0)