update internal terminology: Substs -> GenericArgs
This commit is contained in:
parent
4285421cd2
commit
384ac6ebbb
|
|
@ -23,7 +23,7 @@ Term | Meaning
|
|||
<span id="double-ptr">double pointer</span> | A pointer with additional metadata. See "fat pointer" for more.
|
||||
<span id="drop-glue">drop glue</span> | (internal) compiler-generated instructions that handle calling the destructors (`Drop`) for data types.
|
||||
<span id="dst">DST</span> | Short for Dynamically-Sized Type, this is a type for which the compiler cannot statically know the size in memory (e.g. `str` or `[u8]`). Such types don't implement `Sized` and cannot be allocated on the stack. They can only occur as the last field in a struct. They can only be used behind a pointer (e.g. `&str` or `&[u8]`).
|
||||
<span id="ebl">early-bound lifetime</span> | A lifetime region that is substituted at its definition site. Bound in an item's `Generics` and substituted using a `Substs`. Contrast with **late-bound lifetime**. ([see more](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.RegionKind.html#bound-regions))
|
||||
<span id="ebl">early-bound lifetime</span> | A lifetime region that is substituted at its definition site. Bound in an item's `Generics` and substituted using a `GenericArgs`. Contrast with **late-bound lifetime**. ([see more](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.RegionKind.html#bound-regions))
|
||||
<span id="empty-type">empty type</span> | see "uninhabited type".
|
||||
<span id="fat-ptr">fat pointer</span> | A two word value carrying the address of some value, along with some further information necessary to put the value to use. Rust includes two kinds of "fat pointers": references to slices, and trait objects. A reference to a slice carries the starting address of the slice and its length. A trait object carries a value's address and a pointer to the trait's implementation appropriate to that value. "Fat pointers" are also known as "wide pointers", and "double pointers".
|
||||
<span id="free-var">free variable</span> | A "free variable" is one that is not bound within an expression or term; see [the background chapter for more](./background.md#free-vs-bound)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Understanding this page likely requires a rudimentary understanding of higher ranked
|
||||
trait bounds/`for<'a>`and also what types such as `dyn for<'a> Trait<'a>` and
|
||||
`for<'a> fn(&'a u32)` mean. Reading [the nomincon chapter](https://doc.rust-lang.org/nomicon/hrtb.html)
|
||||
`for<'a> fn(&'a u32)` mean. Reading [the nomincon chapter](https://doc.rust-lang.org/nomicon/hrtb.html)
|
||||
on HRTB may be useful for understanding this syntax. The meaning of `for<'a> fn(&'a u32)`
|
||||
is incredibly similar to the meaning of `T: for<'a> Trait<'a>`.
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ fn foo<'a>(_: &'a u32) {}
|
|||
|
||||
fn main() {
|
||||
let b = foo;
|
||||
// ^ `b` has type `FnDef(foo, [])` (no substs because `'a` is late bound)
|
||||
// ^ `b` has type `FnDef(foo, [])` (no args because `'a` is late bound)
|
||||
assert!(std::mem::size_of_val(&b) == 0);
|
||||
}
|
||||
```
|
||||
|
|
@ -38,7 +38,7 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
Because late bound parameters are not part of the `FnDef`'s substs this allows us to prove trait
|
||||
Because late bound parameters are not part of the `FnDef`'s args this allows us to prove trait
|
||||
bounds such as `F: for<'a> Fn(&'a u32)` where `F` is `foo`'s `FnDef`. e.g.
|
||||
```rust
|
||||
fn foo_early<'a, T: Trait<'a>>(_: &'a u32, _: T) {}
|
||||
|
|
@ -161,7 +161,7 @@ this is simpler than the rules for checking impl headers constrain all the param
|
|||
We only have to ensure that all late bound parameters appear at least once in the function argument
|
||||
types outside of an alias (e.g. an associated type).
|
||||
|
||||
The requirement that they not indirectly be in the substs of an alias for it to count is the
|
||||
The requirement that they not indirectly be in the args of an alias for it to count is the
|
||||
same as why the follow code is forbidden:
|
||||
```rust
|
||||
impl<T: Trait> OtherTrait for <T as Trait>::Assoc { type Assoc = T }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Generics and substitutions
|
||||
# Generics and GenericArgs
|
||||
|
||||
Given a generic type `MyType<A, B, …>`, we may want to swap out the generics `A, B, …` for some
|
||||
other types (possibly other generics or concrete types). We do this a lot while doing type
|
||||
|
|
@ -6,19 +6,20 @@ inference, type checking, and trait solving. Conceptually, during these routines
|
|||
that one type is equal to another type and want to swap one out for the other and then swap that out
|
||||
for another type and so on until we eventually get some concrete types (or an error).
|
||||
|
||||
In rustc this is done using [SubstsRef] (“substs” = “substitutions”).
|
||||
Conceptually, you can think of `SubstsRef` as a list of types that are to be substituted for the
|
||||
generic type parameters of the ADT.
|
||||
In rustc this is done using [GenericArgsRef].
|
||||
Conceptually, you can think of `GenericArgsRef` as a list of types that are to be substituted for
|
||||
the generic type parameters of the ADT.
|
||||
|
||||
`SubstsRef` is a type alias of `&'tcx List<GenericArg<'tcx>>` (see [`List` rustdocs][list]).
|
||||
`GenericArgsRef` is a type alias of `&'tcx List<GenericArg<'tcx>>` (see [`List` rustdocs][list]).
|
||||
[`GenericArg`] is essentially a space-efficient wrapper around [`GenericArgKind`], which is an enum
|
||||
indicating what kind of generic the type parameter is (type, lifetime, or const). Thus, `SubstsRef`
|
||||
is conceptually like a `&'tcx [GenericArgKind<'tcx>]` slice (but it is actually a `List`).
|
||||
indicating what kind of generic the type parameter is (type, lifetime, or const).
|
||||
Thus, `GenericArgsRef` is conceptually like a `&'tcx [GenericArgKind<'tcx>]` slice (but it is
|
||||
actually a `List`).
|
||||
|
||||
[list]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.List.html
|
||||
[`GenericArg`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/subst/struct.GenericArg.html
|
||||
[`GenericArgKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/subst/enum.GenericArgKind.html
|
||||
[SubstsRef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/subst/type.SubstsRef.html
|
||||
[`GenericArg`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.GenericArg.html
|
||||
[`GenericArgKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.GenericArgKind.html
|
||||
[GenericArgsRef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.GenericArgsRef.html
|
||||
|
||||
So why do we use this `List` type instead of making it really a slice? It has the length "inline",
|
||||
so `&List` is only 32 bits. As a consequence, it cannot be "subsliced" (that only works if the
|
||||
|
|
@ -36,10 +37,10 @@ struct MyStruct<T>
|
|||
|
||||
- There would be an `AdtDef` (and corresponding `DefId`) for `MyStruct`.
|
||||
- There would be a `TyKind::Param` (and corresponding `DefId`) for `T` (more later).
|
||||
- There would be a `SubstsRef` containing the list `[GenericArgKind::Type(Ty(T))]`
|
||||
- There would be a `GenericArgsRef` containing the list `[GenericArgKind::Type(Ty(T))]`
|
||||
- The `Ty(T)` here is my shorthand for entire other `ty::Ty` that has `TyKind::Param`, which we
|
||||
mentioned in the previous point.
|
||||
- This is one `TyKind::Adt` containing the `AdtDef` of `MyStruct` with the `SubstsRef` above.
|
||||
- This is one `TyKind::Adt` containing the `AdtDef` of `MyStruct` with the `GenericArgsRef` above.
|
||||
|
||||
Finally, we will quickly mention the
|
||||
[`Generics`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Generics.html) type. It
|
||||
|
|
@ -113,33 +114,32 @@ This example has a few different substitutions:
|
|||
|
||||
Let’s look a bit more closely at that last substitution to see why we use indexes. If we want to
|
||||
find the type of `foo.x`, we can get generic type of `x`, which is `Vec<Param(0)>`. Now we can take
|
||||
the index `0` and use it to find the right type substitution: looking at `Foo`'s `SubstsRef`, we
|
||||
have the list `[u32, f32]` , since we want to replace index `0`, we take the 0-th index of this
|
||||
the index `0` and use it to find the right type substitution: looking at `Foo`'s `GenericArgsRef`,
|
||||
we have the list `[u32, f32]` , since we want to replace index `0`, we take the 0-th index of this
|
||||
list, which is `u32`. Voila!
|
||||
|
||||
You may have a couple of followup questions…
|
||||
|
||||
**`type_of`** How do we get the “generic type of `x`"? You can get the type of pretty much anything
|
||||
**`type_of`** How do we get the "generic type of `x`"? You can get the type of pretty much anything
|
||||
with the `tcx.type_of(def_id)` query. In this case, we would pass the `DefId` of the field `x`.
|
||||
The `type_of` query always returns the definition with the generics that are in scope of the
|
||||
definition. For example, `tcx.type_of(def_id_of_my_struct)` would return the “self-view” of
|
||||
`MyStruct`: `Adt(Foo, &[Param(0), Param(1)])`.
|
||||
|
||||
**`subst`** How do we actually do the substitutions? There is a function for that too! You use
|
||||
[`subst`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/subst/struct.EarlyBinder.html#method.subst) to
|
||||
replace a `SubstsRef` with another list of types.
|
||||
**`instantiate`** How do we actually do the substitutions? There is a function for that too! You
|
||||
use [`instantiate`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/
|
||||
generic_args/struct.EarlyBinder.html#method.instantiate) to replace a `GenericArgsRef` with
|
||||
another list of types.
|
||||
|
||||
[Here is an example of actually using `subst` in the compiler][substex]. The exact details are not
|
||||
too important, but in this piece of code, we happen to be converting from the `rustc_hir::Ty` to
|
||||
a real `ty::Ty`. You can see that we first get some substitutions (`substs`). Then we call
|
||||
`type_of` to get a type and call `ty.subst(substs)` to get a new version of `ty` with
|
||||
the substitutions made.
|
||||
[Here is an example of actually using `instantiate` in the compiler][instantiatex].
|
||||
The exact details are not too important, but in this piece of code, we happen to be
|
||||
converting from the `rustc_hir::Ty` to a real `ty::Ty`. You can see that we first get some args
|
||||
(`args`). Then we call `type_of` to get a type and call `ty.instantiate(tcx, args)` to get a new
|
||||
version of `ty` with the args made.
|
||||
|
||||
[substex]: https://github.com/rust-lang/rust/blob/0940040c0486a536be4f8685c7dd9a078f9e87c2/compiler/rustc_hir_analysis/src/astconv/mod.rs#L1231-L1242
|
||||
[instantiatex]: https://github.com/rust-lang/rust/blob/master/compiler/rustc_hir_analysis/src/astconv/mod.rs#L905-L927
|
||||
|
||||
**Note on indices:** It is possible for the indices in `Param` to not match with what we expect. For
|
||||
example, the index could be out of bounds or it could be the index of a lifetime when we were
|
||||
expecting a type. These sorts of errors would be caught earlier in the compiler when translating
|
||||
from a `rustc_hir::Ty` to a `ty::Ty`. If they occur later, that is a compiler bug.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -40,16 +40,16 @@ to that buffer is freed and our `'tcx` references would be invalid.
|
|||
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`][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]`).
|
||||
- [`GenericArgs`][subst], allocated with `mk_args` – this will intern a slice of types, often used
|
||||
to specify the values to be substituted for generics args(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** consists of a reference to a trait
|
||||
along with its various type parameters (including `Self`), like `i32: Display` (here, the def-id
|
||||
would reference the `Display` trait, and the substs would contain `i32`). Note that `def-id` is
|
||||
would reference the `Display` trait, and the args would contain `i32`). Note that `def-id` is
|
||||
defined and discussed in depth in the `AdtDef and DefId` section.
|
||||
- [`Predicate`] defines something the trait system has to prove (see `traits` module).
|
||||
|
||||
[subst]: ./generic_arguments.html#subst
|
||||
[`GenericArgs`]: ./generic_arguments.html#GenericArgs
|
||||
[`TraitRef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TraitRef.html
|
||||
[`Predicate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Predicate.html
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ We record `lifetime_mapping`s for the opaque type, described below.
|
|||
lifetimes into new lifetime parameters local to the opaque. The main
|
||||
reason we do this is because RPITs need to be able to "reify"[^1] any
|
||||
captured late-bound arguments, or make them into early-bound ones. This
|
||||
is so they can be used as substs for the opaque, and later to
|
||||
is so they can be used as generic args for the opaque, and later to
|
||||
instantiate hidden types. Since we don't know which lifetimes are early-
|
||||
or late-bound during AST lowering, we just do this for all lifetimes.
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) ->
|
|||
| rbv::ResolvedArg::Free(_, node_id),
|
||||
) = def
|
||||
{
|
||||
if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() {
|
||||
if let Some(lt) = cx.args.get(&node_id).and_then(|p| p.as_lt()).cloned() {
|
||||
return lt;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
20
src/ty.md
20
src/ty.md
|
|
@ -200,11 +200,11 @@ the function calls if one is available in some place (like during type checking)
|
|||
If no inference context is available at all, then one can be created as described in
|
||||
[type-inference]. But this is only useful when the involved types (for example, if
|
||||
they came from a query like `tcx.type_of()`) are actually substituted with fresh
|
||||
inference variables using [`fresh_substs_for_item`]. This can be used to answer questions
|
||||
inference variables using [`fresh_args_for_item`]. This can be used to answer questions
|
||||
like "can `Vec<T>` for any `T` be unified with `Vec<u32>`?".
|
||||
|
||||
[type-inference]: ./type-inference.md#creating-an-inference-context
|
||||
[`fresh_substs_for_item`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_infer/infer/struct.InferCtxt.html#method.fresh_substs_for_item
|
||||
[`fresh_args_for_item`]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_infer/infer/struct.InferCtxt.html#method.fresh_args_for_item
|
||||
|
||||
## `ty::TyKind` Variants
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ struct MyStruct<T> { x: u32, y: T }
|
|||
The type `MyStruct<u32>` would be an instance of `TyKind::Adt`:
|
||||
|
||||
```rust,ignore
|
||||
Adt(&'tcx AdtDef, SubstsRef<'tcx>)
|
||||
Adt(&'tcx AdtDef, GenericArgsRef<'tcx>)
|
||||
// ------------ ---------------
|
||||
// (1) (2)
|
||||
//
|
||||
|
|
@ -301,12 +301,12 @@ There are two parts:
|
|||
parameters. In our example, this is the `MyStruct` part *without* the argument `u32`.
|
||||
(Note that in the HIR, structs, enums and unions are represented differently, but in `ty::Ty`,
|
||||
they are all represented using `TyKind::Adt`.)
|
||||
- The [`SubstsRef`][substsref] is an interned list of values that are to be substituted for the
|
||||
generic parameters. In our example of `MyStruct<u32>`, we would end up with a list like `[u32]`.
|
||||
We’ll dig more into generics and substitutions in a little bit.
|
||||
- The [`GenericArgsRef`][GenericArgsRef] is an interned list of values that are to be substituted
|
||||
for the generic parameters. In our example of `MyStruct<u32>`, we would end up with a list like
|
||||
`[u32]`. We’ll dig more into generics and substitutions in a little bit.
|
||||
|
||||
[adtdef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.AdtDef.html
|
||||
[substsref]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/subst/type.SubstsRef.html
|
||||
[GenericArgsRef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/subst/type.GenericArgsRef.html
|
||||
|
||||
**`AdtDef` and `DefId`**
|
||||
|
||||
|
|
@ -363,13 +363,13 @@ delaying a redundant span bug.
|
|||
|
||||
## Question: Why not substitute “inside” the `AdtDef`?
|
||||
|
||||
Recall that we represent a generic struct with `(AdtDef, substs)`. So why bother with this scheme?
|
||||
Recall that we represent a generic struct with `(AdtDef, args)`. So why bother with this scheme?
|
||||
|
||||
Well, the alternate way we could have chosen to represent types would be to always create a new,
|
||||
fully-substituted form of the `AdtDef` where all the types are already substituted. This seems like
|
||||
less of a hassle. However, the `(AdtDef, substs)` scheme has some advantages over this.
|
||||
less of a hassle. However, the `(AdtDef, args)` scheme has some advantages over this.
|
||||
|
||||
First, `(AdtDef, substs)` scheme has an efficiency win:
|
||||
First, `(AdtDef, args)` scheme has an efficiency win:
|
||||
|
||||
```rust,ignore
|
||||
struct MyStruct<T> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue