Skip to content

Commit 2ed15c2

Browse files
authored
Merge pull request #85 from mark-i-m/typeck
Add the contents of the typeck READMEs
2 parents ed04741 + e745674 commit 2ed15c2

7 files changed

+467
-1
lines changed

src/SUMMARY.md

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
- [The SLG solver](./traits-slg.md)
3636
- [Bibliography](./traits-bibliography.md)
3737
- [Type checking](./type-checking.md)
38+
- [Method Lookup](./method-lookup.md)
39+
- [Variance](./variance.md)
3840
- [The MIR (Mid-level IR)](./mir.md)
3941
- [MIR construction](./mir-construction.md)
4042
- [MIR visitor and traversal](./mir-visitor.md)

src/appendix-background.md

+3
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ cycle.
9191
Check out the subtyping chapter from the
9292
[Rust Nomicon](https://doc.rust-lang.org/nomicon/subtyping.html).
9393

94+
See the [variance](./variance.html) chapter of this guide for more info on how
95+
the type checker handles variance.
96+
9497
<a name=free-vs-bound>
9598

9699
## What is a "free region" or a "free variable"? What about "bound region"?

src/appendix-code-index.md

+2
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ Item | Kind | Short description | Chapter |
1414
`Session` | struct | The data associated with a compilation session | [the Parser], [The Rustc Driver] | [src/librustc/session/mod.html](https://github.com/rust-lang/rust/blob/master/src/librustc/session/mod.rs)
1515
`StringReader` | struct | This is the lexer used during parsing. It consumes characters from the raw source code being compiled and produces a series of tokens for use by the rest of the parser | [The parser] | [src/libsyntax/parse/lexer/mod.rs](https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/lexer/mod.rs)
1616
`TraitDef` | struct | This struct contains a trait's definition with type information | [The `ty` modules] | [src/librustc/ty/trait_def.rs](https://github.com/rust-lang/rust/blob/master/src/librustc/ty/trait_def.rs)
17+
`Ty<'tcx>` | struct | This is the internal representation of a type used for type checking | [Type checking] | [src/librustc/ty/mod.rs](https://github.com/rust-lang/rust/blob/master/src/librustc/ty/mod.rs)
1718
`TyCtxt<'cx, 'tcx, 'tcx>` | type | The "typing context". This is the central data structure in the compiler. It is the context that you use to perform all manner of queries. | [The `ty` modules] | [src/librustc/ty/context.rs](https://github.com/rust-lang/rust/blob/master/src/librustc/ty/context.rs)
1819

1920
[The HIR]: hir.html
2021
[The parser]: the-parser.html
2122
[The Rustc Driver]: rustc-driver.html
23+
[Type checking]: type-checking.html
2224
[The `ty` modules]: ty.html

src/appendix-glossary.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ token | the smallest unit of parsing. Tokens are produced aft
5656
trans | the code to translate MIR into LLVM IR.
5757
trait reference | a trait and values for its type parameters ([see more](ty.html)).
5858
ty | the internal representation of a type ([see more](ty.html)).
59-
variance | variance determines how changes to a generic type/lifetime parameter affect subtyping; for example, if `T` is a subtype of `U`, then `Vec<T>` is a subtype `Vec<U>` because `Vec` is *covariant* in its generic parameter. See [the background chapter for more](./appendix-background.html#variance).
59+
UFCS | Universal Function Call Syntax. An unambiguous syntax for calling a method ([see more](type-checking.html)).
60+
variance | variance determines how changes to a generic type/lifetime parameter affect subtyping; for example, if `T` is a subtype of `U`, then `Vec<T>` is a subtype `Vec<U>` because `Vec` is *covariant* in its generic parameter. See [the background chapter](./appendix-background.html#variance) for a more general explanation. See the [variance chapter](./variance.html) for an explanation of how type checking handles variance.
6061

6162
[LLVM]: https://llvm.org/
6263
[lto]: https://llvm.org/docs/LinkTimeOptimization.html

src/method-lookup.md

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Method lookup
2+
3+
Method lookup can be rather complex due to the interaction of a number
4+
of factors, such as self types, autoderef, trait lookup, etc. This
5+
file provides an overview of the process. More detailed notes are in
6+
the code itself, naturally.
7+
8+
One way to think of method lookup is that we convert an expression of
9+
the form:
10+
11+
```rust
12+
receiver.method(...)
13+
```
14+
15+
into a more explicit UFCS form:
16+
17+
```rust
18+
Trait::method(ADJ(receiver), ...) // for a trait call
19+
ReceiverType::method(ADJ(receiver), ...) // for an inherent method call
20+
```
21+
22+
Here `ADJ` is some kind of adjustment, which is typically a series of
23+
autoderefs and then possibly an autoref (e.g., `&**receiver`). However
24+
we sometimes do other adjustments and coercions along the way, in
25+
particular unsizing (e.g., converting from `[T; n]` to `[T]`).
26+
27+
Method lookup is divided into two major phases:
28+
29+
1. Probing ([`probe.rs`][probe]). The probe phase is when we decide what method
30+
to call and how to adjust the receiver.
31+
2. Confirmation ([`confirm.rs`][confirm]). The confirmation phase "applies"
32+
this selection, updating the side-tables, unifying type variables, and
33+
otherwise doing side-effectful things.
34+
35+
One reason for this division is to be more amenable to caching. The
36+
probe phase produces a "pick" (`probe::Pick`), which is designed to be
37+
cacheable across method-call sites. Therefore, it does not include
38+
inference variables or other information.
39+
40+
[probe]: https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/check/method/probe.rs
41+
[confirm]: https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/check/method/confirm.rs
42+
43+
## The Probe phase
44+
45+
### Steps
46+
47+
The first thing that the probe phase does is to create a series of
48+
*steps*. This is done by progressively dereferencing the receiver type
49+
until it cannot be deref'd anymore, as well as applying an optional
50+
"unsize" step. So if the receiver has type `Rc<Box<[T; 3]>>`, this
51+
might yield:
52+
53+
```rust
54+
Rc<Box<[T; 3]>>
55+
Box<[T; 3]>
56+
[T; 3]
57+
[T]
58+
```
59+
60+
### Candidate assembly
61+
62+
We then search along those steps to create a list of *candidates*. A
63+
`Candidate` is a method item that might plausibly be the method being
64+
invoked. For each candidate, we'll derive a "transformed self type"
65+
that takes into account explicit self.
66+
67+
Candidates are grouped into two kinds, inherent and extension.
68+
69+
**Inherent candidates** are those that are derived from the
70+
type of the receiver itself. So, if you have a receiver of some
71+
nominal type `Foo` (e.g., a struct), any methods defined within an
72+
impl like `impl Foo` are inherent methods. Nothing needs to be
73+
imported to use an inherent method, they are associated with the type
74+
itself (note that inherent impls can only be defined in the same
75+
module as the type itself).
76+
77+
FIXME: Inherent candidates are not always derived from impls. If you
78+
have a trait object, such as a value of type `Box<ToString>`, then the
79+
trait methods (`to_string()`, in this case) are inherently associated
80+
with it. Another case is type parameters, in which case the methods of
81+
their bounds are inherent. However, this part of the rules is subject
82+
to change: when DST's "impl Trait for Trait" is complete, trait object
83+
dispatch could be subsumed into trait matching, and the type parameter
84+
behavior should be reconsidered in light of where clauses.
85+
86+
TODO: Is this FIXME still accurate?
87+
88+
**Extension candidates** are derived from imported traits. If I have
89+
the trait `ToString` imported, and I call `to_string()` on a value of
90+
type `T`, then we will go off to find out whether there is an impl of
91+
`ToString` for `T`. These kinds of method calls are called "extension
92+
methods". They can be defined in any module, not only the one that
93+
defined `T`. Furthermore, you must import the trait to call such a
94+
method.
95+
96+
So, let's continue our example. Imagine that we were calling a method
97+
`foo` with the receiver `Rc<Box<[T; 3]>>` and there is a trait `Foo`
98+
that defines it with `&self` for the type `Rc<U>` as well as a method
99+
on the type `Box` that defines `Foo` but with `&mut self`. Then we
100+
might have two candidates:
101+
102+
&Rc<Box<[T; 3]>> from the impl of `Foo` for `Rc<U>` where `U=Box<T; 3]>
103+
&mut Box<[T; 3]>> from the inherent impl on `Box<U>` where `U=[T; 3]`
104+
105+
### Candidate search
106+
107+
Finally, to actually pick the method, we will search down the steps,
108+
trying to match the receiver type against the candidate types. At
109+
each step, we also consider an auto-ref and auto-mut-ref to see whether
110+
that makes any of the candidates match. We pick the first step where
111+
we find a match.
112+
113+
In the case of our example, the first step is `Rc<Box<[T; 3]>>`,
114+
which does not itself match any candidate. But when we autoref it, we
115+
get the type `&Rc<Box<[T; 3]>>` which does match. We would then
116+
recursively consider all where-clauses that appear on the impl: if
117+
those match (or we cannot rule out that they do), then this is the
118+
method we would pick. Otherwise, we would continue down the series of
119+
steps.

src/type-checking.md

+43
Original file line numberDiff line numberDiff line change
@@ -1 +1,44 @@
11
# Type checking
2+
3+
The [`rustc_typeck`][typeck] crate contains the source for "type collection"
4+
and "type checking", as well as a few other bits of related functionality. (It
5+
draws heavily on the [type inference] and [trait solving].)
6+
7+
[typeck]: https://github.com/rust-lang/rust/tree/master/src/librustc_typeck
8+
[type inference]: type-inference.html
9+
[trait solving]: trait-resolution.html
10+
11+
## Type collection
12+
13+
Type "collection" is the process of converting the types found in the HIR
14+
(`hir::Ty`), which represent the syntactic things that the user wrote, into the
15+
**internal representation** used by the compiler (`Ty<'tcx>`) -- we also do
16+
similar conversions for where-clauses and other bits of the function signature.
17+
18+
To try and get a sense for the difference, consider this function:
19+
20+
```rust
21+
struct Foo { }
22+
fn foo(x: Foo, y: self::Foo) { .. }
23+
// ^^^ ^^^^^^^^^
24+
```
25+
26+
Those two parameters `x` and `y` each have the same type: but they will have
27+
distinct `hir::Ty` nodes. Those nodes will have different spans, and of course
28+
they encode the path somewhat differently. But once they are "collected" into
29+
`Ty<'tcx>` nodes, they will be represented by the exact same internal type.
30+
31+
Collection is defined as a bundle of [queries] for computing information about
32+
the various functions, traits, and other items in the crate being compiled.
33+
Note that each of these queries is concerned with *interprocedural* things --
34+
for example, for a function definition, collection will figure out the type and
35+
signature of the function, but it will not visit the *body* of the function in
36+
any way, nor examine type annotations on local variables (that's the job of
37+
type *checking*).
38+
39+
For more details, see the [`collect`][collect] module.
40+
41+
[queries]: query.html
42+
[collect]: https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/collect.rs
43+
44+
**TODO**: actually talk about type checking...

0 commit comments

Comments
 (0)