| # Parameter `Ty`/`Const`/`Region`s | |
| When inside of generic items, types can be written that use in scope generic parameters, for example `fn foo<'a, T>(_: &'a Vec<T>)`. | |
| In this specific case, the `&'a Vec<T>` type would be represented internally as: | |
| ``` | |
| TyKind::Ref( | |
| RegionKind::LateParam(DefId(foo), DefId(foo::'a), "'a"), | |
| TyKind::Adt(Vec, &[TyKind::Param("T", 0)]) | |
| ) | |
| ``` | |
| There are three separate ways we represent usages of generic parameters: | |
| - [`TyKind::Param`]/[`ConstKind::Param`]/[`RegionKind::EarlyParam`] for early bound generic parameters (note: all type and const parameters are considered early bound, see the [chapter on early vs late bound parameters][ch_early_late_bound] for more information) | |
| - [`TyKind::Bound`]/[`ConstKind::Bound`]/[`RegionKind::Bound`] for references to parameters introduced via higher ranked bounds or higher ranked types i.e. `for<'a> fn(&'a u32)` or `for<'a> T: Trait<'a>`. This is discussed in the [chapter on `Binder`s][ch_binders]. | |
| - [`RegionKind::LateParam`] for late bound lifetime parameters, `LateParam` is discussed in the [chapter on instantiating `Binder`s][ch_instantiating_binders]. | |
| This chapter only covers `TyKind::Param` `ConstKind::Param` and `RegionKind::EarlyParam`. | |
| ## Ty/Const Parameters | |
| As `TyKind::Param` and `ConstKind::Param` are implemented identically this section only refers to `TyKind::Param` for simplicity. | |
| However you should keep in mind that everything here also is true of `ConstKind::Param` | |
| Each `TyKind::Param` contains two things: the name of the parameter and an index. | |
| See the following concrete example of a usage of `TyKind::Param`: | |
| ```rust,ignore | |
| struct Foo<T>(Vec<T>); | |
| ``` | |
| The `Vec<T>` type is represented as `TyKind::Adt(Vec, &[GenericArgKind::Type(Param("T", 0))])`. | |
| The name is somewhat self explanatory; it's the name of the type parameter. | |
| The index of the type parameter is an integer indicating | |
| its order in the list of generic parameters in scope. | |
| Note that this includes parameters defined on items on outer scopes than the item the parameter is defined on. | |
| Consider the following examples: | |
| ```rust,ignore | |
| struct Foo<A, B> { | |
| // A would have index 0 | |
| // B would have index 1 | |
| .. // some fields | |
| } | |
| impl<X, Y> Foo<X, Y> { | |
| fn method<Z>() { | |
| // inside here, X, Y and Z are all in scope | |
| // X has index 0 | |
| // Y has index 1 | |
| // Z has index 2 | |
| } | |
| } | |
| ``` | |
| Concretely, given the `ty::Generics` for the item the parameter is defined on, | |
| if the index is `2` and if we start from the root `parent`, it will be the third parameter to be introduced. | |
| For example in the above example, `Z` has index `2` and is the third generic parameter to be introduced, starting from the `impl` block. | |
| The index fully defines the `Ty` and is the only part of `TyKind::Param` that matters for reasoning about the code we are compiling. | |
| Generally, we do not care what the name is, and we only use the index. | |
| The name is included for diagnostics and debug logs as otherwise it would be | |
| incredibly difficult to understand the output, i.e. `Vec<Param(0)>: Sized` vs `Vec<T>: Sized`. In debug output, parameter types are | |
| often printed out as `{name}/#{index}`, for example in the function `foo` if we were to debug print `Vec<T>` it would be written as `Vec<T/#0>`. | |
| An alternative representation would be to only have the name. | |
| However, using an index is more efficient as it means we can index into `GenericArgs` when instantiating generic parameters with some arguments. | |
| We would otherwise have to store `GenericArgs` as a `HashMap<Symbol, GenericArg>` and do a hashmap lookup everytime we used a generic item. | |
| In theory an index would also allow for having multiple distinct parameters that use the same name, e.g. | |
| `impl<A> Foo<A> { fn bar<A>() { .. } }`. | |
| The rules against shadowing make this difficult but those language rules could change in the future. | |
| ### Lifetime parameters | |
| In contrast to `Ty`/`Const`'s `Param` singular `Param` variant, lifetimes have two variants for representing region parameters: [`RegionKind::EarlyParam`] and [`RegionKind::LateParam`]. | |
| The reason for this is due to function's distinguishing between [early and late bound parameters][ch_early_late_bound] which is discussed in an earlier chapter (see link). | |
| `RegionKind::EarlyParam` is structured identically to `Ty/Const`'s `Param` variant; it is simply a `u32` index and a `Symbol`. | |
| For lifetime parameters defined on non-function items, we always use `ReEarlyParam`. | |
| For functions, we use `ReEarlyParam` for any early bound parameters and `ReLateParam` for any late bound parameters. | |
| Note that, just like `Ty` and `Const` params, we often debug format them as `'SYMBOL/#INDEX`. | |
| An example: | |
| ```rust,ignore | |
| // This function would have its signature represented as: | |
| // | |
| // ``` | |
| // fn( | |
| // T/#2, | |
| // Ref('a/#0, Ref(ReLateParam(...), u32)) | |
| // ) -> Ref(ReLateParam(...), u32) | |
| // ``` | |
| fn foo<'a, 'b, T: 'a>(one: T, two: &'a &'b u32) -> &'b u32 { | |
| ... | |
| } | |
| ``` | |
| `RegionKind::LateParam` is discussed more in the chapter on [instantiating binders][ch_instantiating_binders]. | |
| [ch_early_late_bound]: ../early-late-parameters.md | |
| [ch_binders]: ./binders.md | |
| [ch_instantiating_binders]: ./instantiating-binders.md | |
| [`BoundRegionKind`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.BoundRegionKind.html | |
| [`RegionKind::EarlyParam`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.RegionKind.html#variant.ReEarlyParam | |
| [`RegionKind::LateParam`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.RegionKind.html#variant.ReLateParam | |
| [`ConstKind::Param`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Param | |
| [`TyKind::Param`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.TyKind.html#variant.Param | |
| [`TyKind::Bound`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.TyKind.html#variant.Bound | |
| [`ConstKind::Bound`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.ConstKind.html#variant.Bound | |
| [`RegionKind::Bound`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/type.RegionKind.html#variant.ReBound |