Skip to content

Commit f8ca030

Browse files
authored
Only output type bounds when a field actually refers to a generic (#508)
1 parent 44ef78d commit f8ca030

File tree

1 file changed

+72
-7
lines changed

1 file changed

+72
-7
lines changed

asn1_derive/src/lib.rs

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub fn derive_asn1_read(input: proc_macro::TokenStream) -> proc_macro::TokenStre
1414
let lifetime_name = add_lifetime_if_none(&mut generics);
1515
add_bounds(
1616
&mut generics,
17-
all_field_types(&input.data),
17+
all_field_types(&input.data, &input.generics),
1818
syn::parse_quote!(asn1::Asn1Readable<#lifetime_name>),
1919
syn::parse_quote!(asn1::Asn1DefinedByReadable<#lifetime_name, asn1::ObjectIdentifier>),
2020
false,
@@ -61,9 +61,10 @@ pub fn derive_asn1_write(input: proc_macro::TokenStream) -> proc_macro::TokenStr
6161
let mut input = syn::parse_macro_input!(input as syn::DeriveInput);
6262

6363
let name = input.ident;
64+
let fields = all_field_types(&input.data, &input.generics);
6465
add_bounds(
6566
&mut input.generics,
66-
all_field_types(&input.data),
67+
fields,
6768
syn::parse_quote!(asn1::Asn1Writable),
6869
syn::parse_quote!(asn1::Asn1DefinedByWritable<asn1::ObjectIdentifier>),
6970
true,
@@ -275,16 +276,33 @@ fn add_lifetime_if_none(generics: &mut syn::Generics) -> syn::Lifetime {
275276
generics.lifetimes().next().unwrap().lifetime.clone()
276277
}
277278

278-
fn all_field_types(data: &syn::Data) -> Vec<(syn::Type, OpType, bool)> {
279+
fn all_field_types(data: &syn::Data, generics: &syn::Generics) -> Vec<(syn::Type, OpType, bool)> {
280+
let generic_params = generics
281+
.params
282+
.iter()
283+
.filter_map(|p| {
284+
if let syn::GenericParam::Type(tp) = p {
285+
Some(tp.ident.clone())
286+
} else {
287+
None
288+
}
289+
})
290+
.collect::<Vec<_>>();
291+
279292
let mut field_types = vec![];
280293
match data {
281294
syn::Data::Struct(v) => {
282-
add_field_types(&mut field_types, &v.fields, None);
295+
add_field_types(&mut field_types, &v.fields, None, &generic_params);
283296
}
284297
syn::Data::Enum(v) => {
285298
for variant in &v.variants {
286299
let (op_type, _) = extract_field_properties(&variant.attrs);
287-
add_field_types(&mut field_types, &variant.fields, Some(op_type));
300+
add_field_types(
301+
&mut field_types,
302+
&variant.fields,
303+
Some(op_type),
304+
&generic_params,
305+
);
288306
}
289307
}
290308
syn::Data::Union(_) => panic!("Unions not supported"),
@@ -296,27 +314,74 @@ fn add_field_types(
296314
field_types: &mut Vec<(syn::Type, OpType, bool)>,
297315
fields: &syn::Fields,
298316
op_type: Option<OpType>,
317+
generic_params: &[syn::Ident],
299318
) {
300319
match fields {
301320
syn::Fields::Named(v) => {
302321
for f in &v.named {
303-
add_field_type(field_types, f, op_type.clone());
322+
add_field_type(field_types, f, op_type.clone(), generic_params);
304323
}
305324
}
306325
syn::Fields::Unnamed(v) => {
307326
for f in &v.unnamed {
308-
add_field_type(field_types, f, op_type.clone());
327+
add_field_type(field_types, f, op_type.clone(), generic_params);
309328
}
310329
}
311330
syn::Fields::Unit => {}
312331
}
313332
}
314333

334+
fn type_contains_generic_param(t: &syn::Type, generic_params: &[syn::Ident]) -> bool {
335+
match t {
336+
syn::Type::Array(v) => type_contains_generic_param(&v.elem, generic_params),
337+
syn::Type::BareFn(_) => todo!("BareFn"),
338+
syn::Type::Group(v) => type_contains_generic_param(&v.elem, generic_params),
339+
syn::Type::ImplTrait(_) => todo!("ImplTrait"),
340+
syn::Type::Infer(_) => false,
341+
syn::Type::Macro(_) => false,
342+
syn::Type::Never(_) => false,
343+
syn::Type::Paren(v) => type_contains_generic_param(&v.elem, generic_params),
344+
syn::Type::Path(v) => {
345+
if let Some(q) = &v.qself {
346+
if type_contains_generic_param(&q.ty, generic_params) {
347+
return true;
348+
}
349+
} else if generic_params.contains(&v.path.segments[0].ident) {
350+
return true;
351+
}
352+
v.path.segments.iter().any(|s| match &s.arguments {
353+
syn::PathArguments::AngleBracketed(a) => a.args.iter().any(|ga| match ga {
354+
syn::GenericArgument::Type(t) => type_contains_generic_param(t, generic_params),
355+
_ => false,
356+
}),
357+
syn::PathArguments::Parenthesized(_) => todo!("ParenthesizedGenericArguments"),
358+
syn::PathArguments::None => false,
359+
})
360+
}
361+
syn::Type::Ptr(v) => type_contains_generic_param(&v.elem, generic_params),
362+
syn::Type::Reference(v) => type_contains_generic_param(&v.elem, generic_params),
363+
syn::Type::Slice(v) => type_contains_generic_param(&v.elem, generic_params),
364+
syn::Type::TraitObject(_) => todo!("TraitObject"),
365+
syn::Type::Tuple(v) => v
366+
.elems
367+
.iter()
368+
.any(|t| type_contains_generic_param(t, generic_params)),
369+
syn::Type::Verbatim(_) => false,
370+
371+
_ => false,
372+
}
373+
}
374+
315375
fn add_field_type(
316376
field_types: &mut Vec<(syn::Type, OpType, bool)>,
317377
f: &syn::Field,
318378
op_type: Option<OpType>,
379+
generic_params: &[syn::Ident],
319380
) {
381+
if !type_contains_generic_param(&f.ty, generic_params) {
382+
return;
383+
}
384+
320385
// If we have an op_type here, it means it came from an enum variant. In
321386
// that case, even though it wasn't marked "required", it is for the
322387
// purposes of how we're using it.

0 commit comments

Comments
 (0)