From 4b488a54874137fe01cd7dd211277aa69b6d030d Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 27 Feb 2026 21:48:51 +0100 Subject: [PATCH 1/5] Fix UseType with self referential bound --- .../src/derive_component/derive.rs | 4 +- .../cgp-macro-lib/src/entrypoints/cgp_type.rs | 13 ++++- .../src/type_component/derive.rs | 12 ++-- .../cgp-macro-lib/src/type_component/mod.rs | 1 + .../src/type_component/replace.rs | 39 +++++++++++++ .../cgp-tests/tests/cgp_fn_tests/use_type.rs | 57 ++++++++++++++++--- 6 files changed, 108 insertions(+), 18 deletions(-) create mode 100644 crates/cgp-macro-lib/src/type_component/replace.rs diff --git a/crates/cgp-macro-lib/src/derive_component/derive.rs b/crates/cgp-macro-lib/src/derive_component/derive.rs index bd4a4c07..32de632b 100644 --- a/crates/cgp-macro-lib/src/derive_component/derive.rs +++ b/crates/cgp-macro-lib/src/derive_component/derive.rs @@ -54,8 +54,8 @@ pub fn derive_component_with_ast( )?; let mut item_impls = vec![ + provider_impl.clone(), consumer_impl, - provider_impl, use_context_impl, use_context_is_provider_impl, ]; @@ -80,6 +80,7 @@ pub fn derive_component_with_ast( component_struct, consumer_trait, provider_trait, + provider_impl, item_impls, }; @@ -90,6 +91,7 @@ pub struct DerivedComponent { pub component_struct: ItemStruct, pub consumer_trait: ItemTrait, pub provider_trait: ItemTrait, + pub provider_impl: ItemImpl, pub item_impls: Vec, } diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_type.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_type.rs index 4aac783a..27a047ba 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_type.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_type.rs @@ -7,7 +7,9 @@ use syn::{Ident, ItemTrait, parse_quote, parse2}; use crate::derive_component::derive_component_with_ast; use crate::parse::{ComponentSpec, Entries}; -use crate::type_component::{derive_type_alias, derive_type_providers, extract_item_type}; +use crate::type_component::{ + derive_type_alias, derive_type_providers, extract_item_type_from_trait, +}; pub fn cgp_type(attrs: TokenStream, body: TokenStream) -> syn::Result { let mut entries = if let Ok(provider_ident) = parse2::(attrs.clone()) { @@ -18,7 +20,7 @@ pub fn cgp_type(attrs: TokenStream, body: TokenStream) -> syn::Result syn::Result syn::Result<&TraitItemType> { +pub fn extract_item_type_from_trait(consumer_trait: &ItemTrait) -> syn::Result<&TraitItemType> { if consumer_trait.items.len() != 1 { return Err(Error::new( consumer_trait.span(), @@ -63,15 +64,16 @@ pub fn derive_type_alias( pub fn derive_type_providers( spec: &ComponentSpec, provider_trait: &ItemTrait, + provider_impl: &ItemImpl, item_type: &TraitItemType, ) -> syn::Result> { let context_name = &spec.context_type; - let component_name = { + let component_name: Type = { let name = &spec.component_name; let params = &spec.component_params; - parse2::(quote! { #name < #params > }) - }?; + parse2(quote! { #name < #params > })? + }; let provider_trait_name = &provider_trait.ident; @@ -85,7 +87,7 @@ pub fn derive_type_providers( let type_name = &item_type.ident; - let type_bounds = &item_type.bounds; + let type_bounds = get_bounds_and_replace_self_assoc_type(&item_type); let use_type_impl: ItemImpl = parse2(quote! { impl< #type_name, #impl_generics_params > diff --git a/crates/cgp-macro-lib/src/type_component/mod.rs b/crates/cgp-macro-lib/src/type_component/mod.rs index 61eca8a7..42dc01bc 100644 --- a/crates/cgp-macro-lib/src/type_component/mod.rs +++ b/crates/cgp-macro-lib/src/type_component/mod.rs @@ -1,3 +1,4 @@ mod derive; +mod replace; pub use derive::*; diff --git a/crates/cgp-macro-lib/src/type_component/replace.rs b/crates/cgp-macro-lib/src/type_component/replace.rs new file mode 100644 index 00000000..a97fcb01 --- /dev/null +++ b/crates/cgp-macro-lib/src/type_component/replace.rs @@ -0,0 +1,39 @@ +// pub fn replace_self_assoc_type + +use syn::punctuated::Punctuated; +use syn::token::Plus; +use syn::visit_mut::{VisitMut, visit_type_mut, visit_type_param_bound_mut}; +use syn::{Ident, TraitItemType, Type, TypeParamBound, parse_quote}; + +pub fn get_bounds_and_replace_self_assoc_type( + item_type: &TraitItemType, +) -> Punctuated { + let mut bounds = item_type.bounds.clone(); + let mut visitor = ReplaceSelfAssocTypeVisitor { + type_ident: item_type.ident.clone(), + }; + + for bound in &mut bounds { + visit_type_param_bound_mut(&mut visitor, bound); + } + + bounds +} + +pub struct ReplaceSelfAssocTypeVisitor { + pub type_ident: Ident, +} + +impl VisitMut for ReplaceSelfAssocTypeVisitor { + fn visit_type_mut(&mut self, node: &mut Type) { + if let Type::Path(type_path) = node { + let type_ident = &self.type_ident; + if type_path == &parse_quote! { Self :: #type_ident } { + *node = parse_quote!(#type_ident); + return; + } + } + + visit_type_mut(self, node); + } +} diff --git a/crates/cgp-tests/tests/cgp_fn_tests/use_type.rs b/crates/cgp-tests/tests/cgp_fn_tests/use_type.rs index 662a8039..06d1531f 100644 --- a/crates/cgp-tests/tests/cgp_fn_tests/use_type.rs +++ b/crates/cgp-tests/tests/cgp_fn_tests/use_type.rs @@ -1,18 +1,57 @@ +use core::f64; use std::ops::Mul; use cgp::prelude::*; -#[cgp_type] +// #[cgp_type] +#[cgp_component(ScalarTypeProvider)] pub trait HasScalarType { - type Scalar; + type Scalar: Mul + Clone; } #[cgp_fn] -#[use_type(HasScalarType::Scalar)] -pub fn rectangle_area(&self, #[implicit] width: Scalar, #[implicit] height: Scalar) -> Scalar -where - Scalar: Mul + Clone, -{ - let res: Scalar = width * height; - res +#[extend(HasScalarType)] +pub fn rectangle_area( + &self, + #[implicit] width: Self::Scalar, + #[implicit] height: Self::Scalar, +) -> Self::Scalar { + width * height +} + +#[derive(HasField)] +pub struct F32Rectangle { + pub width: f32, + pub height: f32, +} + +impl HasScalarType for F32Rectangle { + type Scalar = f32; +} + +#[derive(HasField)] +pub struct F64Rectangle { + pub width: f64, + pub height: f64, +} + +impl HasScalarType for F64Rectangle { + type Scalar = f64; +} + +#[test] +fn test_rectangle_area() { + let f32_rectangle = F32Rectangle { + width: 3.0, + height: 4.0, + }; + + assert_eq!(f32_rectangle.rectangle_area(), 12.0); + + let f64_rectangle = F64Rectangle { + width: 3.0, + height: 4.0, + }; + + assert_eq!(f64_rectangle.rectangle_area(), 12.0); } From 59b8d82268ee8642f4fbd12460cd498b338c3601 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 27 Feb 2026 21:50:56 +0100 Subject: [PATCH 2/5] Fix WithProvider derivation --- crates/cgp-macro-lib/src/derive_component/derive.rs | 4 +--- crates/cgp-macro-lib/src/entrypoints/cgp_type.rs | 7 +------ crates/cgp-macro-lib/src/type_component/derive.rs | 9 ++++----- crates/cgp-tests/tests/cgp_fn_tests/use_type.rs | 3 +-- 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/crates/cgp-macro-lib/src/derive_component/derive.rs b/crates/cgp-macro-lib/src/derive_component/derive.rs index 32de632b..be02ae26 100644 --- a/crates/cgp-macro-lib/src/derive_component/derive.rs +++ b/crates/cgp-macro-lib/src/derive_component/derive.rs @@ -54,7 +54,7 @@ pub fn derive_component_with_ast( )?; let mut item_impls = vec![ - provider_impl.clone(), + provider_impl, consumer_impl, use_context_impl, use_context_is_provider_impl, @@ -80,7 +80,6 @@ pub fn derive_component_with_ast( component_struct, consumer_trait, provider_trait, - provider_impl, item_impls, }; @@ -91,7 +90,6 @@ pub struct DerivedComponent { pub component_struct: ItemStruct, pub consumer_trait: ItemTrait, pub provider_trait: ItemTrait, - pub provider_impl: ItemImpl, pub item_impls: Vec, } diff --git a/crates/cgp-macro-lib/src/entrypoints/cgp_type.rs b/crates/cgp-macro-lib/src/entrypoints/cgp_type.rs index 27a047ba..8fbec5c0 100644 --- a/crates/cgp-macro-lib/src/entrypoints/cgp_type.rs +++ b/crates/cgp-macro-lib/src/entrypoints/cgp_type.rs @@ -36,12 +36,7 @@ pub fn cgp_type(attrs: TokenStream, body: TokenStream) -> syn::Result syn::Result> { let context_name = &spec.context_type; @@ -104,15 +103,15 @@ pub fn derive_type_providers( let use_type_is_provider_impl = derive_is_provider_for(&component_name, &use_type_impl)?; let with_provider_impl: ItemImpl = parse2(quote! { - impl< __Provider__, #impl_generics_params > + impl< __Provider__, #type_name, #impl_generics_params > #provider_trait_name #type_generics for WithProvider< __Provider__ > where - __Provider__: ProvideType< #context_name, #component_name >, - __Provider__::Type: #type_bounds, + __Provider__: ProvideType< #context_name, #component_name, Type = #type_name >, + #type_name: #type_bounds, #predicates { - type #type_name = __Provider__::Type; + type #type_name = #type_name; } })?; diff --git a/crates/cgp-tests/tests/cgp_fn_tests/use_type.rs b/crates/cgp-tests/tests/cgp_fn_tests/use_type.rs index 06d1531f..8f43135c 100644 --- a/crates/cgp-tests/tests/cgp_fn_tests/use_type.rs +++ b/crates/cgp-tests/tests/cgp_fn_tests/use_type.rs @@ -3,8 +3,7 @@ use std::ops::Mul; use cgp::prelude::*; -// #[cgp_type] -#[cgp_component(ScalarTypeProvider)] +#[cgp_type] pub trait HasScalarType { type Scalar: Mul + Clone; } From 8396bfe95049b01adc6fc781a38ca65e0c845811 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 27 Feb 2026 21:53:12 +0100 Subject: [PATCH 3/5] Add test --- .../component_tests/abstract_types/mod.rs | 1 + .../abstract_types/self_referential.rs | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 crates/cgp-tests/tests/component_tests/abstract_types/self_referential.rs diff --git a/crates/cgp-tests/tests/component_tests/abstract_types/mod.rs b/crates/cgp-tests/tests/component_tests/abstract_types/mod.rs index e206b362..ba04dea3 100644 --- a/crates/cgp-tests/tests/component_tests/abstract_types/mod.rs +++ b/crates/cgp-tests/tests/component_tests/abstract_types/mod.rs @@ -1,3 +1,4 @@ pub mod basic; pub mod extend; pub mod foreign; +pub mod self_referential; diff --git a/crates/cgp-tests/tests/component_tests/abstract_types/self_referential.rs b/crates/cgp-tests/tests/component_tests/abstract_types/self_referential.rs new file mode 100644 index 00000000..ee7112b4 --- /dev/null +++ b/crates/cgp-tests/tests/component_tests/abstract_types/self_referential.rs @@ -0,0 +1,23 @@ +use core::ops::Mul; + +use cgp::prelude::*; + +#[cgp_type] +pub trait HasScalarType { + type Scalar: Mul + Clone; +} + +pub struct App; + +delegate_components! { + App { + ScalarTypeProviderComponent: + UseType, + } +} + +check_components! { + CanUseApp for App { + ScalarTypeProviderComponent, + } +} From 9707786f301fc0fae6b7224a0561f53718ef9b49 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 27 Feb 2026 22:04:21 +0100 Subject: [PATCH 4/5] Fix #[cgp_getter] --- .../src/derive_getter/blanket.rs | 3 +- .../src/derive_getter/use_field.rs | 3 +- .../src/derive_getter/use_fields.rs | 3 +- .../src/derive_getter/with_provider.rs | 3 +- .../cgp-macro-lib/src/type_component/mod.rs | 1 + .../tests/getter_tests/assoc_type/mod.rs | 2 ++ .../assoc_type/self_referential.rs | 29 +++++++++++++++++++ .../assoc_type/self_referential_auto.rs | 22 ++++++++++++++ 8 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 crates/cgp-tests/tests/getter_tests/assoc_type/self_referential.rs create mode 100644 crates/cgp-tests/tests/getter_tests/assoc_type/self_referential_auto.rs diff --git a/crates/cgp-macro-lib/src/derive_getter/blanket.rs b/crates/cgp-macro-lib/src/derive_getter/blanket.rs index e067a095..24157f5c 100644 --- a/crates/cgp-macro-lib/src/derive_getter/blanket.rs +++ b/crates/cgp-macro-lib/src/derive_getter/blanket.rs @@ -9,6 +9,7 @@ use crate::derive_getter::{ ContextArg, ReceiverMode, derive_getter_constraint, derive_getter_method, }; use crate::symbol::symbol_from_string; +use crate::type_component::get_bounds_and_replace_self_assoc_type; pub fn derive_blanket_impl( context_type: &Ident, @@ -39,7 +40,7 @@ pub fn derive_blanket_impl( type #field_assoc_type_ident = #field_assoc_type_ident; }); - let field_constraints = &field_assoc_type.bounds; + let field_constraints = get_bounds_and_replace_self_assoc_type(&field_assoc_type); generics.make_where_clause().predicates.push(parse2(quote! { #field_assoc_type_ident: #field_constraints diff --git a/crates/cgp-macro-lib/src/derive_getter/use_field.rs b/crates/cgp-macro-lib/src/derive_getter/use_field.rs index 661e98f4..d6f4e5d6 100644 --- a/crates/cgp-macro-lib/src/derive_getter/use_field.rs +++ b/crates/cgp-macro-lib/src/derive_getter/use_field.rs @@ -9,6 +9,7 @@ use crate::derive_getter::{ ContextArg, ReceiverMode, derive_getter_constraint, derive_getter_method, }; use crate::parse::ComponentSpec; +use crate::type_component::get_bounds_and_replace_self_assoc_type; pub fn derive_use_field_impl( spec: &ComponentSpec, @@ -43,7 +44,7 @@ pub fn derive_use_field_impl( type #field_assoc_type_ident = #field_assoc_type_ident; }); - let field_constraints = &field_assoc_type.bounds; + let field_constraints = get_bounds_and_replace_self_assoc_type(&field_assoc_type); provider_generics .make_where_clause() diff --git a/crates/cgp-macro-lib/src/derive_getter/use_fields.rs b/crates/cgp-macro-lib/src/derive_getter/use_fields.rs index 9ebdb81e..7605c507 100644 --- a/crates/cgp-macro-lib/src/derive_getter/use_fields.rs +++ b/crates/cgp-macro-lib/src/derive_getter/use_fields.rs @@ -10,6 +10,7 @@ use crate::derive_getter::{ }; use crate::parse::ComponentSpec; use crate::symbol::symbol_from_string; +use crate::type_component::get_bounds_and_replace_self_assoc_type; pub fn derive_use_fields_impl( spec: &ComponentSpec, @@ -36,7 +37,7 @@ pub fn derive_use_fields_impl( type #field_assoc_type_ident = #field_assoc_type_ident; }); - let field_constraints = &field_assoc_type.bounds; + let field_constraints = get_bounds_and_replace_self_assoc_type(&field_assoc_type); provider_generics .make_where_clause() diff --git a/crates/cgp-macro-lib/src/derive_getter/with_provider.rs b/crates/cgp-macro-lib/src/derive_getter/with_provider.rs index 30a1d0d5..2eaf72cf 100644 --- a/crates/cgp-macro-lib/src/derive_getter/with_provider.rs +++ b/crates/cgp-macro-lib/src/derive_getter/with_provider.rs @@ -5,6 +5,7 @@ use syn::{Generics, Ident, ItemImpl, ItemTrait, TraitItemType, parse_quote, pars use crate::derive_getter::getter_field::GetterField; use crate::derive_getter::{ContextArg, FieldMode, ReceiverMode, derive_getter_method}; use crate::parse::ComponentSpec; +use crate::type_component::get_bounds_and_replace_self_assoc_type; pub fn derive_with_provider_impl( spec: &ComponentSpec, @@ -50,7 +51,7 @@ pub fn derive_with_provider_impl( type #field_assoc_type_ident = #field_assoc_type_ident; }); - let field_constraints = &field_assoc_type.bounds; + let field_constraints = get_bounds_and_replace_self_assoc_type(&field_assoc_type); provider_generics .make_where_clause() diff --git a/crates/cgp-macro-lib/src/type_component/mod.rs b/crates/cgp-macro-lib/src/type_component/mod.rs index 42dc01bc..8eaf91af 100644 --- a/crates/cgp-macro-lib/src/type_component/mod.rs +++ b/crates/cgp-macro-lib/src/type_component/mod.rs @@ -2,3 +2,4 @@ mod derive; mod replace; pub use derive::*; +pub use replace::*; diff --git a/crates/cgp-tests/tests/getter_tests/assoc_type/mod.rs b/crates/cgp-tests/tests/getter_tests/assoc_type/mod.rs index 98e2c237..5661cac9 100644 --- a/crates/cgp-tests/tests/getter_tests/assoc_type/mod.rs +++ b/crates/cgp-tests/tests/getter_tests/assoc_type/mod.rs @@ -1,2 +1,4 @@ pub mod auto_getter; pub mod getter; +pub mod self_referential; +pub mod self_referential_auto; diff --git a/crates/cgp-tests/tests/getter_tests/assoc_type/self_referential.rs b/crates/cgp-tests/tests/getter_tests/assoc_type/self_referential.rs new file mode 100644 index 00000000..e3aa8502 --- /dev/null +++ b/crates/cgp-tests/tests/getter_tests/assoc_type/self_referential.rs @@ -0,0 +1,29 @@ +use core::ops::Mul; + +use cgp::prelude::*; + +#[cgp_getter] +pub trait HasScalar { + type Scalar: Mul + Clone; + + fn scalar(&self) -> &Self::Scalar; +} + +#[derive(HasField)] +pub struct App { + pub scalar: f64, +} + +delegate_components! { + App { + ScalarGetterComponent: + UseField, + } +} + +#[test] +fn test_auto_getter_scalar() { + let app = App { scalar: 2.0 }; + + assert_eq!(*app.scalar(), 2.0); +} diff --git a/crates/cgp-tests/tests/getter_tests/assoc_type/self_referential_auto.rs b/crates/cgp-tests/tests/getter_tests/assoc_type/self_referential_auto.rs new file mode 100644 index 00000000..b054d784 --- /dev/null +++ b/crates/cgp-tests/tests/getter_tests/assoc_type/self_referential_auto.rs @@ -0,0 +1,22 @@ +use core::ops::Mul; + +use cgp::prelude::*; + +#[cgp_auto_getter] +pub trait HasScalarType { + type Scalar: Mul + Clone; + + fn scalar(&self) -> &Self::Scalar; +} + +#[derive(HasField)] +pub struct App { + pub scalar: f64, +} + +#[test] +fn test_auto_getter_scalar() { + let app = App { scalar: 2.0 }; + + assert_eq!(*app.scalar(), 2.0); +} From 59f330a3ed4166ff7aa48d7f92bfd3e063ecd353 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Fri, 27 Feb 2026 22:14:48 +0100 Subject: [PATCH 5/5] Fix clippy --- crates/cgp-macro-lib/src/derive_getter/blanket.rs | 2 +- crates/cgp-macro-lib/src/derive_getter/use_field.rs | 2 +- crates/cgp-macro-lib/src/derive_getter/use_fields.rs | 2 +- crates/cgp-macro-lib/src/derive_getter/with_provider.rs | 2 +- crates/cgp-macro-lib/src/type_component/derive.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/cgp-macro-lib/src/derive_getter/blanket.rs b/crates/cgp-macro-lib/src/derive_getter/blanket.rs index 24157f5c..8dc02a9a 100644 --- a/crates/cgp-macro-lib/src/derive_getter/blanket.rs +++ b/crates/cgp-macro-lib/src/derive_getter/blanket.rs @@ -40,7 +40,7 @@ pub fn derive_blanket_impl( type #field_assoc_type_ident = #field_assoc_type_ident; }); - let field_constraints = get_bounds_and_replace_self_assoc_type(&field_assoc_type); + let field_constraints = get_bounds_and_replace_self_assoc_type(field_assoc_type); generics.make_where_clause().predicates.push(parse2(quote! { #field_assoc_type_ident: #field_constraints diff --git a/crates/cgp-macro-lib/src/derive_getter/use_field.rs b/crates/cgp-macro-lib/src/derive_getter/use_field.rs index d6f4e5d6..cddc1977 100644 --- a/crates/cgp-macro-lib/src/derive_getter/use_field.rs +++ b/crates/cgp-macro-lib/src/derive_getter/use_field.rs @@ -44,7 +44,7 @@ pub fn derive_use_field_impl( type #field_assoc_type_ident = #field_assoc_type_ident; }); - let field_constraints = get_bounds_and_replace_self_assoc_type(&field_assoc_type); + let field_constraints = get_bounds_and_replace_self_assoc_type(field_assoc_type); provider_generics .make_where_clause() diff --git a/crates/cgp-macro-lib/src/derive_getter/use_fields.rs b/crates/cgp-macro-lib/src/derive_getter/use_fields.rs index 7605c507..068122db 100644 --- a/crates/cgp-macro-lib/src/derive_getter/use_fields.rs +++ b/crates/cgp-macro-lib/src/derive_getter/use_fields.rs @@ -37,7 +37,7 @@ pub fn derive_use_fields_impl( type #field_assoc_type_ident = #field_assoc_type_ident; }); - let field_constraints = get_bounds_and_replace_self_assoc_type(&field_assoc_type); + let field_constraints = get_bounds_and_replace_self_assoc_type(field_assoc_type); provider_generics .make_where_clause() diff --git a/crates/cgp-macro-lib/src/derive_getter/with_provider.rs b/crates/cgp-macro-lib/src/derive_getter/with_provider.rs index 2eaf72cf..6f470d6a 100644 --- a/crates/cgp-macro-lib/src/derive_getter/with_provider.rs +++ b/crates/cgp-macro-lib/src/derive_getter/with_provider.rs @@ -51,7 +51,7 @@ pub fn derive_with_provider_impl( type #field_assoc_type_ident = #field_assoc_type_ident; }); - let field_constraints = get_bounds_and_replace_self_assoc_type(&field_assoc_type); + let field_constraints = get_bounds_and_replace_self_assoc_type(field_assoc_type); provider_generics .make_where_clause() diff --git a/crates/cgp-macro-lib/src/type_component/derive.rs b/crates/cgp-macro-lib/src/type_component/derive.rs index 58fd5fdf..d7178613 100644 --- a/crates/cgp-macro-lib/src/type_component/derive.rs +++ b/crates/cgp-macro-lib/src/type_component/derive.rs @@ -86,7 +86,7 @@ pub fn derive_type_providers( let type_name = &item_type.ident; - let type_bounds = get_bounds_and_replace_self_assoc_type(&item_type); + let type_bounds = get_bounds_and_replace_self_assoc_type(item_type); let use_type_impl: ItemImpl = parse2(quote! { impl< #type_name, #impl_generics_params >