Skip to content

Commit ff87b7a

Browse files
committed
Move folding traits to type library
1 parent 59ee434 commit ff87b7a

File tree

7 files changed

+457
-519
lines changed

7 files changed

+457
-519
lines changed

compiler/rustc_middle/src/macros.rs

+1-126
Original file line numberDiff line numberDiff line change
@@ -63,47 +63,12 @@ macro_rules! CloneLiftImpls {
6363
};
6464
}
6565

66-
/// Used for types that are `Copy` and which **do not care arena
67-
/// allocated data** (i.e., don't need to be folded).
68-
#[macro_export]
69-
macro_rules! TrivialTypeFoldableImpls {
70-
(for <$tcx:lifetime> { $($ty:ty,)+ }) => {
71-
$(
72-
impl<$tcx> $crate::ty::fold::TypeFoldable<$crate::ty::TyCtxt<$tcx>> for $ty {
73-
fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$crate::ty::TyCtxt<$tcx>>>(
74-
self,
75-
_: &mut F,
76-
) -> ::std::result::Result<Self, F::Error> {
77-
Ok(self)
78-
}
79-
80-
#[inline]
81-
fn fold_with<F: $crate::ty::fold::TypeFolder<$crate::ty::TyCtxt<$tcx>>>(
82-
self,
83-
_: &mut F,
84-
) -> Self {
85-
self
86-
}
87-
}
88-
)+
89-
};
90-
91-
($($ty:ty,)+) => {
92-
TrivialTypeFoldableImpls! {
93-
for <'tcx> {
94-
$($ty,)+
95-
}
96-
}
97-
};
98-
}
99-
10066
/// Used for types that are `Copy` and which **do not care arena
10167
/// allocated data** (i.e., don't need to be folded).
10268
#[macro_export]
10369
macro_rules! TrivialTypeTraversalImpls {
10470
(for <$tcx:lifetime> { $($ty:ty,)+ }) => {
105-
TrivialTypeFoldableImpls!(for <$tcx> { $($ty,)+ });
106-
rustc_type_ir::TrivialTypeVisitableImpls!($(<$tcx> $crate::ty::TyCtxt<$tcx> { $ty })+);
71+
rustc_type_ir::TrivialTypeTraversalImpls!($(<$tcx> $crate::ty::TyCtxt<$tcx> { $ty })+);
10772
};
10873

10974
($($ty:ty,)+) => {
@@ -115,100 +80,10 @@ macro_rules! TrivialTypeTraversalImpls {
11580
};
11681
}
11782

118-
#[macro_export]
119-
macro_rules! TrivialTypeFoldableAndLiftImpls {
120-
($($t:tt)*) => {
121-
TrivialTypeFoldableImpls! { $($t)* }
122-
CloneLiftImpls! { $($t)* }
123-
}
124-
}
125-
12683
#[macro_export]
12784
macro_rules! TrivialTypeTraversalAndLiftImpls {
12885
($($t:tt)*) => {
12986
TrivialTypeTraversalImpls! { $($t)* }
13087
CloneLiftImpls! { $($t)* }
13188
}
13289
}
133-
134-
#[macro_export]
135-
macro_rules! EnumTypeTraversalImpl {
136-
(impl<$($p:tt),*> TypeFoldable<$tcx:ty> for $s:path {
137-
$($variants:tt)*
138-
} $(where $($wc:tt)*)*) => {
139-
impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
140-
$(where $($wc)*)*
141-
{
142-
fn try_fold_with<V: $crate::ty::fold::FallibleTypeFolder<$tcx>>(
143-
self,
144-
folder: &mut V,
145-
) -> ::std::result::Result<Self, V::Error> {
146-
EnumTypeTraversalImpl!(@FoldVariants(self, folder) input($($variants)*) output())
147-
}
148-
}
149-
};
150-
151-
(impl<$($p:tt),*> TypeVisitable<$tcx:ty> for $s:path {
152-
$($variants:tt)*
153-
} $(where $($wc:tt)*)*) => {
154-
rustc_type_ir::EnumTypeVisitableImpl! {
155-
impl<$($p),*> TypeVisitable<$tcx> for $s {
156-
$($variants)*
157-
} $(where $($wc)*)*
158-
}
159-
};
160-
161-
(@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => {
162-
Ok(match $this {
163-
$($output)*
164-
})
165-
};
166-
167-
(@FoldVariants($this:expr, $folder:expr)
168-
input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
169-
output( $($output:tt)*) ) => {
170-
EnumTypeTraversalImpl!(
171-
@FoldVariants($this, $folder)
172-
input($($input)*)
173-
output(
174-
$variant ( $($variant_arg),* ) => {
175-
$variant (
176-
$($crate::ty::fold::TypeFoldable::try_fold_with($variant_arg, $folder)?),*
177-
)
178-
}
179-
$($output)*
180-
)
181-
)
182-
};
183-
184-
(@FoldVariants($this:expr, $folder:expr)
185-
input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*)
186-
output( $($output:tt)*) ) => {
187-
EnumTypeTraversalImpl!(
188-
@FoldVariants($this, $folder)
189-
input($($input)*)
190-
output(
191-
$variant { $($variant_arg),* } => {
192-
$variant {
193-
$($variant_arg: $crate::ty::fold::TypeFoldable::fold_with(
194-
$variant_arg, $folder
195-
)?),* }
196-
}
197-
$($output)*
198-
)
199-
)
200-
};
201-
202-
(@FoldVariants($this:expr, $folder:expr)
203-
input( ($variant:path), $($input:tt)*)
204-
output( $($output:tt)*) ) => {
205-
EnumTypeTraversalImpl!(
206-
@FoldVariants($this, $folder)
207-
input($($input)*)
208-
output(
209-
$variant => { $variant }
210-
$($output)*
211-
)
212-
)
213-
};
214-
}

compiler/rustc_middle/src/ty/fold.rs

+2-238
Original file line numberDiff line numberDiff line change
@@ -1,246 +1,10 @@
1-
//! A folding traversal mechanism for complex data structures that contain type
2-
//! information.
3-
//!
4-
//! This is a modifying traversal. It consumes the data structure, producing a
5-
//! (possibly) modified version of it. Both fallible and infallible versions are
6-
//! available. The name is potentially confusing, because this traversal is more
7-
//! like `Iterator::map` than `Iterator::fold`.
8-
//!
9-
//! This traversal has limited flexibility. Only a small number of "types of
10-
//! interest" within the complex data structures can receive custom
11-
//! modification. These are the ones containing the most important type-related
12-
//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
13-
//!
14-
//! There are three groups of traits involved in each traversal.
15-
//! - `TypeFoldable`. This is implemented once for many types, including:
16-
//! - Types of interest, for which the methods delegate to the folder.
17-
//! - All other types, including generic containers like `Vec` and `Option`.
18-
//! It defines a "skeleton" of how they should be folded.
19-
//! - `TypeSuperFoldable`. This is implemented only for each type of interest,
20-
//! and defines the folding "skeleton" for these types.
21-
//! - `TypeFolder`/`FallibleTypeFolder. One of these is implemented for each
22-
//! folder. This defines how types of interest are folded.
23-
//!
24-
//! This means each fold is a mixture of (a) generic folding operations, and (b)
25-
//! custom fold operations that are specific to the folder.
26-
//! - The `TypeFoldable` impls handle most of the traversal, and call into
27-
//! `TypeFolder`/`FallibleTypeFolder` when they encounter a type of interest.
28-
//! - A `TypeFolder`/`FallibleTypeFolder` may call into another `TypeFoldable`
29-
//! impl, because some of the types of interest are recursive and can contain
30-
//! other types of interest.
31-
//! - A `TypeFolder`/`FallibleTypeFolder` may also call into a `TypeSuperFoldable`
32-
//! impl, because each folder might provide custom handling only for some types
33-
//! of interest, or only for some variants of each type of interest, and then
34-
//! use default traversal for the remaining cases.
35-
//!
36-
//! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U:
37-
//! TypeFoldable`, and an instance `s = S(ty, u)`, it would be folded like so:
38-
//! ```text
39-
//! s.fold_with(folder) calls
40-
//! - ty.fold_with(folder) calls
41-
//! - folder.fold_ty(ty) may call
42-
//! - ty.super_fold_with(folder)
43-
//! - u.fold_with(folder)
44-
//! ```
45-
use crate::ty::{self, Binder, BoundTy, Interner, Ty, TyCtxt, TypeVisitable};
1+
use crate::ty::{self, Binder, BoundTy, Ty, TyCtxt, TypeVisitable};
462
use rustc_data_structures::fx::FxIndexMap;
473
use rustc_hir::def_id::DefId;
484

495
use std::collections::BTreeMap;
506

51-
/// This trait is implemented for every type that can be folded,
52-
/// providing the skeleton of the traversal.
53-
///
54-
/// To implement this conveniently, use the derive macro located in
55-
/// `rustc_macros`.
56-
pub trait TypeFoldable<I: Interner>: TypeVisitable<I> {
57-
/// The entry point for folding. To fold a value `t` with a folder `f`
58-
/// call: `t.try_fold_with(f)`.
59-
///
60-
/// For most types, this just traverses the value, calling `try_fold_with`
61-
/// on each field/element.
62-
///
63-
/// For types of interest (such as `Ty`), the implementation of method
64-
/// calls a folder method specifically for that type (such as
65-
/// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
66-
/// to `TypeFolder`.
67-
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error>;
68-
69-
/// A convenient alternative to `try_fold_with` for use with infallible
70-
/// folders. Do not override this method, to ensure coherence with
71-
/// `try_fold_with`.
72-
fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
73-
self.try_fold_with(folder).into_ok()
74-
}
75-
}
76-
77-
// This trait is implemented for types of interest.
78-
pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
79-
/// Provides a default fold for a type of interest. This should only be
80-
/// called within `TypeFolder` methods, when a non-custom traversal is
81-
/// desired for the value of the type of interest passed to that method.
82-
/// For example, in `MyFolder::try_fold_ty(ty)`, it is valid to call
83-
/// `ty.try_super_fold_with(self)`, but any other folding should be done
84-
/// with `xyz.try_fold_with(self)`.
85-
fn try_super_fold_with<F: FallibleTypeFolder<I>>(
86-
self,
87-
folder: &mut F,
88-
) -> Result<Self, F::Error>;
89-
90-
/// A convenient alternative to `try_super_fold_with` for use with
91-
/// infallible folders. Do not override this method, to ensure coherence
92-
/// with `try_super_fold_with`.
93-
fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
94-
self.try_super_fold_with(folder).into_ok()
95-
}
96-
}
97-
98-
/// This trait is implemented for every infallible folding traversal. There is
99-
/// a fold method defined for every type of interest. Each such method has a
100-
/// default that does an "identity" fold. Implementations of these methods
101-
/// often fall back to a `super_fold_with` method if the primary argument
102-
/// doesn't satisfy a particular condition.
103-
///
104-
/// A blanket implementation of [`FallibleTypeFolder`] will defer to
105-
/// the infallible methods of this trait to ensure that the two APIs
106-
/// are coherent.
107-
pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = !> {
108-
fn tcx(&self) -> I;
109-
110-
fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T>
111-
where
112-
T: TypeFoldable<I>,
113-
I::Binder<T>: TypeSuperFoldable<I>,
114-
{
115-
t.super_fold_with(self)
116-
}
117-
118-
fn fold_ty(&mut self, t: I::Ty) -> I::Ty
119-
where
120-
I::Ty: TypeSuperFoldable<I>,
121-
{
122-
t.super_fold_with(self)
123-
}
124-
125-
fn fold_region(&mut self, r: I::Region) -> I::Region
126-
where
127-
I::Region: TypeSuperFoldable<I>,
128-
{
129-
r.super_fold_with(self)
130-
}
131-
132-
fn fold_const(&mut self, c: I::Const) -> I::Const
133-
where
134-
I::Const: TypeSuperFoldable<I>,
135-
{
136-
c.super_fold_with(self)
137-
}
138-
139-
fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate
140-
where
141-
I::Predicate: TypeSuperFoldable<I>,
142-
{
143-
p.super_fold_with(self)
144-
}
145-
}
146-
147-
/// This trait is implemented for every folding traversal. There is a fold
148-
/// method defined for every type of interest. Each such method has a default
149-
/// that does an "identity" fold.
150-
///
151-
/// A blanket implementation of this trait (that defers to the relevant
152-
/// method of [`TypeFolder`]) is provided for all infallible folders in
153-
/// order to ensure the two APIs are coherent.
154-
pub trait FallibleTypeFolder<I: Interner>: Sized {
155-
type Error;
156-
157-
fn tcx(&self) -> I;
158-
159-
fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, Self::Error>
160-
where
161-
T: TypeFoldable<I>,
162-
I::Binder<T>: TypeSuperFoldable<I>,
163-
{
164-
t.try_super_fold_with(self)
165-
}
166-
167-
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Self::Error>
168-
where
169-
I::Ty: TypeSuperFoldable<I>,
170-
{
171-
t.try_super_fold_with(self)
172-
}
173-
174-
fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error>
175-
where
176-
I::Region: TypeSuperFoldable<I>,
177-
{
178-
r.try_super_fold_with(self)
179-
}
180-
181-
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error>
182-
where
183-
I::Const: TypeSuperFoldable<I>,
184-
{
185-
c.try_super_fold_with(self)
186-
}
187-
188-
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error>
189-
where
190-
I::Predicate: TypeSuperFoldable<I>,
191-
{
192-
p.try_super_fold_with(self)
193-
}
194-
}
195-
196-
// This blanket implementation of the fallible trait for infallible folders
197-
// delegates to infallible methods to ensure coherence.
198-
impl<I: Interner, F> FallibleTypeFolder<I> for F
199-
where
200-
F: TypeFolder<I>,
201-
{
202-
type Error = !;
203-
204-
fn tcx(&self) -> I {
205-
TypeFolder::tcx(self)
206-
}
207-
208-
fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, !>
209-
where
210-
T: TypeFoldable<I>,
211-
I::Binder<T>: TypeSuperFoldable<I>,
212-
{
213-
Ok(self.fold_binder(t))
214-
}
215-
216-
fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, !>
217-
where
218-
I::Ty: TypeSuperFoldable<I>,
219-
{
220-
Ok(self.fold_ty(t))
221-
}
222-
223-
fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, !>
224-
where
225-
I::Region: TypeSuperFoldable<I>,
226-
{
227-
Ok(self.fold_region(r))
228-
}
229-
230-
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, !>
231-
where
232-
I::Const: TypeSuperFoldable<I>,
233-
{
234-
Ok(self.fold_const(c))
235-
}
236-
237-
fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, !>
238-
where
239-
I::Predicate: TypeSuperFoldable<I>,
240-
{
241-
Ok(self.fold_predicate(p))
242-
}
243-
}
7+
pub use rustc_type_ir::fold::*;
2448

2459
///////////////////////////////////////////////////////////////////////////
24610
// Some sample folders

0 commit comments

Comments
 (0)