update internal terminology: Substs -> GenericArgs

This commit is contained in:
yukang 2023-08-20 16:30:19 +08:00 committed by Tshepang Mbambo
parent 4285421cd2
commit 384ac6ebbb
7 changed files with 57 additions and 57 deletions

View File

@ -23,7 +23,7 @@ Term | Meaning
<span id="double-ptr">double pointer</span> &nbsp; | A pointer with additional metadata. See "fat pointer" for more.
<span id="drop-glue">drop glue</span> &nbsp; | (internal) compiler-generated instructions that handle calling the destructors (`Drop`) for data types.
<span id="dst">DST</span> &nbsp; | 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> &nbsp; | 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> &nbsp; | 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> &nbsp; | see "uninhabited type".
<span id="fat-ptr">fat pointer</span> &nbsp; | 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> &nbsp; | 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)

View File

@ -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 }

View File

@ -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:
Lets 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.

View File

@ -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

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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]`.
Well 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]`. Well 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> {