in amzn-smt-ir-derive/src/lib.rs [352:429]
fn derive_fold(mut s: synstructure::Structure) -> TokenStream {
let smt_ir = smt_ir_crate_path();
let name = &s.ast().ident; // E.g. `Foo`
#[allow(non_snake_case)]
let (Logic, Fold, SuperFold, Folder) = (
quote!(#smt_ir::Logic),
quote!(#smt_ir::fold::Fold),
quote!(#smt_ir::fold::SuperFold),
quote!(#smt_ir::fold::Folder),
);
s.add_bounds(synstructure::AddBounds::None)
.bind_with(|_| synstructure::BindStyle::Move);
let impl_fold = s.gen_impl(quote! {
extern crate std;
gen impl<L: #Logic<Op = Self>, Out> #Fold<L, Out> for @Self {
type Output = Out;
fn fold_with<F, M>(
self,
folder: &mut F,
) -> std::result::Result<Self::Output, F::Error>
where
F: #Folder<L, M, Output = Out>,
{
folder.fold_theory_op(self.into())
}
}
});
let impl_super_fold = {
// Bound each generic parameter to implement `Fold`
let mut where_clause = None;
s.add_trait_bounds(
&parse_quote!(#Fold<L, Out>),
&mut where_clause,
synstructure::AddBounds::Generics,
);
// For each variant, construct a new version by folding each of the fields
let body = s.each_variant(|vi| {
vi.construct(|_, idx| {
let field = &vi.bindings()[idx];
quote!(#Fold::fold_with(#field, folder)?)
})
});
// If input type is `Foo<A, B>`, output `Foo<<A as Fold>::Output, <B as Fold>::Output>`
let out_params = s
.referenced_ty_params()
.into_iter()
.map(|ty| quote!(<#ty as #Fold<L, Out>>::Output));
s.gen_impl(quote! {
extern crate std;
gen impl<L: #Logic, Out> #SuperFold<L, Out> for @Self #where_clause {
type Output = #name<#(#out_params),*>;
fn super_fold_with<F, M>(
self,
folder: &mut F,
) -> std::result::Result<Self::Output, F::Error>
where
F: #Folder<L, M, Output = Out>,
{
Ok(match self { #body })
}
}
})
};
quote! {
#impl_fold
#impl_super_fold
}
}