Skip to content

Commit c207e4c

Browse files
authored
Merge pull request #70 from nikomatsakis/traits
work on traits chapters
2 parents 86c5f6c + 49e8e09 commit c207e4c

16 files changed

+1322
-3
lines changed

src/SUMMARY.md

+14-2
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,22 @@
1717
- [The HIR (High-level IR)](./hir.md)
1818
- [The `ty` module: representing types](./ty.md)
1919
- [Type inference](./type-inference.md)
20-
- [Trait resolution](./trait-resolution.md)
20+
- [Trait solving (old-style)](./trait-resolution.md)
2121
- [Higher-ranked trait bounds](./trait-hrtb.md)
2222
- [Caching subtleties](./trait-caching.md)
23-
- [Speciailization](./trait-specialization.md)
23+
- [Specialization](./trait-specialization.md)
24+
- [Trait solving (new-style)](./traits.md)
25+
- [Lowering to logic](./traits-lowering-to-logic.md)
26+
- [Goals and clauses](./traits-goals-and-clauses.md)
27+
- [Equality and associated types](./traits-associated-types.md)
28+
- [Implied bounds](./traits-implied-bounds.md)
29+
- [Region constraints](./traits-regions.md)
30+
- [Canonical queries](./traits-canonical-queries.md)
31+
- [Canonicalization](./traits-canonicalization.md)
32+
- [Lowering rules](./traits-lowering-rules.md)
33+
- [Well-formedness checking](./traits-wf.md)
34+
- [The SLG solver](./traits-slg.md)
35+
- [Bibliography](./traits-bibliography.md)
2436
- [Type checking](./type-checking.md)
2537
- [The MIR (Mid-level IR)](./mir.md)
2638
- [MIR construction](./mir-construction.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/trait-resolution.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
# Trait resolution
1+
# Trait resolution (old-style)
22

33
This chapter describes the general process of _trait resolution_ and points out
44
some non-obvious things.
55

6+
**Note:** This chapter (and its subchapters) describe how the trait
7+
solver **currently** works. However, we are in the process of
8+
designing a new trait solver. If you'd prefer to read about *that*,
9+
see [*this* traits chapter](./traits.html).
10+
611
## Major concepts
712

813
Trait resolution is the process of pairing up an impl with each

src/traits-associated-types.md

+145
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# Equality and associated types
2+
3+
This section covers how the trait system handles equality between
4+
associated types. The full system consists of several moving parts,
5+
which we will introduce one by one:
6+
7+
- Projection and the `Normalize` predicate
8+
- Skolemization
9+
- The `ProjectionEq` predicate
10+
- Integration with unification
11+
12+
## Associated type projection and normalization
13+
14+
When a trait defines an associated type (e.g.,
15+
[the `Item` type in the `IntoIterator` trait][intoiter-item]), that
16+
type can be referenced by the user using an **associated type
17+
projection** like `<Option<u32> as IntoIterator>::Item`. (Often,
18+
though, people will use the shorthand syntax `T::Item` -- presently,
19+
that syntax is expanded during
20+
["type collection"](./type-checking.html) into the explicit form,
21+
though that is something we may want to change in the future.)
22+
23+
<a name=normalize>
24+
25+
In some cases, associated type projections can be **normalized** --
26+
that is, simplified -- based on the types given in an impl. So, to
27+
continue with our example, the impl of `IntoIterator` for `Option<T>`
28+
declares (among other things) that `Item = T`:
29+
30+
```rust
31+
impl<T> IntoIterator for Option<T> {
32+
type Item = T;
33+
..
34+
}
35+
```
36+
37+
This means we can normalize the projection `<Option<u32> as
38+
IntoIterator>::Item` to just `u32`.
39+
40+
In this case, the projection was a "monomorphic" one -- that is, it
41+
did not have any type parameters. Monomorphic projections are special
42+
because they can **always** be fully normalized -- but often we can
43+
normalize other associated type projections as well. For example,
44+
`<Option<?T> as IntoIterator>::Item` (where `?T` is an inference
45+
variable) can be normalized to just `?T`.
46+
47+
In our logic, normalization is defined by a predicate
48+
`Normalize`. The `Normalize` clauses arise only from
49+
impls. For example, the `impl` of `IntoIterator` for `Option<T>` that
50+
we saw above would be lowered to a program clause like so:
51+
52+
forall<T> {
53+
Normalize(<Option<T> as IntoIterator>::Item -> T)
54+
}
55+
56+
(An aside: since we do not permit quantification over traits, this is
57+
really more like a family of predicates, one for each associated
58+
type.)
59+
60+
We could apply that rule to normalize either of the examples that
61+
we've seen so far.
62+
63+
## Skolemized associated types
64+
65+
Sometimes however we want to work with associated types that cannot be
66+
normalized. For example, consider this function:
67+
68+
```rust
69+
fn foo<T: IntoIterator>(...) { ... }
70+
```
71+
72+
In this context, how would we normalize the type `T::Item`? Without
73+
knowing what `T` is, we can't really do so. To represent this case, we
74+
introduce a type called a **skolemized associated type
75+
projection**. This is written like so `(IntoIterator::Item)<T>`. You
76+
may note that it looks a lot like a regular type (e.g., `Option<T>`),
77+
except that the "name" of the type is `(IntoIterator::Item)`. This is
78+
not an accident: skolemized associated type projections work just like
79+
ordinary types like `Vec<T>` when it comes to unification. That is,
80+
they are only considered equal if (a) they are both references to the
81+
same associated type, like `IntoIterator::Item` and (b) their type
82+
arguments are equal.
83+
84+
Skolemized associated types are never written directly by the user.
85+
They are used internally by the trait system only, as we will see
86+
shortly.
87+
88+
## Projection equality
89+
90+
So far we have seen two ways to answer the question of "When can we
91+
consider an associated type projection equal to another type?":
92+
93+
- the `Normalize` predicate could be used to transform associated type
94+
projections when we knew which impl was applicable;
95+
- **skolemized** associated types can be used when we don't.
96+
97+
We now introduce the `ProjectionEq` predicate to bring those two cases
98+
together. The `ProjectionEq` predicate looks like so:
99+
100+
ProjectionEq(<T as IntoIterator>::Item = U)
101+
102+
and we will see that it can be proven *either* via normalization or
103+
skolemization. As part of lowering an associated type declaration from
104+
some trait, we create two program clauses for `ProjectionEq`:
105+
106+
forall<T, U> {
107+
ProjectionEq(<T as IntoIterator>::Item = U) :-
108+
Normalize(<T as IntoIterator>::Item -> U)
109+
}
110+
111+
forall<T> {
112+
ProjectionEq(<T as IntoIterator>::Item = (IntoIterator::Item)<T>)
113+
}
114+
115+
These are the only two `ProjectionEq` program clauses we ever make for
116+
any given associated item.
117+
118+
## Integration with unification
119+
120+
Now we are ready to discuss how associated type equality integrates
121+
with unification. As described in the
122+
[type inference](./type-inference.html) section, unification is
123+
basically a procedure with a signature like this:
124+
125+
Unify(A, B) = Result<(Subgoals, RegionConstraints), NoSolution>
126+
127+
In other words, we try to unify two things A and B. That procedure
128+
might just fail, in which case we get back `Err(NoSolution)`. This
129+
would happen, for example, if we tried to unify `u32` and `i32`.
130+
131+
The key point is that, on success, unification can also give back to
132+
us a set of subgoals that still remain to be proven (it can also give
133+
back region constraints, but those are not relevant here).
134+
135+
Whenever unification encounters an (unskolemized!) associated type
136+
projection P being equated with some other type T, it always succeeds,
137+
but it produces a subgoal `ProjectionEq(P = T)` that is propagated
138+
back up. Thus it falls to the ordinary workings of the trait system
139+
to process that constraint.
140+
141+
(If we unify two projections P1 and P2, then unification produces a
142+
variable X and asks us to prove that `ProjectionEq(P1 = X)` and
143+
`ProjectionEq(P2 = X)`. That used to be needed in an older system to
144+
prevent cycles; I rather doubt it still is. -nmatsakis)
145+

src/traits-bibliography.md

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Bibliography
2+
3+
If you'd like to read more background material, here are some
4+
recommended texts and papers:
5+
6+
[Programming with Higher-order Logic][phl], by Dale Miller and Gopalan
7+
Nadathur, covers the key concepts of Lambda prolog. Although it's a
8+
slim little volume, it's the kind of book where you learn something
9+
new every time you open it.
10+
11+
[phl]: https://www.amazon.com/Programming-Higher-Order-Logic-Dale-Miller/dp/052187940X
12+
13+
<a name=pphhf>
14+
15+
["A proof procedure for the logic of Hereditary Harrop formulas"][pphhf],
16+
by Gopalan Nadathur. This paper covers the basics of universes,
17+
environments, and Lambda Prolog-style proof search. Quite readable.
18+
19+
[pphhf]: https://dl.acm.org/citation.cfm?id=868380
20+
21+
<a name=slg>
22+
23+
["A new formulation of tabled resolution with delay"][nftrd], by
24+
[Theresa Swift]. This paper gives a kind of abstract treatment of the
25+
SLG formulation that is the basis for our on-demand solver.
26+
27+
[nftrd]: https://dl.acm.org/citation.cfm?id=651202
28+
[ts]: http://www3.cs.stonybrook.edu/~tswift/

0 commit comments

Comments
 (0)