Add more information and an example to Kind chapter

This commit is contained in:
varkor 2019-02-16 14:38:15 +00:00 committed by Who? Me?!
parent 7cc2afab20
commit 99d47b84c6
1 changed files with 40 additions and 22 deletions

View File

@ -1,31 +1,49 @@
# Kinds # Kinds
A `ty::subst::Kind<'tcx>` represents some entity in the type system: currently A `ty::subst::Kind<'tcx>` represents some entity in the type system: a type
either a type (`Ty<'tcx>`) or a lifetime (`ty::Region<'tcx>`), though in the (`Ty<'tcx>`), lifetime (`ty::Region<'tcx>`) or constant (`ty::Const<'tcx>`).
future this will also include constants (`ty::Const<'tcx>`) to facilitate the `Kind` is used to perform substitutions of generic parameters for concrete
use of const generics. `Kind` is used for type and lifetime substitution (from arguments, such as when calling a function with generic parameters explicitly
abstract type and lifetime parameters to concrete types and lifetimes). with type arguments. Substitutions are represented using the
[`Subst` type](#subst) as described below.
## `UnpackedKind`
As `Kind` itself is not type-safe (see [`Kind`](#kind)), the `UnpackedKind` enum
provides a more convenient and safe interface for dealing with kinds. To
convert from an `UnpackedKind` to a `Kind`, you can call `Kind::from` (or
`.into`). It should not be necessary to convert a `Kind` to an `UnpackedKind`:
instead, you should prefer to deal with `UnpackedKind`, converting it only when
passing it to `Subst` methods.
## `Kind`
The actual `Kind` struct is optimised for space, storing the type or lifetime
as an interned pointer containing a mask identifying its kind (in the lowest
2 bits).
## `Subst` ## `Subst`
`ty::subst::Subst<'tcx>` is simply defined as a slice of `Kind<'tcx>`s `ty::subst::Subst<'tcx>` is intuitively simply a slice of `Kind<'tcx>`s,
and acts as an ordered list of substitutions from kind parameters (i.e. acting as an ordered list of substitutions from generic parameters to
type and lifetime parameters) to kinds. concrete arguments (such as types, lifetimes and consts).
For example, given a `HashMap<K, V>` with two type parameters, `K` and `V`, an For example, given a `HashMap<K, V>` with two type parameters, `K` and `V`, an
instantiation of the parameters, for example `HashMap<i32, u32>`, would be instantiation of the parameters, for example `HashMap<i32, u32>`, would be
represented by the substitution `&'tcx [tcx.types.i32, tcx.types.u32]`. represented by the substitution `&'tcx [tcx.types.i32, tcx.types.u32]`.
`Subst` provides various convenience methods to instantiant substitutions `Subst` provides various convenience methods to instantiant substitutions
given item definitions. given item definitions, which should generally be used rather than explicitly
constructing such substitution slices.
## `Kind`
The actual `Kind` struct is optimised for space, storing the type, lifetime or
const as an interned pointer containing a mask identifying its kind (in the
lowest 2 bits). Unless you are working with the `Subst` implementation
specifically, you should generally not have to deal with `Kind` and instead
make use of the safe [`UnpackedKind`](#unpackedkind) abstraction.
## `UnpackedKind`
As `Kind` itself is not type-safe, the `UnpackedKind` enum provides a more
convenient and safe interface for dealing with kinds. An `UnpackedKind` can
be converted to a raw `Kind` using `Kind::from()` (or simply `.into()` when
the context is clear). As mentioned earlier, substition lists store raw
`Kind`s, so before dealing with them, it is preferable to convert them to
`UnpackedKind`s first. This is done by calling the `.unpack()` method.
```rust
// An example of unpacking and packing a kind.
fn deal_with_kind<'tcx>(kind: Kind<'tcx>) -> Kind<'tcx> {
// Unpack a raw `Kind` to deal with it safely.
let new_kind: UnpackedKind<'tcx> = match kind.unpack() {
UnpackedKind::Type(ty) => { /* ... */ }
UnpackedKind::Lifetime(lt) => { /* ... */ }
UnpackedKind::Const(ct) => { /* ... */ }
};
// Pack the `UnpackedKind` to store it in a substitution list.
new_kind.into()
}
```