diff --git a/src/lib.rs b/src/lib.rs index 5738426..8767b3d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,20 +4,38 @@ mod delegate_to_checker; mod delegate_to_remover; mod generic_param_replacer; mod ident_replacer; -mod punctuated_parser; -mod storage; +mod self_replacer; use crate::delegate_to_arg::DelegateToArg; use crate::generic_param_replacer::GenericParamReplacer; -use crate::punctuated_parser::PunctuatedParser; -use crate::storage::Storage; -use indoc::indoc; -use itertools::Itertools; use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens}; -use syn::parse_macro_input; +use std::ops::Deref; use syn::spanned::Spanned; +fn macro_name_feed_trait_def_for(trait_name: &T, span: Span) -> syn::Ident +where + T: std::fmt::Display, +{ + syn::Ident::new( + &format!("__thin_delegate__feed_trait_def_for_{}", trait_name), + span, + ) +} + +fn macro_name_feed_structenum_def_for(structenum_name: &T, span: Span) -> syn::Ident +where + T: std::fmt::Display, +{ + syn::Ident::new( + &format!( + "__thin_delegate__feed_structenum_def_for_{}", + structenum_name + ), + span, + ) +} + #[derive(Debug)] pub(crate) struct TraitData { trait_path: syn::Path, @@ -25,47 +43,29 @@ pub(crate) struct TraitData { sigs: Vec, } -struct FnIngredient<'a> { - trait_path: &'a syn::Path, - sig: &'a syn::Signature, -} +impl TraitData { + pub fn new(trait_: &syn::ItemTrait, mut trait_path: syn::Path) -> Self { + trait_path.segments.last_mut().unwrap().arguments = syn::PathArguments::None; -#[derive(Debug)] -pub(crate) struct StorableTraitData { - trait_path: String, - generics: String, - sigs: Vec, -} + let sigs = trait_ + .items + .iter() + .filter_map(|x| { + let syn::TraitItem::Fn(fn_) = x else { + return None; + }; -impl From<&TraitData> for StorableTraitData { - fn from(x: &TraitData) -> Self { - Self { - trait_path: x.trait_path.to_token_stream().to_string(), - generics: x.generics.to_token_stream().to_string(), - sigs: x - .sigs - .iter() - .map(|sig| sig.to_token_stream().to_string()) - .collect(), - } - } -} + Some(fn_.sig.clone()) + }) + .collect(); -impl From<&StorableTraitData> for TraitData { - fn from(x: &StorableTraitData) -> Self { - Self { - trait_path: syn::parse2::(x.trait_path.parse().unwrap()).unwrap(), - generics: syn::parse2::(x.generics.parse().unwrap()).unwrap(), - sigs: x - .sigs - .iter() - .map(|sig| syn::parse2::(sig.parse().unwrap()).unwrap()) - .collect(), + TraitData { + trait_path, + generics: trait_.generics.clone(), + sigs, } } -} -impl TraitData { fn fn_ingredients(&self) -> impl Iterator> { self.sigs.iter().map(|sig| FnIngredient { trait_path: &self.trait_path, @@ -82,6 +82,11 @@ impl TraitData { } } +struct FnIngredient<'a> { + trait_path: &'a syn::Path, + sig: &'a syn::Signature, +} + impl<'a> FnIngredient<'a> { pub fn validate(&self) -> syn::Result<()> { self.receiver_prefix()?; @@ -133,161 +138,236 @@ impl<'a> FnIngredient<'a> { #[proc_macro_attribute] pub fn register( args: proc_macro::TokenStream, - input: proc_macro::TokenStream, + item: proc_macro::TokenStream, ) -> proc_macro::TokenStream { - let item = parse_macro_input!(input as syn::Item); - let mut storage = Storage::global(); - - match register_aux(&mut storage, args.into(), &item) { + let item: TokenStream = item.into(); + match register_aux(args.into(), item.clone()) { Ok(x) => x.into(), - Err(e) => TokenStream::from_iter([e.into_compile_error(), (quote! { #item })]).into(), + Err(e) => TokenStream::from_iter([e.into_compile_error(), item]).into(), } } -fn register_aux( - storage: &mut Storage, - args: TokenStream, - item: &syn::Item, -) -> syn::Result { - if args.is_empty() { - return Err(syn::Error::new_spanned( - args, - "arguments must not be empty: `#[thin_delegate::register(, ...)]`", - )); +fn register_aux(args: TokenStream, item: TokenStream) -> syn::Result { + if !args.is_empty() { + return Err(syn::Error::new_spanned(args, "arguments must be empty")); } - let path = syn::parse2::(args.clone()).map_err(|_| { - syn::Error::new_spanned( - args, - "type argument expected: `#[thin_delegate::register(, ...)]`", + let mut item = syn::parse2::(item.clone()).map_err(|_| { + syn::Error::new( + item.span(), + "expected `trait ...` or `struct ...` or `enum ...`", ) })?; - - let syn::Item::Trait(trait_) = item else { - return Err(syn::Error::new(item.span(), "expected `trait ...`")); + let macro_def = match &item { + syn::Item::Trait(trait_) => { + // TODO: Support external crates. + let trait_path = syn::Path::from(syn::PathSegment::from(trait_.ident.clone())); + // Note that `trait_path` here is a kind of dummy. It's just used for creating `TraitData`. + let trait_data = TraitData::new(trait_, trait_path); + trait_data.validate()?; + + let feed_trait_def_for = + macro_name_feed_trait_def_for(&trait_.ident, trait_.ident.span()); + quote! { + macro_rules! #feed_trait_def_for { + { + @KONT { $kont:path }, + $(@$arg_key:ident { $arg_value:tt },)* + } => { + $kont! { + $(@$arg_key { $arg_value },)* + @TRAIT_DEF { #trait_ }, + } + } + } + } + } + syn::Item::Struct(structenum) => { + let feed_structenum_def_for = + macro_name_feed_structenum_def_for(&structenum.ident, structenum.ident.span()); + quote! { + macro_rules! #feed_structenum_def_for { + { + @KONT { $kont:path }, + $(@$arg_key:ident { $arg_value:tt },)* + } => { + $kont! { + $(@$arg_key { $arg_value },)* + @STRUCTENUM_DEF { #structenum }, + } + } + } + } + } + syn::Item::Enum(structenum) => { + let feed_structenum_def_for = + macro_name_feed_structenum_def_for(&structenum.ident, structenum.ident.span()); + quote! { + macro_rules! #feed_structenum_def_for { + { + @KONT { $kont:path }, + $(@$arg_key:ident { $arg_value:tt },)* + } => { + $kont! { + $(@$arg_key { $arg_value },)* + @STRUCTENUM_DEF { #structenum }, + } + } + } + } + } + _ => { + return Err(syn::Error::new_spanned( + item, + "expected `trait ...` or `struct ...` or `enum ...`", + )); + } }; - if path.segments.last().unwrap().arguments != syn::PathArguments::None { - return Err(syn::Error::new_spanned( - path, - "argument must be a path without generic paramteres, like in `use ...`", - )); + #[cfg(not(feature = "unstable_delegate_to"))] + { + delegate_to_checker::check_non_existence(&mut item)?; } + delegate_to_remover::remove_delegate_to(&mut item); - let sigs = trait_ - .items - .iter() - .filter_map(|x| { - let syn::TraitItem::Fn(fn_) = x else { - return None; - }; - - Some(fn_.sig.clone()) - }) - .collect_vec(); - let trait_data = TraitData { - trait_path: path.clone(), - generics: trait_.generics.clone(), - sigs, - }; - trait_data.validate()?; - - storage.store(&path, &trait_data)?; + Ok(quote! { + #item - // TODO: Split `register()` and `register_temporarily()` and return tokens for the former. - Ok(TokenStream::new()) + #macro_def + }) } #[proc_macro_attribute] pub fn derive_delegate( args: proc_macro::TokenStream, - input: proc_macro::TokenStream, + item: proc_macro::TokenStream, ) -> proc_macro::TokenStream { - let input_ = input.clone(); - let item = parse_macro_input!(input_ as syn::Item); - let mut storage = Storage::global(); - - #[cfg(not(feature = "unstable_delegate_to"))] - { - let mut item = item.clone(); - match delegate_to_checker::check_non_existence(&mut item) { - Ok(()) => {} - Err(e) => { - return TokenStream::from_iter([e.into_compile_error(), input.into()]).into(); - } - } - } + let item: TokenStream = item.into(); - match derive_delegate_aux(&mut storage, args.into(), item) { + match derive_delegate_aux(args.into(), item.clone()) { Ok(x) => x.into(), - Err(e) => TokenStream::from_iter([e.into_compile_error(), input.into()]).into(), + Err(e) => TokenStream::from_iter([e.into_compile_error(), item]).into(), } } -fn derive_delegate_aux( - storage: &mut Storage, - args: TokenStream, - // Mutation is allowed only for removing attributes used, e.g. `#[delegate_to(...)]`. - mut item: syn::Item, -) -> syn::Result { - if args.is_empty() { - return Err(syn::Error::new_spanned( - args, - "arguments must not be empty `#[thin_delegate::derive_delegate(, ...)]`", - )); +fn derive_delegate_aux(args: TokenStream, item: TokenStream) -> syn::Result { + if !args.is_empty() { + return Err(syn::Error::new_spanned(args, "arguments must be empty")); } - let paths = syn::parse2::>(args)?.into_inner(); + let e = syn::Error::new_spanned(&item, "expected `impl for `"); + let item = syn::parse2::(item).map_err(|_| e.clone())?; + let syn::Item::Impl(impl_) = item else { + return Err(e); + }; + let Some((_, trait_path, _)) = &impl_.trait_ else { + return Err(e); + }; + let syn::Type::Path(structenum_path) = impl_.self_ty.deref() else { + return Err(e); + }; - let impls = paths - .iter() - .map(|path| derive_delegate_aux_1(storage, &item, path)) - .collect::>>()?; + let trait_ident = &trait_path.segments.last().unwrap().ident; + let structenum_ident = &structenum_path.path.segments.last().unwrap().ident; - // Remove `#[delegate_to(...)]` here, as all calls of `derive_delegate_aux_1()` require the attributes. - delegate_to_remover::remove_delegate_to(&mut item); + let feed_trait_def_for = macro_name_feed_trait_def_for(&trait_ident, trait_ident.span()); + let feed_structenum_def_for = + macro_name_feed_structenum_def_for(&structenum_ident, structenum_ident.span()); + // Collect trait and structenum defs by CPS: + // + // #feed_trait_def_for! + // -> __thin_delegate__trampoline1! + // -> #feed_structenum_def_for! + // -> __thin_delegate__trampoline2! + // -> #[::thin_delegate::internal_derive_delegate] Ok(quote! { - #item + macro_rules! __thin_delegate__trampoline2 { + { + @IMPL {{ $impl:item }}, + @TRAIT_DEF { $trait_def:item }, + @STRUCTENUM_DEF { $structenum_def:item }, + } => { + // TODO: Add a test that uses `#[thin_delegate::derive_delegate]` twice. + #[::thin_delegate::internal_derive_delegate] + mod __thin_delegate__change_this_name { + $trait_def + + $structenum_def + + $impl + } + } + } + + macro_rules! __thin_delegate__trampoline1 { + { + @IMPL {{ $impl:item }}, + @TRAIT_DEF { $trait_def:item }, + } => { + #feed_structenum_def_for! { + @KONT { __thin_delegate__trampoline2 }, + @IMPL {{ $impl }}, + @TRAIT_DEF { $trait_def }, + } + } + } - #(#impls)* + #feed_trait_def_for! { + @KONT { __thin_delegate__trampoline1 }, + @IMPL {{ #impl_ }}, + } }) } -fn derive_delegate_aux_1( - storage: &mut Storage, - item: &syn::Item, - path: &syn::Path, -) -> syn::Result { - let Some(trait_data) = storage.get(path) else { - return Err(syn::Error::new( - Span::call_site(), - format!( - indoc! {r#" - trait not registered: path = {path} - - hint: Add `#[thin_delegate::register({path})]` for trait `{path}` - "#}, - path = path.to_token_stream(), - ), - )); - }; +#[proc_macro_attribute] +pub fn internal_derive_delegate( + args: proc_macro::TokenStream, + input: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + match internal_derive_delegate_aux(args.into(), input.into()) { + Ok(x) => x.into(), + Err(e) => TokenStream::from_iter([e.into_compile_error()]).into(), + } +} - if trait_data.sigs.is_empty() { - return Ok(quote! {}); +fn internal_derive_delegate_aux(args: TokenStream, item: TokenStream) -> syn::Result { + if !args.is_empty() { + panic!(); } + let item = syn::parse2::(item.clone()).unwrap(); + let syn::Item::Mod(mod_) = item else { + panic!(); + }; + let content = &mod_.content.as_ref().unwrap().1; + assert_eq!(content.len(), 3); + let syn::Item::Trait(trait_) = &content[0] else { + panic!(); + }; + let structenum = &content[1]; + let syn::Item::Impl(impl_) = &content[2] else { + panic!(); + }; + // TODO: Support exceptional methods. + assert!(impl_.items.is_empty()); + let Some((_, trait_path, _)) = &impl_.trait_ else { + panic!() + }; + + let trait_data = TraitData::new(trait_, trait_path.clone()); + let generic_param_replacer = GenericParamReplacer::new( &trait_data.generics, - &path.segments.last().unwrap().arguments, + &trait_path.segments.last().unwrap().arguments, )?; let funcs = trait_data .fn_ingredients() - .map(|fn_ingredient| gen_impl_fn(&generic_param_replacer, item, fn_ingredient)) + .map(|fn_ingredient| gen_impl_fn(&generic_param_replacer, structenum, fn_ingredient)) .collect::>>()?; - let item_name = match item { + let item_name = match &structenum { syn::Item::Enum(enum_) => { let ident = &enum_.ident; let generics = &enum_.generics; @@ -300,14 +380,14 @@ fn derive_delegate_aux_1( } _ => { return Err(syn::Error::new( - item.span(), + structenum.span(), "expected `enum ...` or `struct ...`", )); } }; Ok(quote! { - impl #path for #item_name { + impl #trait_path for #item_name { #(#funcs)* } }) @@ -410,6 +490,7 @@ fn gen_impl_fn_enum( .collect::>>()?; let sig = generic_param_replacer.replace_signature(fn_ingredient.sig.clone()); + let sig = self_replacer::make_self_hygienic_in_signature(sig); Ok(quote! { #sig { match self { @@ -441,6 +522,7 @@ fn gen_impl_fn_struct( let receiver = quote! { #receiver_prefix self.#field_ident }; let sig = generic_param_replacer.replace_signature(fn_ingredient.sig.clone()); + let sig = self_replacer::make_self_hygienic_in_signature(sig); let trait_path = &fn_ingredient.trait_path; let method_ident = &fn_ingredient.sig.ident; let args = fn_ingredient.args(); @@ -454,7 +536,6 @@ fn gen_impl_fn_struct( #[cfg(test)] mod tests { use super::*; - use crate::storage::TestStorageFactory; macro_rules! compare_result { ($got:expr, $expected:expr) => { @@ -466,139 +547,47 @@ mod tests { }; } - macro_rules! test_register_derive_delegate { - ( - $test_name:ident, - $register_args:expr, - $register_input:expr, - $register_expected:expr, - $derive_delegate_args:expr, - $derive_delegate_input:expr, - $derive_delegate_expected:expr, - ) => { - #[test] - fn $test_name() -> Result<(), syn::Error> { - let mut factory = TestStorageFactory::new(); - let mut storage = factory.factory(); - - let args = $register_args; - let input = $register_input; - compare_result!( - register_aux(&mut storage, args, &syn::parse2::(input)?), - Ok($register_expected) - ); - - let args = $derive_delegate_args; - let input = $derive_delegate_input; - compare_result!( - derive_delegate_aux(&mut storage, args, syn::parse2::(input)?), - Ok($derive_delegate_expected) - ); - - Ok(()) - } - }; - } - - macro_rules! test_register_register_derive_delegate { + macro_rules! test_internal_derive_delegate { ( $test_name:ident, - $register1_args:expr, - $register1_input:expr, - $register1_expected:expr, - $register2_args:expr, - $register2_input:expr, - $register2_expected:expr, - $derive_delegate_args:expr, - $derive_delegate_input:expr, - $derive_delegate_expected:expr, + $input:expr, + $expected:expr, ) => { #[test] - fn $test_name() -> Result<(), syn::Error> { - let mut factory = TestStorageFactory::new(); - let mut storage = factory.factory(); - - let args = $register1_args; - let input = $register1_input; - compare_result!( - register_aux(&mut storage, args, &syn::parse2::(input)?), - Ok($register1_expected) - ); - - let args = $register2_args; - let input = $register2_input; - compare_result!( - register_aux(&mut storage, args, &syn::parse2::(input)?), - Ok($register2_expected) - ); - - let args = $derive_delegate_args; - let input = $derive_delegate_input; - compare_result!( - derive_delegate_aux(&mut storage, args, syn::parse2::(input)?), - Ok($derive_delegate_expected) - ); + fn $test_name() -> syn::Result<()> { + let args = TokenStream::new(); + let input: TokenStream = $input; + let expected: TokenStream = $expected; + + let input = quote! { + mod __thin_delegate__test_mod { + #input + } + }; + compare_result!(internal_derive_delegate_aux(args, input), Ok(expected)); Ok(()) } }; } - macro_rules! test_as_ref { - ( - $test_name:ident, - $derive_delegate_args:expr, - $derive_delegate_input:expr, - $derive_delegate_expected:expr, - ) => { - test_register_derive_delegate! { - $test_name, - // register - quote! { AsRef }, - quote! { - pub trait AsRef { - /// Converts this type into a shared reference of the (usually inferred) input type. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_ref(&self) -> &T; - } - }, - quote! {}, - // derive_delegate - $derive_delegate_args, - $derive_delegate_input, - $derive_delegate_expected, - } - }; - } - - test_register_derive_delegate! { + test_internal_derive_delegate! { r#enum, - // register - quote! { Hello }, quote! { - pub trait Hello { + trait Hello { fn hello(&self) -> String; } - }, - quote! {}, - // derive_delegate - quote! { Hello }, - quote! { + enum Hoge { Named { named: String, }, Unnamed(char), } + + impl Hello for Hoge {} }, quote! { - enum Hoge { - Named { - named: String, - }, - Unnamed(char), - } - impl Hello for Hoge { fn hello(&self) -> String { match self { @@ -610,98 +599,76 @@ mod tests { }, } - test_register_derive_delegate! { + test_internal_derive_delegate! { enum_ref_mut_receiver, - // register - quote! { Hello }, quote! { pub trait Hello { fn hello(&mut self) -> String; } - }, - quote! {}, - // derive_delegate - quote! { Hello }, - quote! { + enum Hoge { - A(String), - B(char), + Named { + named: String, + }, + Unnamed(char), } + + impl Hello for Hoge {} }, quote! { - enum Hoge { - A(String), - B(char), - } - impl Hello for Hoge { fn hello(&mut self) -> String { match self { - Self::A(x) => Hello::hello(x), - Self::B(x) => Hello::hello(x), + Self::Named { named } => Hello::hello(named), + Self::Unnamed(x) => Hello::hello(x), } } } }, } - test_register_derive_delegate! { + test_internal_derive_delegate! { enum_consume_receiver, - // register - quote! { Hello }, quote! { - pub trait Hello { + trait Hello { fn hello(self) -> String; } - }, - quote! {}, - // derive_delegate - quote! { Hello }, - quote! { + enum Hoge { - A(String), - B(char), + Named { + named: String, + }, + Unnamed(char), } + + impl Hello for Hoge {} }, quote! { - enum Hoge { - A(String), - B(char), - } - impl Hello for Hoge { fn hello(self) -> String { match self { - Self::A(x) => Hello::hello(x), - Self::B(x) => Hello::hello(x), + Self::Named { named } => Hello::hello(named), + Self::Unnamed(x) => Hello::hello(x), } } } }, } - test_register_derive_delegate! { + test_internal_derive_delegate! { struct_with_named_field, - // register - quote! { Hello }, quote! { - pub trait Hello { + trait Hello { fn hello(&self) -> String; } - }, - quote! {}, - // derive_delegate - quote! { Hello }, - quote! { + struct Hoge { s: String, } + + impl Hello for Hoge {} }, quote! { - struct Hoge { - s: String, - } - impl Hello for Hoge { fn hello(&self) -> String { Hello::hello(&self.s) @@ -710,24 +677,18 @@ mod tests { }, } - test_register_derive_delegate! { + test_internal_derive_delegate! { struct_with_unnamed_field, - // register - quote! { Hello }, quote! { - pub trait Hello { + trait Hello { fn hello(&self) -> String; } - }, - quote! {}, - // derive_delegate - quote! { Hello }, - quote! { + struct Hoge(String); + + impl Hello for Hoge {} }, quote! { - struct Hoge(String); - impl Hello for Hoge { fn hello(&self) -> String { Hello::hello(&self.0) @@ -736,28 +697,20 @@ mod tests { }, } - test_register_derive_delegate! { + test_internal_derive_delegate! { struct_ref_mut_receiver, - // register - quote! { Hello }, quote! { - pub trait Hello { + trait Hello { fn hello(&mut self) -> String; } - }, - quote! {}, - // derive_delegate - quote! { Hello }, - quote! { + struct Hoge { s: String, } + + impl Hello for Hoge {} }, quote! { - struct Hoge { - s: String, - } - impl Hello for Hoge { fn hello(&mut self) -> String { Hello::hello(&mut self.s) @@ -766,28 +719,20 @@ mod tests { }, } - test_register_derive_delegate! { + test_internal_derive_delegate! { struct_consume_receiver, - // register - quote! { Hello }, quote! { - pub trait Hello { + trait Hello { fn hello(self) -> String; } - }, - quote! {}, - // derive_delegate - quote! { Hello }, - quote! { + struct Hoge { s: String, } + + impl Hello for Hoge {} }, quote! { - struct Hoge { - s: String, - } - impl Hello for Hoge { fn hello(self) -> String { Hello::hello(self.s) @@ -796,30 +741,21 @@ mod tests { }, } - test_register_derive_delegate! { + test_internal_derive_delegate! { method_with_args, - // register - quote! { Hello }, quote! { - pub trait Hello { + trait Hello { fn hello(&self, prefix: &str) -> String; } - }, - quote! {}, - // derive_delegate - quote! { Hello }, - quote! { + enum Hoge { A(String), B(char), } + + impl Hello for Hoge {} }, quote! { - enum Hoge { - A(String), - B(char), - } - impl Hello for Hoge { fn hello(&self, prefix: &str) -> String { match self { @@ -831,30 +767,21 @@ mod tests { }, } - test_register_derive_delegate! { - super_crate, - // register - quote! { Hello }, + test_internal_derive_delegate! { + super_trait, quote! { - pub trait Hello: ToString { + trait Hello: ToString { fn hello(&self) -> String; } - }, - quote! {}, - // derive_delegate - quote! { Hello }, - quote! { + enum Hoge { A(String), B(char), } + + impl Hello for Hoge {} }, quote! { - enum Hoge { - A(String), - B(char), - } - impl Hello for Hoge { fn hello(&self) -> String { match self { @@ -866,87 +793,23 @@ mod tests { }, } - test_register_register_derive_delegate! { - multiple_derive, - // register - quote! { ToString }, + test_internal_derive_delegate! { + generics_enum, quote! { - pub trait ToString { - /// Converts the given value to a `String`. - /// - /// # Examples - /// - /// ``` - /// let i = 5; - /// let five = String::from("5"); - /// - /// assert_eq!(five, i.to_string()); - /// ``` - #[rustc_conversion_suggestion] + pub trait AsRef { + /// Converts this type into a shared reference of the (usually inferred) input type. #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "to_string_method")] - fn to_string(&self) -> String; - } - }, - quote! {}, - // register - quote! { Hello }, - quote! { - pub trait Hello: ToString { - fn hello(&self) -> String; - } - }, - quote! {}, - // derive_delegate - quote! { ToString, Hello }, - quote! { - enum Hoge { - A(String), - B(char), - } - }, - quote! { - enum Hoge { - A(String), - B(char), - } - - impl ToString for Hoge { - fn to_string(&self) -> String { - match self { - Self::A(x) => ToString::to_string(x), - Self::B(x) => ToString::to_string(x), - } - } - } - - impl Hello for Hoge { - fn hello(&self) -> String { - match self { - Self::A(x) => Hello::hello(x), - Self::B(x) => Hello::hello(x), - } - } + fn as_ref(&self) -> &T; } - }, - } - test_as_ref! { - generics_enum, - // derive_delegate - quote! { AsRef }, - quote! { enum Hoge { A(String), B(char), } + + impl AsRef for Hoge {} }, quote! { - enum Hoge { - A(String), - B(char), - } - impl AsRef for Hoge { fn as_ref(&self) -> &str { match self { @@ -958,20 +821,22 @@ mod tests { }, } - test_as_ref! { + test_internal_derive_delegate! { generics_struct, - // derive_delegate - quote! { AsRef }, quote! { - struct Hoge { - s: String, + pub trait AsRef { + /// Converts this type into a shared reference of the (usually inferred) input type. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_ref(&self) -> &T; } - }, - quote! { + struct Hoge { s: String, } + impl AsRef for Hoge {} + }, + quote! { impl AsRef for Hoge { fn as_ref(&self) -> &str { AsRef::as_ref(&self.s) @@ -980,16 +845,20 @@ mod tests { }, } - test_as_ref! { + test_internal_derive_delegate! { generics_specilize_complex, - // derive_delegate - quote! { AsRef<(dyn Fn(usize) -> usize + 'static)> }, quote! { + pub trait AsRef { + /// Converts this type into a shared reference of the (usually inferred) input type. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_ref(&self) -> &T; + } + struct Hoge(Box usize>); + + impl AsRef<(dyn Fn(usize) -> usize + 'static)> for Hoge {} }, quote! { - struct Hoge(Box usize>); - impl AsRef<(dyn Fn(usize) -> usize + 'static)> for Hoge { fn as_ref(&self) -> &(dyn Fn(usize) -> usize + 'static) { AsRef::as_ref(&self.0) @@ -998,24 +867,18 @@ mod tests { }, } - test_register_derive_delegate! { + test_internal_derive_delegate! { generics_specilize_lifetime, - // register - quote! { Hello }, quote! { pub trait Hello<'a, T> { fn hello(&self) -> &'a T; } - }, - quote! {}, - // derive_delegate - quote! { Hello<'p, str> }, - quote! { + struct Hoge<'p>(&'p str); + + impl Hello<'p, str> for Hoge<'p> {} }, quote! { - struct Hoge<'p>(&'p str); - impl Hello<'p, str> for Hoge<'p> { fn hello(&self) -> &'p str { Hello::hello(&self.0) @@ -1024,21 +887,23 @@ mod tests { }, } - test_as_ref! { + test_internal_derive_delegate! { custom_receiver, - // derive_delegate - quote! { AsRef }, quote! { + pub trait AsRef { + /// Converts this type into a shared reference of the (usually inferred) input type. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_ref(&self) -> &T; + } + enum Hoge { #[delegate_to(x => &x.0)] A((String, u8)), } + + impl AsRef for Hoge {} }, quote! { - enum Hoge { - A((String, u8)), - } - impl AsRef for Hoge { fn as_ref(&self) -> &str { match self { diff --git a/src/punctuated_parser.rs b/src/punctuated_parser.rs deleted file mode 100644 index 13b5ac5..0000000 --- a/src/punctuated_parser.rs +++ /dev/null @@ -1,20 +0,0 @@ -pub(crate) struct PunctuatedParser { - inner: syn::punctuated::Punctuated, -} - -impl PunctuatedParser { - pub fn into_inner(self) -> syn::punctuated::Punctuated { - self.inner - } -} - -impl syn::parse::Parse for PunctuatedParser -where - T: syn::parse::Parse, - P: syn::parse::Parse, -{ - fn parse(input: &syn::parse::ParseBuffer) -> Result { - let inner = syn::punctuated::Punctuated::parse_terminated(input)?; - Ok(Self { inner }) - } -} diff --git a/src/self_replacer.rs b/src/self_replacer.rs new file mode 100644 index 0000000..09b8d3d --- /dev/null +++ b/src/self_replacer.rs @@ -0,0 +1,41 @@ +use proc_macro2::Span; +use syn::visit_mut::VisitMut; + +pub(crate) fn make_self_hygienic_in_signature(mut target: syn::Signature) -> syn::Signature { + let mut visitor = Visitor; + visitor.visit_signature_mut(&mut target); + target +} + +/// Replaces `self` to avoid issues around macro hygienicity. +/// +/// `thin_delegate` transfers definition of a trait and a struct/enum to +/// `#[thin_delegate::derive_delegate]` by using declarative macro. +/// `#[thin_delegate::internal_derive_delegate]` processes a token stream in the macro context. +/// If we use `self` in this token stream as is, an error like the following arise: +/// +/// ```ignore +/// error[E0424]: expected value, found module `self` +/// --> src/main.rs:24:1 +/// | +/// 3 | fn hello(&self) -> String; +/// | -- this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters +/// ... +/// 24 | #[thin_delegate::derive_delegate] +/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self` value is a keyword only available in methods with a `self` parameter +/// | +/// = note: this error originates in the attribute macro `::thin_delegate::internal_derive_delegate` which comes from the expansion of the attribute macro `thin_delegate::derive_delegate` (in Nightly builds, run with -Z macro-backtrace for more info) +/// For more information about this error, try `rustc --explain E0424`. +/// ``` +/// +/// Rust's macro hygienicity forbids use of `self` in declarative macros. +/// We can resolve it by replacing `self` in the token stream by `self` generated in a proc macro, +/// which this `Visitor` does. +struct Visitor; + +impl VisitMut for Visitor { + // We only replaces `self` in receiver position, as we need it for `syn::Signature`. + fn visit_receiver_mut(&mut self, node: &mut syn::Receiver) { + node.self_token = syn::Token![self](Span::call_site()); + } +} diff --git a/src/storage.rs b/src/storage.rs deleted file mode 100644 index b21f122..0000000 --- a/src/storage.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::{StorableTraitData, TraitData}; -use quote::ToTokens; -use std::collections::HashMap; -use std::sync::{Arc, LazyLock, Mutex}; - -#[derive(Debug, PartialEq, Eq, Hash)] -struct Key(String); - -impl Key { - fn new(path: &syn::Path) -> Self { - let mut path = path.clone(); - path.segments.last_mut().unwrap().arguments = syn::PathArguments::None; - - Self(path.to_token_stream().to_string()) - } -} - -impl From<&syn::Path> for Key { - fn from(path: &syn::Path) -> Self { - Key::new(path) - } -} - -/// Store information that in necessary to pass from `register()` to `derive_delegate()`. -pub(crate) struct Storage { - path_to_trait_data: Arc>>, -} - -impl core::fmt::Debug for Storage { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - let map = self.path_to_trait_data.lock().unwrap(); - map.fmt(f) - } -} - -#[allow(clippy::type_complexity)] -static STORAGE: LazyLock>>> = - LazyLock::new(|| Arc::new(Mutex::new(HashMap::new()))); - -impl Storage { - /// Acquire an accessor to compile-time global storage. - pub fn global() -> Self { - Self { - path_to_trait_data: LazyLock::force(&STORAGE).clone(), - } - } - - pub fn store(&mut self, path: &syn::Path, trait_data: &TraitData) -> syn::Result<()> { - let key = path.into(); - let mut map = self.path_to_trait_data.lock().unwrap(); - - if map.contains_key(&key) { - return Err(syn::Error::new_spanned( - path, - format!( - "type name conflicted, arleady registered: path = {path}", - path = path.to_token_stream(), - ), - )); - } - - map.insert(key, trait_data.into()); - - Ok(()) - } - - pub fn get(&mut self, path: &syn::Path) -> Option { - let key = path.into(); - let map = self.path_to_trait_data.lock().unwrap(); - let trait_data = map.get(&key)?.into(); - Some(trait_data) - } -} - -#[cfg(test)] -mod test_storage { - use super::*; - - pub(crate) struct TestStorageFactory { - path_to_trait_data: Arc>>, - } - - impl TestStorageFactory { - pub fn new() -> Self { - Self { - path_to_trait_data: Arc::new(Mutex::new(HashMap::new())), - } - } - - pub fn factory(&mut self) -> Storage { - Storage { - path_to_trait_data: self.path_to_trait_data.clone(), - } - } - } -} - -#[cfg(test)] -pub(crate) use test_storage::TestStorageFactory; diff --git a/tests/ui.old/fail_num_of_generic_parameters_differ.stderr b/tests/ui.old/fail_num_of_generic_parameters_differ.stderr deleted file mode 100644 index 98d363b..0000000 --- a/tests/ui.old/fail_num_of_generic_parameters_differ.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error: number of generic parameters must coinside: - in definition of trait = < T > - in definition of derive target = < u8, u16 > - --> tests/ui/fail_num_of_generic_parameters_differ.rs:25:39 - | -25 | #[thin_delegate::derive_delegate(Hello)] - | ^^^^^^^^^ diff --git a/tests/ui.old/fail_parameter_cant_substituted_to_argument.rs b/tests/ui.old/fail_parameter_cant_substituted_to_argument.rs deleted file mode 100644 index 09d26c7..0000000 --- a/tests/ui.old/fail_parameter_cant_substituted_to_argument.rs +++ /dev/null @@ -1,16 +0,0 @@ -trait Hello<'a, T> { - fn hello(&self) -> &'a T; -} - -// TODO: Make `register()` is usable for trait definition. -mod private_for_thin_delegate { - #[thin_delegate::register(Hello)] - trait Hello<'a, T> { - fn hello(&self) -> &'a T; - } -} - -#[thin_delegate::derive_delegate(Hello)] -struct Hoge; - -fn main() {} diff --git a/tests/ui.old/fail_parameter_cant_substituted_to_argument.stderr b/tests/ui.old/fail_parameter_cant_substituted_to_argument.stderr deleted file mode 100644 index f47e064..0000000 --- a/tests/ui.old/fail_parameter_cant_substituted_to_argument.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error: parameter can't be substituted to argument: - in definition of trait = < 'a, T > - in definition of derive target = < String, String > - --> tests/ui/fail_parameter_cant_substituted_to_argument.rs:13:40 - | -13 | #[thin_delegate::derive_delegate(Hello)] - | ^^^^^^ diff --git a/tests/ui.old/fail_register_conflicted.rs b/tests/ui.old/fail_register_conflicted.rs deleted file mode 100644 index 6ace7ec..0000000 --- a/tests/ui.old/fail_register_conflicted.rs +++ /dev/null @@ -1,17 +0,0 @@ -mod external { - #[thin_delegate::register(external::Hello)] - pub trait Hello { - fn hello(&self, prefix: &str) -> String; - } -} - -mod user { - mod private_for_thin_delegate { - #[thin_delegate::register(external::Hello)] - pub trait Hello { - fn hello(&self, prefix: &str) -> String; - } - } -} - -fn main() {} diff --git a/tests/ui.old/fail_register_conflicted.stderr b/tests/ui.old/fail_register_conflicted.stderr deleted file mode 100644 index 0e52cb4..0000000 --- a/tests/ui.old/fail_register_conflicted.stderr +++ /dev/null @@ -1,5 +0,0 @@ -error: type name conflicted, arleady registered: path = external :: Hello - --> tests/ui/fail_register_conflicted.rs:10:35 - | -10 | #[thin_delegate::register(external::Hello)] - | ^^^^^^^^^^^^^^^ diff --git a/tests/ui.old/fail_register_missing.rs b/tests/ui.old/fail_register_missing.rs deleted file mode 100644 index 78aa0a4..0000000 --- a/tests/ui.old/fail_register_missing.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[thin_delegate::derive_delegate(ToString)] -enum Hoge { - A(String), - B(char), -} - -fn main() {} diff --git a/tests/ui.old/fail_register_missing.stderr b/tests/ui.old/fail_register_missing.stderr deleted file mode 100644 index 012073c..0000000 --- a/tests/ui.old/fail_register_missing.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error: trait not registered: path = ToString - - hint: Add `#[thin_delegate::register(ToString)]` for trait `ToString` - --> tests/ui/fail_register_missing.rs:1:1 - | -1 | #[thin_delegate::derive_delegate(ToString)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `thin_delegate::derive_delegate` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui.old/pass_generics_specialize_complex.rs b/tests/ui.old/pass_generics_specialize_complex.rs deleted file mode 100644 index 2894bd3..0000000 --- a/tests/ui.old/pass_generics_specialize_complex.rs +++ /dev/null @@ -1,14 +0,0 @@ -// TODO: Make `register()` is usable for trait definition. -mod private_for_thin_delegate { - #[thin_delegate::register(AsRef)] - pub trait AsRef { - /// Converts this type into a shared reference of the (usually inferred) input type. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_ref(&self) -> &T; - } -} - -#[thin_delegate::derive_delegate(AsRef<(dyn Fn(usize) -> usize + 'static)>)] -struct Hoge(Box usize>); - -fn main() {} diff --git a/tests/ui.old/pass_multiple_derive.rs b/tests/ui.old/pass_multiple_derive.rs deleted file mode 100644 index 5292fe1..0000000 --- a/tests/ui.old/pass_multiple_derive.rs +++ /dev/null @@ -1,55 +0,0 @@ -pub trait Hello: ToString { - fn hello(&self) -> String; -} - -impl Hello for String { - fn hello(&self) -> String { - format!("hello, {}", &self.to_string()) - } -} - -impl Hello for char { - fn hello(&self) -> String { - format!("hello, {}", &self.to_string()) - } -} - -// TODO: Make `register()` is usable for trait definition. -mod private_for_thin_delegate { - #[thin_delegate::register(ToString)] - pub trait ToString { - /// Converts the given value to a `String`. - /// - /// # Examples - /// - /// ``` - /// let i = 5; - /// let five = String::from("5"); - /// - /// assert_eq!(five, i.to_string()); - /// ``` - #[rustc_conversion_suggestion] - #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "to_string_method")] - fn to_string(&self) -> String; - } - - #[thin_delegate::register(Hello)] - pub trait Hello: ToString { - fn hello(&self) -> String; - } -} - -#[thin_delegate::derive_delegate(ToString, Hello)] -enum Hoge { - A(String), - B(char), -} - -fn main() { - let hoge = Hoge::A("a".to_string()); - assert_eq!(hoge.hello(), "hello, a"); - - let hoge = Hoge::B('b'); - assert_eq!(hoge.hello(), "hello, b"); -} diff --git a/tests/ui/_pass_generics_specialize_complex.rs b/tests/ui/_pass_generics_specialize_complex.rs new file mode 100644 index 0000000..ffc695b --- /dev/null +++ b/tests/ui/_pass_generics_specialize_complex.rs @@ -0,0 +1,15 @@ +// TODO: Support external crates. +#[thin_delegate::register] +pub trait AsRef { + /// Converts this type into a shared reference of the (usually inferred) input type. + #[stable(feature = "rust1", since = "1.0.0")] + fn as_ref(&self) -> &T; +} + +#[thin_delegate::register] +struct Hoge(Box usize>); + +#[thin_delegate::derive_delegate] +impl AsRef<(dyn Fn(usize) -> usize + 'static)> for Hoge {} + +fn main() {} diff --git a/tests/ui/_pass_multiple_derive.rs b/tests/ui/_pass_multiple_derive.rs new file mode 100644 index 0000000..fd2ea6e --- /dev/null +++ b/tests/ui/_pass_multiple_derive.rs @@ -0,0 +1,55 @@ +// TODO: Support external crates. +#[thin_delegate::register] +pub trait ToString { + /// Converts the given value to a `String`. + /// + /// # Examples + /// + /// ``` + /// let i = 5; + /// let five = String::from("5"); + /// + /// assert_eq!(five, i.to_string()); + /// ``` + #[rustc_conversion_suggestion] + #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(not(test), rustc_diagnostic_item = "to_string_method")] + fn to_string(&self) -> String; +} + +#[thin_delegate::register] +pub trait Hello: ToString { + fn hello(&self) -> String; +} + +impl Hello for String { + fn hello(&self) -> String { + format!("hello, {}", &self.to_string()) + } +} + +impl Hello for char { + fn hello(&self) -> String { + format!("hello, {}", &self.to_string()) + } +} + +#[thin_delegate::register] +enum Hoge { + A(String), + B(char), +} + +#[thin_delegate::derive_delegate] +impl ToString for Hoge {} + +#[thin_delegate::derive_delegate] +impl Hello for Hoge {} + +fn main() { + let hoge = Hoge::A("a".to_string()); + assert_eq!(hoge.hello(), "hello, a"); + + let hoge = Hoge::B('b'); + assert_eq!(hoge.hello(), "hello, b"); +} diff --git a/tests/ui/fail_derive_delegate_for_impl_without_trait.rs b/tests/ui/fail_derive_delegate_for_impl_without_trait.rs new file mode 100644 index 0000000..31dc6bf --- /dev/null +++ b/tests/ui/fail_derive_delegate_for_impl_without_trait.rs @@ -0,0 +1,7 @@ +#[thin_delegate::register] +struct Hoge(String); + +#[thin_delegate::derive_delegate] +impl Hoge {} + +fn main() {} diff --git a/tests/ui/fail_derive_delegate_for_impl_without_trait.stderr b/tests/ui/fail_derive_delegate_for_impl_without_trait.stderr new file mode 100644 index 0000000..fe42645 --- /dev/null +++ b/tests/ui/fail_derive_delegate_for_impl_without_trait.stderr @@ -0,0 +1,5 @@ +error: expected `impl for ` + --> tests/ui/fail_derive_delegate_for_impl_without_trait.rs:5:1 + | +5 | impl Hoge {} + | ^^^^^^^^^^^^ diff --git a/tests/ui.old/fail_num_of_generic_parameters_differ.rs b/tests/ui/fail_num_of_generic_parameters_differ.rs similarity index 56% rename from tests/ui.old/fail_num_of_generic_parameters_differ.rs rename to tests/ui/fail_num_of_generic_parameters_differ.rs index 19056f2..982aebe 100644 --- a/tests/ui.old/fail_num_of_generic_parameters_differ.rs +++ b/tests/ui/fail_num_of_generic_parameters_differ.rs @@ -1,3 +1,4 @@ +#[thin_delegate::register] pub trait Hello { fn hello(&self) -> String; } @@ -14,18 +15,13 @@ impl Hello for char { } } -// TODO: Make `register()` is usable for trait definition. -mod private_for_thin_delegate { - #[thin_delegate::register(Hello)] - pub trait Hello { - fn hello(&self) -> String; - } -} - -#[thin_delegate::derive_delegate(Hello)] +#[thin_delegate::register] enum Hoge { A(String), B(char), } +#[thin_delegate::derive_delegate] +impl Hello for Hoge {} + fn main() {} diff --git a/tests/ui/fail_num_of_generic_parameters_differ.stderr b/tests/ui/fail_num_of_generic_parameters_differ.stderr new file mode 100644 index 0000000..d061870 --- /dev/null +++ b/tests/ui/fail_num_of_generic_parameters_differ.stderr @@ -0,0 +1,7 @@ +error: number of generic parameters must coinside: + in definition of trait = < T > + in definition of derive target = < u8, u16 > + --> tests/ui/fail_num_of_generic_parameters_differ.rs:25:11 + | +25 | impl Hello for Hoge {} + | ^^^^^^^^^ diff --git a/tests/ui/fail_parameter_cant_substituted_to_argument.rs b/tests/ui/fail_parameter_cant_substituted_to_argument.rs new file mode 100644 index 0000000..68d703a --- /dev/null +++ b/tests/ui/fail_parameter_cant_substituted_to_argument.rs @@ -0,0 +1,12 @@ +#[thin_delegate::register] +trait Hello<'a, T> { + fn hello(&self) -> &'a T; +} + +#[thin_delegate::register] +struct Hoge; + +#[thin_delegate::derive_delegate] +impl Hello for Hoge {} + +fn main() {} diff --git a/tests/ui/fail_parameter_cant_substituted_to_argument.stderr b/tests/ui/fail_parameter_cant_substituted_to_argument.stderr new file mode 100644 index 0000000..f40ae1e --- /dev/null +++ b/tests/ui/fail_parameter_cant_substituted_to_argument.stderr @@ -0,0 +1,7 @@ +error: parameter can't be substituted to argument: + in definition of trait = < 'a, T > + in definition of derive target = < String, String > + --> tests/ui/fail_parameter_cant_substituted_to_argument.rs:10:12 + | +10 | impl Hello for Hoge {} + | ^^^^^^ diff --git a/tests/ui/fail_register_for_invalid_item.rs b/tests/ui/fail_register_for_invalid_item.rs new file mode 100644 index 0000000..9781f75 --- /dev/null +++ b/tests/ui/fail_register_for_invalid_item.rs @@ -0,0 +1,6 @@ +#[thin_delegate::register] +fn hoge() -> bool { + true +} + +fn main() {} diff --git a/tests/ui/fail_register_for_invalid_item.stderr b/tests/ui/fail_register_for_invalid_item.stderr new file mode 100644 index 0000000..8959ca2 --- /dev/null +++ b/tests/ui/fail_register_for_invalid_item.stderr @@ -0,0 +1,7 @@ +error: expected `trait ...` or `struct ...` or `enum ...` + --> tests/ui/fail_register_for_invalid_item.rs:2:1 + | +2 | / fn hoge() -> bool { +3 | | true +4 | | } + | |_^ diff --git a/tests/ui/fail_register_for_trait_missing.rs b/tests/ui/fail_register_for_trait_missing.rs new file mode 100644 index 0000000..3e13ddb --- /dev/null +++ b/tests/ui/fail_register_for_trait_missing.rs @@ -0,0 +1,10 @@ +#[thin_delegate::register] +enum Hoge { + A(String), + B(char), +} + +#[thin_delegate::derive_delegate] +impl ToString for Hoge {} + +fn main() {} diff --git a/tests/ui/fail_register_for_trait_missing.stderr b/tests/ui/fail_register_for_trait_missing.stderr new file mode 100644 index 0000000..ac5735a --- /dev/null +++ b/tests/ui/fail_register_for_trait_missing.stderr @@ -0,0 +1,8 @@ +error: cannot find macro `__thin_delegate__feed_trait_def_for_ToString` in this scope + --> tests/ui/fail_register_for_trait_missing.rs:8:6 + | +1 | #[thin_delegate::register] + | -------------------------- similarly named macro `__thin_delegate__feed_structenum_def_for_Hoge` defined here +... +8 | impl ToString for Hoge {} + | ^^^^^^^^ help: a macro with a similar name exists: `__thin_delegate__feed_structenum_def_for_Hoge` diff --git a/tests/ui.old/pass_enum.rs b/tests/ui/pass_enum.rs similarity index 66% rename from tests/ui.old/pass_enum.rs rename to tests/ui/pass_enum.rs index f942143..9eaba4e 100644 --- a/tests/ui.old/pass_enum.rs +++ b/tests/ui/pass_enum.rs @@ -1,3 +1,4 @@ +#[thin_delegate::register] pub trait Hello { fn hello(&self) -> String; } @@ -14,20 +15,15 @@ impl Hello for char { } } -// TODO: Make `register()` is usable for trait definition. -mod private_for_thin_delegate { - #[thin_delegate::register(Hello)] - pub trait Hello { - fn hello(&self) -> String; - } -} - -#[thin_delegate::derive_delegate(Hello)] +#[thin_delegate::register] enum Hoge { A(String), B(char), } +#[thin_delegate::derive_delegate] +impl Hello for Hoge {} + fn main() { let hoge = Hoge::A("a".to_string()); assert_eq!(hoge.hello(), "hello, a"); diff --git a/tests/ui.old/pass_enum_consume_receiver.rs b/tests/ui/pass_enum_consume_receiver.rs similarity index 66% rename from tests/ui.old/pass_enum_consume_receiver.rs rename to tests/ui/pass_enum_consume_receiver.rs index 147afa8..f71014c 100644 --- a/tests/ui.old/pass_enum_consume_receiver.rs +++ b/tests/ui/pass_enum_consume_receiver.rs @@ -1,3 +1,4 @@ +#[thin_delegate::register] pub trait Hello { fn hello(self) -> String; } @@ -14,20 +15,15 @@ impl Hello for char { } } -// TODO: Make `register()` is usable for trait definition. -mod private_for_thin_delegate { - #[thin_delegate::register(Hello)] - pub trait Hello { - fn hello(self) -> String; - } -} - -#[thin_delegate::derive_delegate(Hello)] +#[thin_delegate::register] enum Hoge { A(String), B(char), } +#[thin_delegate::derive_delegate] +impl Hello for Hoge {} + fn main() { let hoge = Hoge::A("a".to_string()); assert_eq!(hoge.hello(), "hello, a"); diff --git a/tests/ui.old/pass_enum_ref_mut_receiver.rs b/tests/ui/pass_enum_ref_mut_receiver.rs similarity index 66% rename from tests/ui.old/pass_enum_ref_mut_receiver.rs rename to tests/ui/pass_enum_ref_mut_receiver.rs index 2ea0809..1327bfd 100644 --- a/tests/ui.old/pass_enum_ref_mut_receiver.rs +++ b/tests/ui/pass_enum_ref_mut_receiver.rs @@ -1,3 +1,4 @@ +#[thin_delegate::register] pub trait Hello { fn hello(&mut self) -> String; } @@ -14,20 +15,15 @@ impl Hello for char { } } -// TODO: Make `register()` is usable for trait definition. -mod private_for_thin_delegate { - #[thin_delegate::register(Hello)] - pub trait Hello { - fn hello(&mut self) -> String; - } -} - -#[thin_delegate::derive_delegate(Hello)] +#[thin_delegate::register] enum Hoge { A(String), B(char), } +#[thin_delegate::derive_delegate] +impl Hello for Hoge {} + fn main() { let mut hoge = Hoge::A("a".to_string()); assert_eq!(hoge.hello(), "hello, a"); diff --git a/tests/ui.old/pass_generics_const.rs b/tests/ui/pass_generics_const.rs similarity index 60% rename from tests/ui.old/pass_generics_const.rs rename to tests/ui/pass_generics_const.rs index 7befd5d..fb0ffb1 100644 --- a/tests/ui.old/pass_generics_const.rs +++ b/tests/ui/pass_generics_const.rs @@ -1,15 +1,8 @@ +#[thin_delegate::register] pub trait Hello { fn hello(&self) -> [T; N]; } -// TODO: Make `register()` is usable for trait definition. -mod private_for_thin_delegate { - #[thin_delegate::register(Hello)] - pub trait Hello { - fn hello(&self) -> [T; N]; - } -} - impl Hello for char { fn hello(&self) -> [u8; 4] { let mut buf = [0; 4]; @@ -18,9 +11,12 @@ impl Hello for char { } } -#[thin_delegate::derive_delegate(Hello)] +#[thin_delegate::register] struct Hoge(char); +#[thin_delegate::derive_delegate] +impl Hello for Hoge {} + fn main() { let hoge = Hoge('あ'); assert_eq!(&hoge.hello(), &[227, 129, 130, 0]); diff --git a/tests/ui.old/pass_method_with_args.rs b/tests/ui/pass_method_with_args.rs similarity index 67% rename from tests/ui.old/pass_method_with_args.rs rename to tests/ui/pass_method_with_args.rs index d9b8633..90af150 100644 --- a/tests/ui.old/pass_method_with_args.rs +++ b/tests/ui/pass_method_with_args.rs @@ -1,3 +1,4 @@ +#[thin_delegate::register] pub trait Hello { fn hello(&self, prefix: &str) -> String; } @@ -14,20 +15,15 @@ impl Hello for char { } } -// TODO: Make `register()` is usable for trait definition. -mod private_for_thin_delegate { - #[thin_delegate::register(Hello)] - pub trait Hello { - fn hello(&self, prefix: &str) -> String; - } -} - -#[thin_delegate::derive_delegate(Hello)] +#[thin_delegate::register] enum Hoge { A(String), B(char), } +#[thin_delegate::derive_delegate] +impl Hello for Hoge {} + fn main() { let hoge = Hoge::A("a".to_string()); assert_eq!(hoge.hello("hello, "), "hello, a"); diff --git a/tests/ui/pass_register_in_multiple_modules.rs b/tests/ui/pass_register_in_multiple_modules.rs new file mode 100644 index 0000000..df6d6f7 --- /dev/null +++ b/tests/ui/pass_register_in_multiple_modules.rs @@ -0,0 +1,39 @@ +mod a { + #[thin_delegate::register] + pub trait Hello { + fn hello(&self) -> String; + } + + impl Hello for String { + fn hello(&self) -> String { + format!("hello, {self}") + } + } + + #[thin_delegate::register] + struct Hoge(String); + + #[thin_delegate::derive_delegate] + impl Hello for Hoge {} +} + +mod b { + #[thin_delegate::register] + pub trait Hello { + fn hello(&self) -> String; + } + + impl Hello for String { + fn hello(&self) -> String { + format!("hello, {self}") + } + } + + #[thin_delegate::register] + struct Hoge(String); + + #[thin_delegate::derive_delegate] + impl Hello for Hoge {} +} + +fn main() {} diff --git a/tests/ui.old/pass_super_trait.rs b/tests/ui/pass_super_trait.rs similarity index 72% rename from tests/ui.old/pass_super_trait.rs rename to tests/ui/pass_super_trait.rs index a5fbfb9..839bd97 100644 --- a/tests/ui.old/pass_super_trait.rs +++ b/tests/ui/pass_super_trait.rs @@ -1,7 +1,9 @@ +#[thin_delegate::register] pub trait Hello: ToString { fn hello(&self) -> String; } +// Note that we can use default implementation in this case. impl Hello for String { fn hello(&self) -> String { format!("hello, {}", &self.to_string()) @@ -14,20 +16,13 @@ impl Hello for char { } } -// TODO: Make `register()` is usable for trait definition. -mod private_for_thin_delegate { - #[thin_delegate::register(Hello)] - pub trait Hello: ToString { - fn hello(&self) -> String; - } -} - -#[thin_delegate::derive_delegate(Hello)] +#[thin_delegate::register] enum Hoge { A(String), B(char), } +// Note that we can also derive `ToString` in this case. See pass_multiple_derive.rs. impl ToString for Hoge { fn to_string(&self) -> String { match self { @@ -37,6 +32,9 @@ impl ToString for Hoge { } } +#[thin_delegate::derive_delegate] +impl Hello for Hoge {} + fn main() { let hoge = Hoge::A("a".to_string()); assert_eq!(hoge.hello(), "hello, a");