mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
start writing some typeck docs (incomplete)
This commit is contained in:
parent
032fdef3be
commit
38813cf40d
48
src/librustc_typeck/README.md
Normal file
48
src/librustc_typeck/README.md
Normal file
@ -0,0 +1,48 @@
|
||||
NB: This crate is part of the Rust compiler. For an overview of the
|
||||
compiler as a whole, see
|
||||
[the README.md file found in `librustc`](../librustc/README.md).
|
||||
|
||||
The `rustc_typeck` crate contains the source for "type collection" and
|
||||
"type checking", as well as a few other bits of related functionality.
|
||||
(It draws heavily on the [type inferencing][infer] and
|
||||
[trait solving][traits] code found in librustc.)
|
||||
|
||||
[infer]: ../librustc/infer/README.md
|
||||
[traits]: ../librustc/traits/README.md
|
||||
|
||||
## Type collection
|
||||
|
||||
Type "collection" is the process of convering the types found in the
|
||||
HIR (`hir::Ty`), which represent the syntactic things that the user
|
||||
wrote, into the **internal representation** used by the compiler
|
||||
(`Ty<'tcx>`) -- we also do similar conversions for where-clauses and
|
||||
other bits of the function signature.
|
||||
|
||||
To try and get a sense for the difference, consider this function:
|
||||
|
||||
```rust
|
||||
struct Foo { }
|
||||
fn foo(x: Foo, y: self::Foo) { .. }
|
||||
// ^^^ ^^^^^^^^^
|
||||
```
|
||||
|
||||
Those two parameters `x` and `y` each have the same type: but they
|
||||
will have distinct `hir::Ty` nodes. Those nodes will have different
|
||||
spans, and of course they encode the path somewhat differently. But
|
||||
once they are "collected" into `Ty<'tcx>` nodes, they will be
|
||||
represented by the exact same internal type.
|
||||
|
||||
Collection is defined as a bundle of queries (e.g., `type_of`) for
|
||||
computing information about the various functions, traits, and other
|
||||
items in the crate being compiled. Note that each of these queries is
|
||||
concerned with *interprocedural* things -- for example, for a function
|
||||
definition, collection will figure out the type and signature of the
|
||||
function, but it will not visit the *body* of the function in any way,
|
||||
nor examine type annotations on local variables (that's the job of
|
||||
type *checking*).
|
||||
|
||||
For more details, see the `collect` module.
|
||||
|
||||
## Type checking
|
||||
|
||||
TODO
|
@ -8,50 +8,21 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*
|
||||
|
||||
# Collect phase
|
||||
|
||||
The collect phase of type check has the job of visiting all items,
|
||||
determining their type, and writing that type into the `tcx.types`
|
||||
table. Despite its name, this table does not really operate as a
|
||||
*cache*, at least not for the types of items defined within the
|
||||
current crate: we assume that after the collect phase, the types of
|
||||
all local items will be present in the table.
|
||||
|
||||
Unlike most of the types that are present in Rust, the types computed
|
||||
for each item are in fact type schemes. This means that they are
|
||||
generic types that may have type parameters. TypeSchemes are
|
||||
represented by a pair of `Generics` and `Ty`. Type
|
||||
parameters themselves are represented as `ty_param()` instances.
|
||||
|
||||
The phasing of type conversion is somewhat complicated. There is no
|
||||
clear set of phases we can enforce (e.g., converting traits first,
|
||||
then types, or something like that) because the user can introduce
|
||||
arbitrary interdependencies. So instead we generally convert things
|
||||
lazilly and on demand, and include logic that checks for cycles.
|
||||
Demand is driven by calls to `AstConv::get_item_type_scheme` or
|
||||
`AstConv::trait_def`.
|
||||
|
||||
Currently, we "convert" types and traits in two phases (note that
|
||||
conversion only affects the types of items / enum variants / methods;
|
||||
it does not e.g. compute the types of individual expressions):
|
||||
|
||||
0. Intrinsics
|
||||
1. Trait/Type definitions
|
||||
|
||||
Conversion itself is done by simply walking each of the items in turn
|
||||
and invoking an appropriate function (e.g., `trait_def_of_item` or
|
||||
`convert_item`). However, it is possible that while converting an
|
||||
item, we may need to compute the *type scheme* or *trait definition*
|
||||
for other items.
|
||||
|
||||
There are some shortcomings in this design:
|
||||
- Because the item generics include defaults, cycles through type
|
||||
parameter defaults are illegal even if those defaults are never
|
||||
employed. This is not necessarily a bug.
|
||||
|
||||
*/
|
||||
//! "Collection" is the process of determining the type and other external
|
||||
//! details of each item in Rust. Collection is specifically concerned
|
||||
//! with *interprocedural* things -- for example, for a function
|
||||
//! definition, collection will figure out the type and signature of the
|
||||
//! function, but it will not visit the *body* of the function in any way,
|
||||
//! nor examine type annotations on local variables (that's the job of
|
||||
//! type *checking*).
|
||||
//!
|
||||
//! Collecting is ultimately defined by a bundle of queries that
|
||||
//! inquire after various facts about the items in the crate (e.g.,
|
||||
//! `type_of`, `generics_of`, `predicates_of`, etc). See the `provide` function
|
||||
//! for the full set.
|
||||
//!
|
||||
//! At present, however, we do run collection across all items in the
|
||||
//! crate as a kind of pass. This should eventually be factored away.
|
||||
|
||||
use astconv::{AstConv, Bounds};
|
||||
use lint;
|
||||
|
Loading…
Reference in New Issue
Block a user