Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Precise bounds #19

Merged
merged 18 commits into from
Jun 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -89,7 +87,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 @@ -108,27 +107,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
Loading