Skip to content

Commit

Permalink
Merge branch 'ijackson-precise-bounds'
Browse files Browse the repository at this point in the history
  • Loading branch information
magiclen committed Jun 1, 2024
2 parents 4a994a1 + 2ee8bd1 commit 2813ba0
Show file tree
Hide file tree
Showing 30 changed files with 395 additions and 222 deletions.
21 changes: 3 additions & 18 deletions src/common/bound.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use syn::{punctuated::Punctuated, token::Comma, GenericParam, Meta, Path, Type, WherePredicate};

use crate::common::where_predicates_bool::{
create_where_predicates_from_generic_parameters,
create_where_predicates_from_generic_parameters_check_types, meta_2_where_predicates,
WherePredicates, WherePredicatesOrBool,
};
Expand Down Expand Up @@ -33,34 +32,20 @@ impl Bound {
}

impl Bound {
#[inline]
pub(crate) fn into_where_predicates_by_generic_parameters(
self,
params: &Punctuated<GenericParam, Comma>,
bound_trait: &Path,
) -> Punctuated<WherePredicate, Comma> {
match self {
Self::Disabled => Punctuated::new(),
Self::Auto => create_where_predicates_from_generic_parameters(params, bound_trait),
Self::Custom(where_predicates) => where_predicates,
}
}

#[inline]
pub(crate) fn into_where_predicates_by_generic_parameters_check_types(
self,
params: &Punctuated<GenericParam, Comma>,
_params: &Punctuated<GenericParam, Comma>,
bound_trait: &Path,
types: &[&Type],
recursive: Option<(bool, bool, bool)>,
supertraits: &[proc_macro2::TokenStream],
) -> Punctuated<WherePredicate, Comma> {
match self {
Self::Disabled => Punctuated::new(),
Self::Auto => create_where_predicates_from_generic_parameters_check_types(
params,
bound_trait,
types,
recursive,
supertraits,
),
Self::Custom(where_predicates) => where_predicates,
}
Expand Down
113 changes: 1 addition & 112 deletions src/common/type.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use std::collections::HashSet;

use syn::{
parse::{Parse, ParseStream},
punctuated::Punctuated,
GenericArgument, Ident, Meta, Path, PathArguments, Token, Type, TypeParamBound,
Meta, Token, Type,
};

pub(crate) struct TypeWithPunctuatedMeta {
Expand Down Expand Up @@ -34,115 +32,6 @@ impl Parse for TypeWithPunctuatedMeta {
}
}

/// recursive (dereference, de_ptr, de_param)
#[inline]
pub(crate) fn find_idents_in_path<'a>(
set: &mut HashSet<&'a Ident>,
path: &'a Path,
recursive: Option<(bool, bool, bool)>,
) {
if let Some((_, _, de_param)) = recursive {
if de_param {
if let Some(segment) = path.segments.iter().last() {
if let PathArguments::AngleBracketed(a) = &segment.arguments {
// the ident is definitely not a generic parameter, so we don't insert it

for arg in a.args.iter() {
match arg {
GenericArgument::Type(ty) => {
find_idents_in_type(set, ty, recursive);
},
GenericArgument::AssocType(ty) => {
find_idents_in_type(set, &ty.ty, recursive);
},
_ => (),
}
}

return;
}
}
}
}

if let Some(ty) = path.get_ident() {
set.insert(ty);
}
}

/// recursive (dereference, de_ptr, de_param)
#[inline]
pub(crate) fn find_idents_in_type<'a>(
set: &mut HashSet<&'a Ident>,
ty: &'a Type,
recursive: Option<(bool, bool, bool)>,
) {
match ty {
Type::Array(ty) => {
if recursive.is_some() {
find_idents_in_type(set, ty.elem.as_ref(), recursive);
}
},
Type::Group(ty) => {
if recursive.is_some() {
find_idents_in_type(set, ty.elem.as_ref(), recursive);
}
},
Type::ImplTrait(ty) => {
// always recursive
for b in &ty.bounds {
if let TypeParamBound::Trait(ty) = b {
find_idents_in_path(set, &ty.path, recursive);
}
}
},
Type::Macro(ty) => {
if recursive.is_some() {
find_idents_in_path(set, &ty.mac.path, recursive);
}
},
Type::Paren(ty) => {
if recursive.is_some() {
find_idents_in_type(set, ty.elem.as_ref(), recursive);
}
},
Type::Path(ty) => {
find_idents_in_path(set, &ty.path, recursive);
},
Type::Ptr(ty) => {
if let Some((_, true, _)) = recursive {
find_idents_in_type(set, ty.elem.as_ref(), recursive);
}
},
Type::Reference(ty) => {
if let Some((true, ..)) = recursive {
find_idents_in_type(set, ty.elem.as_ref(), recursive);
}
},
Type::Slice(ty) => {
if recursive.is_some() {
find_idents_in_type(set, ty.elem.as_ref(), recursive);
}
},
Type::TraitObject(ty) => {
// always recursive
for b in &ty.bounds {
if let TypeParamBound::Trait(ty) = b {
find_idents_in_path(set, &ty.path, recursive);
}
}
},
Type::Tuple(ty) => {
if recursive.is_some() {
for ty in &ty.elems {
find_idents_in_type(set, ty, recursive)
}
}
},
_ => (),
}
}

#[inline]
pub(crate) fn dereference(ty: &Type) -> &Type {
if let Type::Reference(ty) = ty {
Expand Down
24 changes: 7 additions & 17 deletions src/common/where_predicates_bool.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::collections::HashSet;

use quote::{quote, ToTokens};
use syn::{
parse::{Parse, ParseStream},
Expand All @@ -9,7 +7,7 @@ use syn::{
Expr, GenericParam, Lit, Meta, MetaNameValue, Path, Token, Type, WherePredicate,
};

use super::{path::path_to_string, r#type::find_idents_in_type};
use super::path::path_to_string;

pub(crate) type WherePredicates = Punctuated<WherePredicate, Token![,]>;

Expand Down Expand Up @@ -82,7 +80,8 @@ pub(crate) fn meta_2_where_predicates(meta: &Meta) -> syn::Result<WherePredicate
}

#[inline]
pub(crate) fn create_where_predicates_from_generic_parameters(
#[allow(dead_code)]
pub(crate) fn create_where_predicates_from_all_generic_parameters(
params: &Punctuated<GenericParam, Comma>,
bound_trait: &Path,
) -> WherePredicates {
Expand All @@ -101,27 +100,18 @@ pub(crate) fn create_where_predicates_from_generic_parameters(

#[inline]
pub(crate) fn create_where_predicates_from_generic_parameters_check_types(
params: &Punctuated<GenericParam, Comma>,
bound_trait: &Path,
types: &[&Type],
recursive: Option<(bool, bool, bool)>,
supertraits: &[proc_macro2::TokenStream],
) -> WherePredicates {
let mut where_predicates = Punctuated::new();

let mut set = HashSet::new();

for t in types {
find_idents_in_type(&mut set, t, recursive);
where_predicates.push(syn::parse2(quote! { #t: #bound_trait }).unwrap());
}

for param in params {
if let GenericParam::Type(ty) = param {
let ident = &ty.ident;

if set.contains(ident) {
where_predicates.push(syn::parse2(quote! { #ident: #bound_trait }).unwrap());
}
}
for supertrait in supertraits {
where_predicates.push(syn::parse2(quote! { Self: #supertrait }).unwrap());
}

where_predicates
Expand Down
2 changes: 1 addition & 1 deletion src/trait_handlers/clone/clone_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ impl TraitHandler for CloneEnumHandler {
})
.unwrap(),
&clone_types,
Some((false, false, false)),
&[],
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/trait_handlers/clone/clone_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl TraitHandler for CloneStructHandler {
})
.unwrap(),
&clone_types,
Some((false, false, false)),
&[],
);
}

Expand Down
7 changes: 6 additions & 1 deletion src/trait_handlers/clone/clone_union.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ impl TraitHandler for CloneUnionHandler {
}
.build_from_clone_meta(meta)?;

let mut field_types = vec![];

if let Data::Union(data) = &ast.data {
for field in data.fields.named.iter() {
field_types.push(&field.ty);
let _ = FieldAttributeBuilder {
enable_method: false
}
Expand All @@ -32,9 +35,11 @@ impl TraitHandler for CloneUnionHandler {

let ident = &ast.ident;

let bound = type_attribute.bound.into_where_predicates_by_generic_parameters(
let bound = type_attribute.bound.into_where_predicates_by_generic_parameters_check_types(
&ast.generics.params,
&syn::parse2(quote!(::core::marker::Copy)).unwrap(),
&field_types,
&[],
);

let where_clause = ast.generics.make_where_clause();
Expand Down
28 changes: 12 additions & 16 deletions src/trait_handlers/copy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ impl TraitHandler for CopyHandler {
}
.build_from_copy_meta(meta)?;

let mut field_types = vec![];

// if `contains_clone` is true, the implementation is handled by the `Clone` attribute, and field attributes is also handled by the `Clone` attribute
if !contains_clone {
match &ast.data {
Data::Struct(data) => {
for field in data.fields.iter() {
field_types.push(&field.ty);
let _ =
FieldAttributeBuilder.build_from_attributes(&field.attrs, traits)?;
}
Expand All @@ -46,13 +49,15 @@ impl TraitHandler for CopyHandler {
.build_from_attributes(&variant.attrs, traits)?;

for field in variant.fields.iter() {
field_types.push(&field.ty);
let _ = FieldAttributeBuilder
.build_from_attributes(&field.attrs, traits)?;
}
}
},
Data::Union(data) => {
for field in data.fields.named.iter() {
field_types.push(&field.ty);
let _ =
FieldAttributeBuilder.build_from_attributes(&field.attrs, traits)?;
}
Expand All @@ -61,22 +66,13 @@ impl TraitHandler for CopyHandler {

let ident = &ast.ident;

/*
#[derive(Clone)]
struct B<T> {
f1: PhantomData<T>,
}
impl<T> Copy for B<T> {
}
// The above code will throw a compile error because T have to be bound to `Copy`. However, it seems not to be necessary logically.
*/
let bound = type_attribute.bound.into_where_predicates_by_generic_parameters(
&ast.generics.params,
&syn::parse2(quote!(::core::marker::Copy)).unwrap(),
);
let bound =
type_attribute.bound.into_where_predicates_by_generic_parameters_check_types(
&ast.generics.params,
&syn::parse2(quote!(::core::marker::Copy)).unwrap(),
&field_types,
&[quote! {::core::clone::Clone}],
);

let where_clause = ast.generics.make_where_clause();

Expand Down
Loading

0 comments on commit 2813ba0

Please sign in to comment.