summaryrefslogtreecommitdiff
path: root/src/parse_trait_sig.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse_trait_sig.rs')
-rw-r--r--src/parse_trait_sig.rs361
1 files changed, 0 insertions, 361 deletions
diff --git a/src/parse_trait_sig.rs b/src/parse_trait_sig.rs
deleted file mode 100644
index 1267707..0000000
--- a/src/parse_trait_sig.rs
+++ /dev/null
@@ -1,361 +0,0 @@
-use std::collections::HashMap;
-
-use proc_macro2::Span;
-use syn::{
- spanned::Spanned, FnArg, PredicateType, Receiver, ReturnType, Type, TypePath, WherePredicate,
-};
-use syn::{Ident, Signature, TypeImplTrait};
-
-use crate::match_assoc_type;
-use crate::parse_assoc_type::BoxType;
-use crate::syn_utils::{iter_type, trait_bounds, TypeOrPath};
-use crate::transform::{dynamize_function_bounds, TransformError, TypeConverter};
-
-#[derive(Debug, Clone)]
-pub enum TypeTransform {
- NoOp,
- Into,
- Box(BoxType),
- Map(Box<TypeTransform>),
- Tuple(Vec<TypeTransform>),
- IntoIterMapCollect(Vec<TypeTransform>),
- Iterator(BoxType, Box<TypeTransform>),
- Result(Box<TypeTransform>, Box<TypeTransform>),
-}
-
-#[derive(Debug)]
-pub enum MethodError {
- NonDispatchableMethod,
- AssocTypeInInputs,
- ImplTraitInInputs,
-
- Transform(TransformError),
-
- UnconvertedAssocType,
-}
-
-impl From<TransformError> for MethodError {
- fn from(err: TransformError) -> Self {
- Self::Transform(err)
- }
-}
-
-fn filter_map_impl_trait(item: TypeOrPath) -> Option<&TypeImplTrait> {
- match item {
- TypeOrPath::Type(Type::ImplTrait(impltrait)) => Some(impltrait),
- _other => None,
- }
-}
-
-pub struct SignatureChanges {
- pub return_type: TypeTransform,
- pub type_param_transforms: HashMap<Ident, Vec<TypeTransform>>,
-}
-
-pub fn parse_trait_signature(
- signature: &mut Signature,
- type_converter: &TypeConverter,
-) -> Result<SignatureChanges, (Span, MethodError)> {
- if is_non_dispatchable(signature) {
- return Err((signature.span(), MethodError::NonDispatchableMethod));
- }
-
- // provide better error messages for associated types in params
- for input in &signature.inputs {
- if let FnArg::Typed(pattype) = input {
- if iter_type(&pattype.ty).any(match_assoc_type) {
- return Err((pattype.ty.span(), MethodError::AssocTypeInInputs));
- }
- if let Some(impl_trait) = iter_type(&pattype.ty).find_map(filter_map_impl_trait) {
- return Err((impl_trait.span(), MethodError::ImplTraitInInputs));
- }
- }
- }
-
- let type_param_transforms = dynamize_function_bounds(&mut signature.generics, type_converter)?;
-
- let return_type = match &mut signature.output {
- ReturnType::Type(_, og_type) => match type_converter.convert_type(og_type) {
- Ok(ret_type) => ret_type,
- Err((span, err)) => {
- return Err((span, err.into()));
- }
- },
- ReturnType::Default => TypeTransform::NoOp,
- };
- Ok(SignatureChanges {
- return_type,
- type_param_transforms,
- })
-}
-
-fn is_non_dispatchable(signature: &Signature) -> bool {
- // non-dispatchable: fn example(&self) where Self: Sized;
- if let Some(where_clause) = &signature.generics.where_clause {
- if where_clause
- .predicates
- .iter()
- .any(bounds_self_and_has_bound_sized)
- {
- return true;
- }
- }
-
- // non-dispatchable: fn example();
- if signature.inputs.is_empty() {
- return true;
- }
-
- // non-dispatchable: fn example(arg: Type);
- if matches!(signature.inputs.first(), Some(FnArg::Typed(_))) {
- return true;
- }
-
- // non-dispatchable: fn example(self);
- if matches!(
- signature.inputs.first(),
- Some(FnArg::Receiver(Receiver {
- reference: None,
- ..
- }))
- ) {
- return true;
- }
- false
-}
-
-/// Returns true if the bounded type is `Self` and the bounds contain `Sized`.
-fn bounds_self_and_has_bound_sized(predicate: &WherePredicate) -> bool {
- matches!(
- predicate,
- WherePredicate::Type(PredicateType {
- bounded_ty: Type::Path(TypePath { path, .. }),
- bounds,
- ..
- })
- if path.is_ident("Self")
- && trait_bounds(bounds).any(|b| b.path.is_ident("Sized"))
- )
-}
-
-#[cfg(test)]
-mod tests {
- use quote::{format_ident, quote};
- use syn::{TraitItemMethod, Type};
-
- use crate::{
- parse_assoc_type::DestType,
- parse_trait_sig::{parse_trait_signature, MethodError, SignatureChanges, TypeTransform},
- transform::{TransformError, TypeConverter},
- };
-
- #[test]
- fn ok_void() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test(&self);
- })
- .unwrap();
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &Default::default()),
- Ok(SignatureChanges {
- return_type: TypeTransform::NoOp,
- ..
- })
- ));
- }
-
- #[test]
- fn ok_assoc_type() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test(&self) -> Self::A;
- })
- .unwrap();
-
- let mut type_converter = TypeConverter::default();
- let ident = format_ident!("A");
- let dest_inner = Type::Verbatim(quote! {Example});
- let dest = DestType::Into(&dest_inner);
- type_converter.assoc_type_conversions.insert(ident, dest);
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &type_converter),
- Ok(SignatureChanges {
- return_type: TypeTransform::Into,
- ..
- })
- ));
- }
-
- #[test]
- fn err_unconvertible_assoc_type() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test(&self) -> Self::A;
- })
- .unwrap();
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &Default::default()),
- Err((
- _,
- MethodError::Transform(TransformError::AssocTypeWithoutDestType)
- ))
- ));
- }
-
- #[test]
- fn err_non_dispatchable_assoc_function_no_args() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test();
- })
- .unwrap();
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &Default::default()),
- Err((_, MethodError::NonDispatchableMethod))
- ));
- }
-
- #[test]
- fn err_non_dispatchable_assoc_function_with_args() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test(arg: Type);
- })
- .unwrap();
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &Default::default()),
- Err((_, MethodError::NonDispatchableMethod))
- ));
- }
-
- #[test]
- fn err_non_dispatchable_consume_self() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test(self);
- })
- .unwrap();
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &Default::default()),
- Err((_, MethodError::NonDispatchableMethod))
- ));
- }
-
- #[test]
- fn err_non_dispatchable_where_self_sized() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test(&self) where Self: Sized;
- })
- .unwrap();
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &Default::default()),
- Err((_, MethodError::NonDispatchableMethod))
- ));
- }
-
- #[test]
- fn err_assoc_type_in_unsupported_return() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test(&self) -> Foo<Self::A>;
- })
- .unwrap();
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &Default::default()),
- Err((_, MethodError::Transform(TransformError::UnsupportedType)))
- ));
- }
-
- #[test]
- fn err_assoc_type_in_unsupported_return_in_opt() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test(&self) -> Option<Foo<Self::A>>;
- })
- .unwrap();
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &Default::default()),
- Err((_, MethodError::Transform(TransformError::UnsupportedType)))
- ));
- }
-
- #[test]
- fn err_assoc_type_in_unsupported_return_in_ok() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test(&self) -> Result<Foo<Self::A>, Error>;
- })
- .unwrap();
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &Default::default()),
- Err((_, MethodError::Transform(TransformError::UnsupportedType)))
- ));
- }
-
- #[test]
- fn err_assoc_type_in_unsupported_return_in_err() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test(&self) -> Result<Ok, Foo<Self::A>>;
- })
- .unwrap();
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &Default::default()),
- Err((_, MethodError::Transform(TransformError::UnsupportedType)))
- ));
- }
-
- #[test]
- fn err_assoc_type_in_input() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test(&self, x: Self::A);
- })
- .unwrap();
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &Default::default()),
- Err((_, MethodError::AssocTypeInInputs))
- ));
- }
-
- #[test]
- fn err_assoc_type_in_input_opt() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test(&self, x: Option<Self::A>);
- })
- .unwrap();
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &Default::default()),
- Err((_, MethodError::AssocTypeInInputs))
- ));
- }
-
- #[test]
- fn err_impl_in_input() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test(&self, arg: Option<impl SomeTrait>);
- })
- .unwrap();
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &Default::default()),
- Err((_, MethodError::ImplTraitInInputs))
- ));
- }
-
- #[test]
- fn err_assoc_type_in_generic() {
- let mut type1: TraitItemMethod = syn::parse2(quote! {
- fn test<F: Fn(Foo<Self::A>)>(&self, fun: F);
- })
- .unwrap();
-
- assert!(matches!(
- parse_trait_signature(&mut type1.sig, &Default::default()),
- Err((_, MethodError::Transform(TransformError::UnsupportedType)))
- ));
- }
-}