1 extern crate proc_macro
;
3 use proc_macro2
::{Span, TokenStream}
;
6 use syn
::{parse_quote, DeriveInput, GenericParam, Ident, TypeParamBound}
;
8 use synstructure
::decl_derive
;
10 /// Checks whether a generic parameter has a `: HasInterner` bound
11 fn has_interner(param
: &GenericParam
) -> Option
<&Ident
> {
12 bounded_by_trait(param
, "HasInterner")
15 /// Checks whether a generic parameter has a `: Interner` bound
16 fn is_interner(param
: &GenericParam
) -> Option
<&Ident
> {
17 bounded_by_trait(param
, "Interner")
20 fn has_interner_attr(input
: &DeriveInput
) -> Option
<TokenStream
> {
25 .find(|a
| a
.path
.is_ident("has_interner"))?
26 .parse_args
::<TokenStream
>()
27 .expect("Expected has_interner argument"),
31 fn bounded_by_trait
<'p
>(param
: &'p GenericParam
, name
: &str) -> Option
<&'p Ident
> {
32 let name
= Some(String
::from(name
));
34 GenericParam
::Type(ref t
) => t
.bounds
.iter().find_map(|b
| {
35 if let TypeParamBound
::Trait(trait_bound
) = b
{
40 .map(|s
| s
.ident
.to_string())
43 return Some(&t
.ident
);
52 fn get_generic_param(input
: &DeriveInput
) -> &GenericParam
{
53 match input
.generics
.params
.len() {
57 "deriving this trait requires a single type parameter or a `#[has_interner]` attr"
60 _
=> panic
!("deriving this trait only works with a single type parameter"),
62 &input
.generics
.params
[0]
65 fn get_generic_param_name(input
: &DeriveInput
) -> Option
<&Ident
> {
66 match get_generic_param(input
) {
67 GenericParam
::Type(t
) => Some(&t
.ident
),
72 fn find_interner(s
: &mut synstructure
::Structure
) -> (TokenStream
, DeriveKind
) {
75 if let Some(arg
) = has_interner_attr(input
) {
76 // Hardcoded interner:
78 // #[has_interner(ChalkIr)]
82 return (arg
, DeriveKind
::FromHasInternerAttr
);
85 let generic_param0
= get_generic_param(input
);
87 if let Some(param
) = has_interner(&generic_param0
) {
92 // struct Binders<T: HasInterner> { }
93 s
.add_impl_generic(parse_quote
! { _I }
);
95 s
.add_where_predicate(parse_quote
! { _I: ::chalk_ir::interner::Interner }
);
96 s
.add_where_predicate(
97 parse_quote
! { #param: ::chalk_ir::interner::HasInterner<Interner = _I> }
,
100 (quote
! { _I }
, DeriveKind
::FromHasInterner
)
101 } else if let Some(i
) = is_interner(&generic_param0
) {
106 // struct Foo<I: Interner> { }
107 (quote
! { #i }
, DeriveKind
::FromInterner
)
109 panic
!("deriving this trait requires a parameter that implements HasInterner or Interner",);
113 #[derive(Copy, Clone, PartialEq)]
120 decl_derive
!([HasInterner
, attributes(has_interner
)] => derive_has_interner
);
121 decl_derive
!([Visit
, attributes(has_interner
)] => derive_visit
);
122 decl_derive
!([SuperVisit
, attributes(has_interner
)] => derive_super_visit
);
123 decl_derive
!([Fold
, attributes(has_interner
)] => derive_fold
);
124 decl_derive
!([Zip
, attributes(has_interner
)] => derive_zip
);
126 fn derive_has_interner(mut s
: synstructure
::Structure
) -> TokenStream
{
127 let (interner
, _
) = find_interner(&mut s
);
129 s
.add_bounds(synstructure
::AddBounds
::None
);
131 quote
!(::chalk_ir
::interner
::HasInterner
),
133 type Interner
= #interner;
138 /// Derives Visit for structs and enums for which one of the following is true:
139 /// - It has a `#[has_interner(TheInterner)]` attribute
140 /// - There is a single parameter `T: HasInterner` (does not have to be named `T`)
141 /// - There is a single parameter `I: Interner` (does not have to be named `I`)
142 fn derive_visit(s
: synstructure
::Structure
) -> TokenStream
{
143 derive_any_visit(s
, parse_quote
! { Visit }
, parse_quote
! { visit_with }
)
146 /// Same as Visit, but derives SuperVisit instead
147 fn derive_super_visit(s
: synstructure
::Structure
) -> TokenStream
{
150 parse_quote
! { SuperVisit }
,
151 parse_quote
! { super_visit_with }
,
156 mut s
: synstructure
::Structure
,
161 let (interner
, kind
) = find_interner(&mut s
);
163 let body
= s
.each(|bi
| {
165 result
= result
.combine(::chalk_ir
::visit
::Visit
::visit_with(#bi, visitor, outer_binder));
166 if result
.return_early() {
172 if kind
== DeriveKind
::FromHasInterner
{
173 let param
= get_generic_param_name(input
).unwrap();
174 s
.add_where_predicate(parse_quote
! { #param: ::chalk_ir::visit::Visit<#interner> }
);
177 s
.add_bounds(synstructure
::AddBounds
::None
);
179 quote
!(::chalk_ir
::visit
:: #trait_name <#interner>),
181 fn #method_name <'i, R: ::chalk_ir::visit::VisitResult>(
183 visitor
: &mut dyn ::chalk_ir
::visit
::Visitor
< 'i
, #interner, Result = R >,
184 outer_binder
: ::chalk_ir
::DebruijnIndex
,
189 let mut result
= R
::new();
199 fn each_variant_pair
<F
, R
>(
200 a
: &mut synstructure
::Structure
,
201 b
: &mut synstructure
::Structure
,
205 F
: FnMut(&synstructure
::VariantInfo
<'_
>, &synstructure
::VariantInfo
<'_
>) -> R
,
208 let mut t
= TokenStream
::new();
209 for (v_a
, v_b
) in a
.variants_mut().iter_mut().zip(b
.variants_mut().iter_mut()) {
210 v_a
.binding_name(|_
, i
| Ident
::new(&format
!("a_{}", i
), Span
::call_site()));
211 v_b
.binding_name(|_
, i
| Ident
::new(&format
!("b_{}", i
), Span
::call_site()));
213 let pat_a
= v_a
.pat();
214 let pat_b
= v_b
.pat();
215 let body
= f(v_a
, v_b
);
217 quote
!((#pat_a, #pat_b) => {#body}).to_tokens(&mut t);
222 fn derive_zip(mut s
: synstructure
::Structure
) -> TokenStream
{
223 let (interner
, _
) = find_interner(&mut s
);
225 let mut a
= s
.clone();
226 let mut b
= s
.clone();
228 let mut body
= each_variant_pair(&mut a
, &mut b
, |v_a
, v_b
| {
229 let mut t
= TokenStream
::new();
230 for (b_a
, b_b
) in v_a
.bindings().iter().zip(v_b
.bindings().iter()) {
231 quote
!(chalk_ir
::zip
::Zip
::zip_with(zipper
, #b_a, #b_b)?;).to_tokens(&mut t);
233 quote
!(Ok(())).to_tokens(&mut t
);
237 // when the two variants are different
238 quote
!((_
, _
) => Err(::chalk_engine
::fallible
::NoSolution
)).to_tokens(&mut body
);
240 s
.add_bounds(synstructure
::AddBounds
::None
);
242 quote
!(::chalk_ir
::zip
::Zip
<#interner>),
245 fn zip_with
<'i
, Z
: ::chalk_ir
::zip
::Zipper
<'i
, #interner>>(
249 ) -> ::chalk_engine
::fallible
::Fallible
<()>
253 match (a
, b
) { #body }
259 /// Derives Fold for structs and enums for which one of the following is true:
260 /// - It has a `#[has_interner(TheInterner)]` attribute
261 /// - There is a single parameter `T: HasInterner` (does not have to be named `T`)
262 /// - There is a single parameter `I: Interner` (does not have to be named `I`)
263 fn derive_fold(mut s
: synstructure
::Structure
) -> TokenStream
{
266 let (interner
, kind
) = find_interner(&mut s
);
268 let body
= s
.each_variant(|vi
| {
269 let bindings
= vi
.bindings();
270 vi
.construct(|_
, index
| {
271 let bind
= &bindings
[index
];
273 ::chalk_ir
::fold
::Fold
::fold_with(#bind, folder, outer_binder)?
278 let type_name
= &input
.ident
;
280 let (target_interner
, result
) = match kind
{
281 DeriveKind
::FromHasInternerAttr
=> (interner
.clone(), quote
! { #type_name }
),
282 DeriveKind
::FromHasInterner
=> {
283 let param
= get_generic_param_name(input
).unwrap();
285 s
.add_impl_generic(parse_quote
! { _U }
)
286 .add_impl_generic(parse_quote
! { _TI }
)
287 .add_where_predicate(
288 parse_quote
! { #param: ::chalk_ir::fold::Fold<#interner, _TI, Result = _U> }
,
290 .add_where_predicate(
291 parse_quote
! { _U: ::chalk_ir::interner::HasInterner<Interner = _TI> }
,
293 .add_where_predicate(
294 parse_quote
! { _TI: ::chalk_ir::interner::TargetInterner<#interner> }
,
297 (quote
! { _TI }
, quote
! { #type_name<_U> }
)
299 DeriveKind
::FromInterner
=> {
300 s
.add_impl_generic(parse_quote
! { _TI }
)
301 .add_where_predicate(
302 parse_quote
! { _TI: ::chalk_ir::interner::TargetInterner<#interner> }
,
305 (quote
! { _TI }
, quote
! { #type_name<_TI> }
)
309 s
.add_bounds(synstructure
::AddBounds
::None
);
311 quote
!(::chalk_ir
::fold
::Fold
<#interner, #target_interner>),
313 type Result
= #result;
317 folder
: &mut dyn ::chalk_ir
::fold
::Folder
< 'i
, #interner, #target_interner >,
318 outer_binder
: ::chalk_ir
::DebruijnIndex
,
319 ) -> ::chalk_engine
::fallible
::Fallible
<Self::Result
>
322 #target_interner: 'i,
324 Ok(match *self { #body }
)