Skip to content

Commit 9a67b2b

Browse files
committed
improve ty-module/binders.md
1 parent 291603e commit 9a67b2b

1 file changed

Lines changed: 13 additions & 9 deletions

File tree

src/ty-module/binders.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# `Binder` and Higher ranked regions
22

3-
Sometimes we define generic parameters not on an item but as part of a type or a where clause.
4-
As an example the type `for<'a> fn(&'a u32)` or the where clause `for<'a> T: Trait<'a>` both introduce a generic lifetime named `'a`.
5-
Currently there is no stable syntax for `for<T>` or `for<const N: usize>` but on nightly `feature(non_lifetime_binders)` can be used to write where clauses (but not types) using `for<T>`/`for<const N: usize>`.
3+
Sometimes, we define generic parameters not on an item but as part of a type or a where clause.
4+
As an example, the type `for<'a> fn(&'a u32)` or the where clause `for<'a> T: Trait<'a>` both introduce a generic lifetime named `'a`.
5+
Currently, there is no stable syntax for `for<T>` or `for<const N: usize>`,
6+
but on nightly, `feature(non_lifetime_binders)` can be used to write where clauses (but not types) using `for<T>`/`for<const N: usize>`.
67

78
The `for` is referred to as a "binder" because it brings new names into scope. In rustc we use the `Binder` type to track where these parameters are introduced and what the parameters are (i.e. how many and whether the parameter is a type/const/region). A type such as `for<'a> fn(&'a u32)` would be
89
represented in rustc as:
@@ -18,12 +19,14 @@ These bound regions/types/consts are composed of two main pieces of data:
1819
- A [DebruijnIndex](../appendix/background.md#what-is-a-de-bruijn-index) to specify which binder we are referring to.
1920
- A [`BoundVar`] which specifies which of the parameters that the `Binder` introduces we are referring to.
2021

21-
We also sometimes store some extra information for diagnostics reasons via the [`BoundTyKind`]/[`BoundRegionKind`] but this is not important for type equality or more generally the semantics of `Ty`.
22+
We also sometimes store some extra information for diagnostics reasons via the [`BoundTyKind`]/[`BoundRegionKind`],
23+
but this is not important for type equality, or, more generally, the semantics of `Ty`.
2224
(omitted from the above example)
2325

24-
In debug output (and also informally when talking to each other) we tend to write these bound variables in the format of `^DebruijnIndex_BoundVar`.
26+
In debug output (and also informally when talking to each other),
27+
we tend to write these bound variables in the format of `^DebruijnIndex_BoundVar`.
2528
The above example would instead be written as `Binder(fn(&'^0_0), &[BoundVariableKind::Region])`.
26-
Sometimes when the `DebruijnIndex` is `0` we just omit it and would write `^0`.
29+
Sometimes, when the `DebruijnIndex` is `0`, we just omit it and would write `^0`.
2730

2831
Another concrete example, this time a mixture of `for<'a>` in a where clause and a type:
2932
```
@@ -45,16 +48,17 @@ Note how the `'^1_0` refers to the `'a` parameter.
4548
We use a `DebruijnIndex` of `1` to refer to the binder one level up from the innermost one, and a var of `0` to refer to the first parameter bound which is `'a`.
4649
We also use `'^0` to refer to the `'b` parameter, the `DebruijnIndex` is `0` (referring to the innermost binder) so we omit it, leaving only the boundvar of `0` referring to the first parameter bound which is `'b`.
4750

48-
We did not always explicitly track the set of bound vars introduced by each `Binder`, this caused a number of bugs (read: ICEs [#81193](https://github.com/rust-lang/rust/issues/81193), [#79949](https://github.com/rust-lang/rust/issues/79949), [#83017](https://github.com/rust-lang/rust/issues/83017)).
49-
By tracking these explicitly we can assert when constructing higher ranked where clauses/types that there are no escaping bound variables or variables from a different binder.
51+
We did not always explicitly track the set of bound vars introduced by each `Binder`,
52+
and this caused a number of bugs (read: ICEs [#81193](https://github.com/rust-lang/rust/issues/81193), [#79949](https://github.com/rust-lang/rust/issues/79949), [#83017](https://github.com/rust-lang/rust/issues/83017)).
53+
By tracking these explicitly, we can assert when constructing higher ranked where clauses/types that there are no escaping bound variables or variables from a different binder.
5054
See the following example of an invalid type inside of a binder:
5155
```
5256
Binder(
5357
fn(&'^1_0 &'^1 T/#0),
5458
&[BoundVariableKind::Region(...)],
5559
)
5660
```
57-
This would cause all kinds of issues as the region `'^1_0` refers to a binder at a higher level than the outermost binder i.e. it is an escaping bound var. The `'^1` region (also writeable as `'^0_1`) is also ill formed as the binder it refers to does not introduce a second parameter. Modern day rustc will ICE when constructing this binder due to both of those reasons, in the past we would have simply allowed this to work and then ran into issues in other parts of the codebase.
61+
This would cause all kinds of issues as the region `'^1_0` refers to a binder at a higher level than the outermost binder i.e. it is an escaping bound var. The `'^1` region (also writeable as `'^0_1`) is also ill formed as the binder it refers to does not introduce a second parameter. Modern day rustc will ICE when constructing this binder due to both of those reasons, in the past we would have simply allowed this to work and then ran into issues in other parts of the codebase.
5862

5963
[`Binder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Binder.html
6064
[`BoundVar`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.BoundVar.html

0 commit comments

Comments
 (0)