diff --git a/crates/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs b/crates/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs index c09b4e77..37e8257d 100644 --- a/crates/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs +++ b/crates/cgp-extra-macro-lib/src/entrypoints/cgp_auto_dispatch.rs @@ -100,13 +100,13 @@ fn derive_blanket_impl(item_trait: &ItemTrait) -> syn::Result { if let FnArg::Typed(pat_type) = arg { let arg_ident = Ident::new(&format!("arg_{}", i), pat_type.span()); arg_idents.push(arg_ident.clone()); - pat_type.pat = Box::new(Pat::Ident(PatIdent { + *pat_type.pat = Pat::Ident(PatIdent { ident: arg_ident, attrs: Default::default(), by_ref: Default::default(), mutability: Default::default(), subpat: Default::default(), - })); + }); let mut arg_type = pat_type.ty.as_ref().clone(); if let Type::Reference(arg_type) = &mut arg_type { diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs index 20794034..b2652d0e 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_impl.rs @@ -2,9 +2,8 @@ use proc_macro2::{Span, TokenStream}; use quote::{ToTokens, quote}; use syn::parse::discouraged::Speculative; use syn::parse::{Parse, ParseStream}; -use syn::spanned::Spanned; use syn::token::{Colon, For}; -use syn::{Error, FnArg, Ident, ImplItem, ItemImpl, Type, parse2}; +use syn::{FnArg, Ident, ImplItem, ItemImpl, Type, parse_quote, parse2}; use crate::derive_provider::{ derive_component_name_from_provider_impl, derive_is_provider_for, derive_provider_struct, @@ -16,18 +15,36 @@ use crate::replace_self::{ pub fn cgp_impl(attr: TokenStream, body: TokenStream) -> syn::Result { let spec: ImplProviderSpec = parse2(attr)?; - let item_impl: ItemImpl = parse2(body)?; - - let consumer_trait_path = &item_impl - .trait_ - .as_ref() - .ok_or_else(|| Error::new(item_impl.span(), "expect impl trait to contain path"))? - .1; - - let consumer_trait_path: SimpleType = parse2(consumer_trait_path.to_token_stream())?; - - let provider_impl = - transform_impl_trait(&item_impl, &consumer_trait_path, &spec.provider_type)?; + let mut item_impl: ItemImpl = parse2(body)?; + + let provider_impl = match &item_impl.trait_ { + Some((_, path, _)) => { + let consumer_trait_path = parse2(path.to_token_stream())?; + let context_type = item_impl.self_ty.as_ref(); + transform_impl_trait( + &item_impl, + &consumer_trait_path, + &spec.provider_type, + context_type, + )? + } + None => { + let consumer_trait_path = parse2(item_impl.self_ty.to_token_stream())?; + let context_type = parse_quote! { __Context__ }; + + item_impl + .generics + .params + .insert(0, parse_quote! { __Context__ }); + + transform_impl_trait( + &item_impl, + &consumer_trait_path, + &spec.provider_type, + &context_type, + )? + } + }; let component_type = match &spec.component_type { Some(component_type) => component_type.clone(), @@ -92,9 +109,8 @@ pub fn transform_impl_trait( item_impl: &ItemImpl, consumer_trait_path: &SimpleType, provider_type: &Type, + context_type: &Type, ) -> syn::Result { - let context_type = item_impl.self_ty.as_ref(); - let context_var = if let Ok(ident) = parse2::(context_type.to_token_stream()) { to_snake_case_ident(&ident) } else { diff --git a/crates/cgp-tests/tests/component_tests/cgp_impl/implicit_context.rs b/crates/cgp-tests/tests/component_tests/cgp_impl/implicit_context.rs new file mode 100644 index 00000000..e822ee7d --- /dev/null +++ b/crates/cgp-tests/tests/component_tests/cgp_impl/implicit_context.rs @@ -0,0 +1,50 @@ +use cgp::prelude::*; + +#[cgp_component(FooProvider)] +pub trait CanDoFoo { + fn foo(&self, value: u32) -> String; +} + +#[cgp_auto_getter] +pub trait HasName { + fn name(&self) -> &str; +} + +#[cgp_impl(new ValueToString)] +impl FooProvider { + fn foo(&self, value: u32) -> String { + value.to_string() + } +} + +pub mod inner { + use core::fmt::Display; + + use cgp::prelude::*; + + use super::{FooProvider, FooProviderComponent, HasName}; + + #[cgp_impl(new WithNamePrefix)] + impl FooProvider + where + Self: HasName, + { + fn foo(&self, value: u32) -> String { + format!("{}: {}", self.name(), value) + } + } + + pub struct Foo { + pub tag: Tag, + } + + #[cgp_impl(new WithFooTag: FooProviderComponent)] + impl FooProvider for Foo + where + Tag: Display, + { + fn foo(&self, value: u32) -> String { + format!("{}: {}", self.tag, value) + } + } +} diff --git a/crates/cgp-tests/tests/component_tests/cgp_impl/mod.rs b/crates/cgp-tests/tests/component_tests/cgp_impl/mod.rs index 38883ee0..a1da2f99 100644 --- a/crates/cgp-tests/tests/component_tests/cgp_impl/mod.rs +++ b/crates/cgp-tests/tests/component_tests/cgp_impl/mod.rs @@ -1 +1,2 @@ pub mod basic; +pub mod implicit_context; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 29b05176..9c144613 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.90" +channel = "1.93" profile = "default"