Merge pull request #2379 from rust-lang/tshepang-which-chapter

clean TypeFold* chapter
This commit is contained in:
Tshepang Mbambo 2025-05-15 00:33:47 +02:00 committed by GitHub
commit 8bc57dec32
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 30 additions and 24 deletions

View File

@ -1,26 +1,28 @@
<!-- date-check: may 2024 -->
# `TypeFoldable` and `TypeFolder` # `TypeFoldable` and `TypeFolder`
In the previous chapter we discussed instantiating binders. This must involves looking at everything inside of a `Early/Binder` In [a previous chapter], we discussed instantiating binders.
to find any usages of the bound vars in order to replace them. Binders can wrap an arbitrary rust type `T` not just a `Ty` so This involves looking at everything inside of a `Early(Binder)`
how do we implement the `instantiate` methods on the `Early/Binder` types. to find any usages of the bound vars in order to replace them.
Binders can wrap an arbitrary Rust type `T`, not just a `Ty`.
So, how do we implement the `instantiate` methods on the `Early/Binder` types?
The answer is a couple of traits: The answer is a couple of traits:
[`TypeFoldable`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/fold/trait.TypeFoldable.html) [`TypeFoldable`]
and and
[`TypeFolder`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/fold/trait.TypeFolder.html). [`TypeFolder`].
- `TypeFoldable` is implemented by types that embed type information. It allows you to recursively - `TypeFoldable` is implemented by types that embed type information. It allows you to recursively
process the contents of the `TypeFoldable` and do stuff to them. process the contents of the `TypeFoldable` and do stuff to them.
- `TypeFolder` defines what you want to do with the types you encounter while processing the - `TypeFolder` defines what you want to do with the types you encounter while processing the
`TypeFoldable`. `TypeFoldable`.
For example, the `TypeFolder` trait has a method For example, the `TypeFolder` trait has a method [`fold_ty`]
[`fold_ty`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/fold/trait.TypeFolder.html#method.fold_ty) that takes a type as input and returns a new type as a result.
that takes a type as input and returns a new type as a result. `TypeFoldable` invokes the `TypeFoldable` invokes the `TypeFolder` `fold_foo` methods on itself,
`TypeFolder` `fold_foo` methods on itself, giving the `TypeFolder` access to its contents (the giving the `TypeFolder` access to its contents (the types, regions, etc that are contained within).
types, regions, etc that are contained within).
You can think of it with this analogy to the iterator combinators we have come to love in rust: You can think of it with this analogy to the iterator combinators we have come to love in Rust:
```rust,ignore ```rust,ignore
vec.iter().map(|e1| foo(e2)).collect() vec.iter().map(|e1| foo(e2)).collect()
@ -33,8 +35,7 @@ So to reiterate:
- `TypeFolder` is a trait that defines a “map” operation. - `TypeFolder` is a trait that defines a “map” operation.
- `TypeFoldable` is a trait that is implemented by things that embed types. - `TypeFoldable` is a trait that is implemented by things that embed types.
In the case of `subst`, we can see that it is implemented as a `TypeFolder`: In the case of `subst`, we can see that it is implemented as a `TypeFolder`: [`ArgFolder`].
[`ArgFolder`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/binder/struct.ArgFolder.html).
Looking at its implementation, we see where the actual substitutions are happening. Looking at its implementation, we see where the actual substitutions are happening.
However, you might also notice that the implementation calls this `super_fold_with` method. What is However, you might also notice that the implementation calls this `super_fold_with` method. What is
@ -88,17 +89,22 @@ things. We only want to do something when we reach a type. That means there may
`TypeFoldable` types whose implementations basically just forward to their fields `TypeFoldable` `TypeFoldable` types whose implementations basically just forward to their fields `TypeFoldable`
implementations. Such implementations of `TypeFoldable` tend to be pretty tedious to write by hand. implementations. Such implementations of `TypeFoldable` tend to be pretty tedious to write by hand.
For this reason, there is a `derive` macro that allows you to `#![derive(TypeFoldable)]`. It is For this reason, there is a `derive` macro that allows you to `#![derive(TypeFoldable)]`. It is
defined defined [here].
[here](https://github.com/rust-lang/rust/blob/master/compiler/rustc_macros/src/type_foldable.rs).
**`subst`** In the case of substitutions the [actual **`subst`** In the case of substitutions the [actual folder]
folder](https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L440-L451) is going to be doing the indexing weve already mentioned.
is going to be doing the indexing weve already mentioned. There we define a `Folder` and call There we define a `Folder` and call `fold_with` on the `TypeFoldable` to process yourself.
`fold_with` on the `TypeFoldable` to process yourself. Then Then [fold_ty] the method that process each type it looks for a `ty::Param` and for those
[fold_ty](https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L512-L536) it replaces it for something from the list of substitutions, otherwise recursively process the type.
the method that process each type it looks for a `ty::Param` and for those it replaces it for To replace it, calls [ty_for_param]
something from the list of substitutions, otherwise recursively process the type. To replace it,
calls
[ty_for_param](https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L552-L587)
and all that does is index into the list of substitutions with the index of the `Param`. and all that does is index into the list of substitutions with the index of the `Param`.
[a previous chapter]: ty_module/instantiating_binders.md
[`TypeFoldable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFoldable.html
[`TypeFolder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFolder.html
[`fold_ty`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/trait.TypeFolder.html#method.fold_ty
[`ArgFolder`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/binder/struct.ArgFolder.html
[here]: https://github.com/rust-lang/rust/blob/master/compiler/rustc_macros/src/type_foldable.rs
[actual folder]: https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L440-L451
[fold_ty]: https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L512-L536
[ty_for_param]: https://github.com/rust-lang/rust/blob/75ff3110ac6d8a0259023b83fd20d7ab295f8dd6/src/librustc_middle/ty/subst.rs#L552-L587