Skip to content

Commit 62e7f15

Browse files
authored
Merge pull request #219 from tmandry/reorg-traits
Traits chapter cleanup
2 parents 34c9d3f + 74e2af2 commit 62e7f15

File tree

4 files changed

+86
-63
lines changed

4 files changed

+86
-63
lines changed

src/SUMMARY.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@
3939
- [Equality and associated types](./traits/associated-types.md)
4040
- [Implied bounds](./traits/implied-bounds.md)
4141
- [Region constraints](./traits/regions.md)
42+
- [The lowering module in rustc](./traits/lowering-module.md)
43+
- [Lowering rules](./traits/lowering-rules.md)
44+
- [Well-formedness checking](./traits/wf.md)
4245
- [Canonical queries](./traits/canonical-queries.md)
4346
- [Canonicalization](./traits/canonicalization.md)
44-
- [Lowering rules](./traits/lowering-rules.md)
45-
- [The lowering module in rustc](./traits/lowering-module.md)
46-
- [Well-formedness checking](./traits/wf.md)
4747
- [The SLG solver](./traits/slg.md)
4848
- [An Overview of Chalk](./traits/chalk-overview.md)
4949
- [Bibliography](./traits/bibliography.md)

src/traits/associated-types.md

Lines changed: 35 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ associated types. The full system consists of several moving parts,
55
which we will introduce one by one:
66

77
- Projection and the `Normalize` predicate
8-
- Skolemization
8+
- Placeholder associated type projections
99
- The `ProjectionEq` predicate
1010
- Integration with unification
1111

@@ -14,11 +14,11 @@ which we will introduce one by one:
1414
When a trait defines an associated type (e.g.,
1515
[the `Item` type in the `IntoIterator` trait][intoiter-item]), that
1616
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.)
17+
projection** like `<Option<u32> as IntoIterator>::Item`.
18+
19+
> Often, people will use the shorthand syntax `T::Item`. Presently, that
20+
> syntax is expanded during ["type collection"](../type-checking.html) into the
21+
> explicit form, though that is something we may want to change in the future.
2222
2323
[intoiter-item]: https://doc.rust-lang.org/nightly/core/iter/trait.IntoIterator.html#associatedtype.Item
2424

@@ -41,10 +41,11 @@ IntoIterator>::Item` to just `u32`.
4141

4242
In this case, the projection was a "monomorphic" one – that is, it
4343
did not have any type parameters. Monomorphic projections are special
44-
because they can **always** be fully normalized – but often we can
45-
normalize other associated type projections as well. For example,
46-
`<Option<?T> as IntoIterator>::Item` (where `?T` is an inference
47-
variable) can be normalized to just `?T`.
44+
because they can **always** be fully normalized.
45+
46+
Often, we can normalize other associated type projections as well. For
47+
example, `<Option<?T> as IntoIterator>::Item`, where `?T` is an inference
48+
variable, can be normalized to just `?T`.
4849

4950
In our logic, normalization is defined by a predicate
5051
`Normalize`. The `Normalize` clauses arise only from
@@ -60,9 +61,8 @@ forall<T> {
6061

6162
where in this case, the one `Implemented` condition is always true.
6263

63-
(An aside: since we do not permit quantification over traits, this is
64-
really more like a family of program clauses, one for each associated
65-
type.)
64+
> Since we do not permit quantification over traits, this is really more like
65+
> a family of program clauses, one for each associated type.
6666
6767
We could apply that rule to normalize either of the examples that
6868
we've seen so far.
@@ -76,17 +76,18 @@ normalized. For example, consider this function:
7676
fn foo<T: IntoIterator>(...) { ... }
7777
```
7878

79-
In this context, how would we normalize the type `T::Item`? Without
80-
knowing what `T` is, we can't really do so. To represent this case, we
81-
introduce a type called a **placeholder associated type
82-
projection**. This is written like so `(IntoIterator::Item)<T>`. You
83-
may note that it looks a lot like a regular type (e.g., `Option<T>`),
84-
except that the "name" of the type is `(IntoIterator::Item)`. This is
85-
not an accident: placeholder associated type projections work just like
86-
ordinary types like `Vec<T>` when it comes to unification. That is,
87-
they are only considered equal if (a) they are both references to the
88-
same associated type, like `IntoIterator::Item` and (b) their type
89-
arguments are equal.
79+
In this context, how would we normalize the type `T::Item`?
80+
81+
Without knowing what `T` is, we can't really do so. To represent this case,
82+
we introduce a type called a **placeholder associated type projection**. This
83+
is written like so: `(IntoIterator::Item)<T>`.
84+
85+
You may note that it looks a lot like a regular type (e.g., `Option<T>`),
86+
except that the "name" of the type is `(IntoIterator::Item)`. This is not an
87+
accident: placeholder associated type projections work just like ordinary
88+
types like `Vec<T>` when it comes to unification. That is, they are only
89+
considered equal if (a) they are both references to the same associated type,
90+
like `IntoIterator::Item` and (b) their type arguments are equal.
9091

9192
Placeholder associated types are never written directly by the user.
9293
They are used internally by the trait system only, as we will see
@@ -106,9 +107,10 @@ placeholder associated types (see the `TypeName` enum declared in
106107
So far we have seen two ways to answer the question of "When can we
107108
consider an associated type projection equal to another type?":
108109

109-
- the `Normalize` predicate could be used to transform associated type
110-
projections when we knew which impl was applicable;
111-
- **placeholder** associated types can be used when we don't.
110+
- the `Normalize` predicate could be used to transform projections when we
111+
knew which impl applied;
112+
- **placeholder** associated types can be used when we don't. This is also
113+
known as **lazy normalization**.
112114

113115
We now introduce the `ProjectionEq` predicate to bring those two cases
114116
together. The `ProjectionEq` predicate looks like so:
@@ -151,16 +153,16 @@ might just fail, in which case we get back `Err(NoSolution)`. This
151153
would happen, for example, if we tried to unify `u32` and `i32`.
152154

153155
The key point is that, on success, unification can also give back to
154-
us a set of subgoals that still remain to be proven (it can also give
156+
us a set of subgoals that still remain to be proven. (It can also give
155157
back region constraints, but those are not relevant here).
156158

157-
Whenever unification encounters an (un-placeholder!) associated type
159+
Whenever unification encounters a non-placeholder associated type
158160
projection P being equated with some other type T, it always succeeds,
159161
but it produces a subgoal `ProjectionEq(P = T)` that is propagated
160162
back up. Thus it falls to the ordinary workings of the trait system
161163
to process that constraint.
162164

163-
(If we unify two projections P1 and P2, then unification produces a
164-
variable X and asks us to prove that `ProjectionEq(P1 = X)` and
165-
`ProjectionEq(P2 = X)`. That used to be needed in an older system to
166-
prevent cycles; I rather doubt it still is. -nmatsakis)
165+
> If we unify two projections P1 and P2, then unification produces a
166+
> variable X and asks us to prove that `ProjectionEq(P1 = X)` and
167+
> `ProjectionEq(P2 = X)`. (That used to be needed in an older system to
168+
> prevent cycles; I rather doubt it still is. -nmatsakis)

src/traits/index.md

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,63 @@
11
# Trait solving (new-style)
22

3-
🚧 This chapter describes "new-style" trait solving. This is still in the
4-
[process of being implemented][wg]; this chapter serves as a kind of
5-
in-progress design document. If you would prefer to read about how the
6-
current trait solver works, check out
7-
[this other chapter](./resolution.html). (By the way, if you
8-
would like to help in hacking on the new solver, you will find
9-
instructions for getting involved in the
10-
[Traits Working Group tracking issue][wg].) 🚧
3+
> 🚧 This chapter describes "new-style" trait solving. This is still in the
4+
> [process of being implemented][wg]; this chapter serves as a kind of
5+
> in-progress design document. If you would prefer to read about how the
6+
> current trait solver works, check out
7+
> [this other chapter](./resolution.html). 🚧
8+
>
9+
> By the way, if you would like to help in hacking on the new solver, you will
10+
> find instructions for getting involved in the
11+
> [Traits Working Group tracking issue][wg]!
1112
1213
[wg]: https://github.com/rust-lang/rust/issues/48416
1314

14-
Trait solving is based around a few key ideas:
15+
The new-style trait solver is based on the work done in [chalk][chalk]. Chalk
16+
recasts Rust's trait system explicitly in terms of logic programming. It does
17+
this by "lowering" Rust code into a kind of logic program we can then execute
18+
queries against.
19+
20+
You can read more about chalk itself in the
21+
[Overview of Chalk](./chalk-overview.md) section.
22+
23+
Trait solving in rustc is based around a few key ideas:
1524

1625
- [Lowering to logic](./lowering-to-logic.html), which expresses
1726
Rust traits in terms of standard logical terms.
1827
- The [goals and clauses](./goals-and-clauses.html) chapter
1928
describes the precise form of rules we use, and
2029
[lowering rules](./lowering-rules.html) gives the complete set of
2130
lowering rules in a more reference-like form.
31+
- [Lazy normalization](./associated-types.html), which is the
32+
technique we use to accommodate associated types when figuring out
33+
whether types are equal.
34+
- [Region constraints](./regions.html), which are accumulated
35+
during trait solving but mostly ignored. This means that trait
36+
solving effectively ignores the precise regions involved, always –
37+
but we still remember the constraints on them so that those
38+
constraints can be checked by the type checker.
2239
- [Canonical queries](./canonical-queries.html), which allow us
2340
to solve trait problems (like "is `Foo` implemented for the type
2441
`Bar`?") once, and then apply that same result independently in many
2542
different inference contexts.
26-
- [Lazy normalization](./associated-types.html), which is the
27-
technique we use to accommodate associated types when figuring out
28-
whether types are equal.
29-
- [Region constraints](./regions.html), which are accumulated
30-
during trait solving but mostly ignored. This means that trait
31-
solving effectively ignores the precise regions involved, always –
32-
but we still remember the constraints on them so that those
33-
constraints can be checked by thet type checker.
3443

35-
Note: this is not a complete list of topics. See the sidebar for more.
44+
> This is not a complete list of topics. See the sidebar for more.
3645
46+
## Ongoing work
3747
The design of the new-style trait solving currently happens in two places:
38-
* The [chalk][chalk] repository is where we experiment with new ideas and
39-
designs for the trait system. It basically consists of a unit testing framework
40-
for the correctness and feasibility of the logical rules defining the new-style
41-
trait system. It also provides the [`chalk_engine`][chalk_engine] crate, which
42-
defines the new-style trait solver used both in the unit testing framework and
43-
in rustc.
44-
* Once we are happy with the logical rules, we proceed to implementing them in
45-
rustc. This mainly happens in [`librustc_traits`][librustc_traits].
48+
49+
**chalk**. The [chalk][chalk] repository is where we experiment with new ideas
50+
and designs for the trait system. It primarily consists of two parts:
51+
* a unit testing framework
52+
for the correctness and feasibility of the logical rules defining the
53+
new-style trait system.
54+
* the [`chalk_engine`][chalk_engine] crate, which
55+
defines the new-style trait solver used both in the unit testing framework
56+
and in rustc.
57+
58+
**rustc**. Once we are happy with the logical rules, we proceed to
59+
implementing them in rustc. This mainly happens in
60+
[`librustc_traits`][librustc_traits].
4661

4762
[chalk]: https://github.com/rust-lang-nursery/chalk
4863
[chalk_engine]: https://github.com/rust-lang-nursery/chalk/tree/master/chalk-engine

src/traits/regions.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
# Region constraints
22

3-
*to be written*
3+
*To be written.*
4+
5+
Chalk does not have the concept of region constraints, and as of this
6+
writing, work on rustc was not far enough to worry about them.
7+
8+
In the meantime, you can read about region constraints in the
9+
[type inference](../type-inference.html#region-constraints) section.

0 commit comments

Comments
 (0)