Skip to content

Add a (short) chapter on Kind #282

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
49 changes: 49 additions & 0 deletions src/kinds.md
Original file line number Diff line number Diff line change
@@ -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<K, V>` with two type parameters, `K` and `V`, an
instantiation of the parameters, for example `HashMap<i32, u32>`, 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lowest 2 bits are the "tag", a (bit) "mask" is what you use to "mask out" bits other than the ones you're interested in (e.g. let (tag, ptr) = (x & 0b11, x & !0b11); uses 0b11 to get the lowest 2 bits and !0b11 for everything else).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #287 to fix.

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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need imports here in order to make the example compile and pass travis

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make this example compile and pass without importing the whole compiler? Usually, I just add rust,ignore...

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()
}
```
6 changes: 4 additions & 2 deletions src/ty.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<i32, u32>` would be represented as a slice
`&'tcx [tcx.types.i32, tcx.types.u32]`).
- `TraitRef`, typically passed by value – a **trait reference**
Expand All @@ -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
Expand Down