diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 091860e9a..b27114f1e 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -38,6 +38,7 @@ - [The HIR (High-level IR)](./hir.md) - [Lowering AST to HIR](./lowering.md) - [The `ty` module: representing types](./ty.md) +- [Kinds](./kinds.md) - [Type inference](./type-inference.md) - [Trait solving (old-style)](./traits/resolution.md) - [Higher-ranked trait bounds](./traits/hrtb.md) diff --git a/src/kinds.md b/src/kinds.md new file mode 100644 index 000000000..d5e218c31 --- /dev/null +++ b/src/kinds.md @@ -0,0 +1,49 @@ +# Kinds +A `ty::subst::Kind<'tcx>` represents some entity in the type system: a type +(`Ty<'tcx>`), lifetime (`ty::Region<'tcx>`) or constant (`ty::Const<'tcx>`). +`Kind` is used to perform substitutions of generic parameters for concrete +arguments, such as when calling a function with generic parameters explicitly +with type arguments. Substitutions are represented using the +[`Subst` type](#subst) as described below. + +## `Subst` +`ty::subst::Subst<'tcx>` is intuitively simply a slice of `Kind<'tcx>`s, +acting as an ordered list of substitutions from generic parameters to +concrete arguments (such as types, lifetimes and consts). + +For example, given a `HashMap` with two type parameters, `K` and `V`, an +instantiation of the parameters, for example `HashMap`, would be +represented by the substitution `&'tcx [tcx.types.i32, tcx.types.u32]`. + +`Subst` provides various convenience methods to instantiant substitutions +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,ignore +// 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() +} +``` diff --git a/src/ty.md b/src/ty.md index fea9afbeb..d9979bc0b 100644 --- a/src/ty.md +++ b/src/ty.md @@ -141,8 +141,8 @@ In addition to types, there are a number of other arena-allocated data structures that you can allocate, and which are found in this module. Here are a few examples: -- `Substs`, allocated with `mk_substs` – this will intern a slice of types, - often used to specify the values to be substituted for generics +- [`Substs`][subst], allocated with `mk_substs` – this will intern a slice of + types, often used to specify the values to be substituted for generics (e.g. `HashMap` would be represented as a slice `&'tcx [tcx.types.i32, tcx.types.u32]`). - `TraitRef`, typically passed by value – a **trait reference** @@ -153,6 +153,8 @@ module. Here are a few examples: - `Predicate` defines something the trait system has to prove (see `traits` module). +[subst]: ./kinds.html#subst + ### Import conventions Although there is no hard and fast rule, the `ty` module tends to be used like