Generalized type folding mechanism. The setup is a bit convoluted
but allows for convenient usage. Let T be an instance of some
“foldable type” (one which implements
TypeFoldable) and F be an
instance of a “folder” (a type which implements
the setup is intended to be:
T.fold_with(F) --calls--> F.fold_T(T) --calls--> T.super_fold_with(F)
This way, when you define a new folder F, you can override
fold_T() to customize the behavior, and invoke
to get the original behavior. Meanwhile, to actually fold
something, you can just write
T.fold_with(F), which is
convenient. (Note that
fold_with will also transparently handle
things like a
Vec<T> where T is foldable and so on.)
In this ideal setup, the only function that actually does
T.super_fold_with(), which traverses the type
T.super_fold_with() should only ever call
In some cases, we follow a degenerate pattern where we do not have
fold_T method. Instead,
T.fold_with traverses the structure directly.
This is suboptimal because the behavior cannot be overridden, but it’s
much less work to implement. If you ever do need an override that
doesn’t exist, it’s not hard to convert the degenerate pattern into the
TypeFoldable T can also be visited by a
TypeVisitor V using similar setup:
T.visit_with(V) --calls--> V.visit_T(T) --calls--> T.super_visit_with(V).
These methods return true to indicate that the visitor has found what it is looking for, and does not need to visit anything else.
Replaces the escaping bound vars (late bound regions or bound types) in a type.
An “escaping var” is a bound var whose binder is not part of
t. A bound var can be a
bound region or a bound type.
Collects all the late-bound regions at the innermost binding level into a hash set.
Folds over the substructure of a type, visiting its component types and all regions that occur free within it.
This trait is implemented for every type that can be folded.
Basically, every type that has a corresponding method in
TypeFolder trait defines the actual folding. There is a
method defined for every foldable type. Each of these has a
default implementation that does an “identity” fold. Within each
identity fold, it should invoke
foo.fold_with(self) to fold each