From 6a182765c2b6b92426d3df6515be9a083e6d16c1 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 18 Feb 2026 12:30:58 +0100 Subject: [PATCH 1/6] Draft implement abstract type equality bounds --- crates/cgp-macro-lib/src/cgp_fn/use_type.rs | 93 ++++++++++++++++++++- 1 file changed, 90 insertions(+), 3 deletions(-) diff --git a/crates/cgp-macro-lib/src/cgp_fn/use_type.rs b/crates/cgp-macro-lib/src/cgp_fn/use_type.rs index 08901872..39d25400 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/use_type.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/use_type.rs @@ -1,6 +1,9 @@ +use proc_macro2::TokenStream; +use quote::{ToTokens, quote}; use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; use syn::token::{As, Brace, Colon, Comma, Gt, Lt}; -use syn::{Ident, braced}; +use syn::{Ident, Type, TypeParamBound, braced, parse2}; use crate::parse::SimpleType; @@ -17,7 +20,7 @@ pub struct UseTypeIdent { impl UseTypeSpec { pub fn replace_ident(&self, ident: &Ident) -> Option { for type_ident in &self.type_idents { - if type_ident.replacement_ident() == ident { + if type_ident.alias_ident() == ident { let mut new_ident = type_ident.type_ident.clone(); new_ident.set_span(ident.span()); return Some(new_ident); @@ -26,10 +29,94 @@ impl UseTypeSpec { None } + + pub fn trait_bounds( + context_type: &TokenStream, + specs: &[Self], + ) -> syn::Result> { + let mut bounds = Vec::new(); + + let mut past_specs = Vec::new(); + + for use_type in specs.iter() { + let type_equalities = use_type.find_type_equalities(context_type, &past_specs)?; + + if type_equalities.is_empty() { + bounds.push(parse2(use_type.trait_path.to_token_stream())?); + past_specs.push(use_type); + } else { + let mut constraints: Punctuated = Punctuated::new(); + + for (alias_ident, equal_target) in type_equalities.into_iter() { + constraints.push(quote! { + #alias_ident = #equal_target + }); + } + + let trait_path = &use_type.trait_path; + let bound = quote! { + #trait_path < #constraints > + }; + + bounds.push(parse2(bound)?); + } + } + + Ok(bounds) + } + + pub fn find_type_equalities( + &self, + context_type: &TokenStream, + past_specs: &[&UseTypeSpec], + ) -> syn::Result> { + let mut equalities = Vec::new(); + + for type_ident in self.type_idents.iter() { + if let Some(equality) = Self::find_type_equality(context_type, type_ident, past_specs)? + { + equalities.push(equality); + } + } + + Ok(equalities) + } + + pub fn find_type_equality( + context_type: &TokenStream, + current_ident: &UseTypeIdent, + past_specs: &[&UseTypeSpec], + ) -> syn::Result> { + for past_spec in past_specs.iter() { + for type_ident in past_spec.type_idents.iter() { + let current_alias = current_ident.alias_ident(); + + if current_alias == type_ident.alias_ident() { + if current_ident.as_alias.is_none() || type_ident.as_alias.is_none() { + return Err(syn::Error::new_spanned( + ¤t_ident.type_ident, + "Multiple abstract types with the same name must be aliased explicitly with `as`", + )); + } + + let trait_path = &past_spec.trait_path; + let type_ident = ¤t_ident.type_ident; + + let equal_target: Type = parse2(quote! { + <#context_type as #trait_path>::#type_ident + })?; + + return Ok(Some((current_alias.clone(), equal_target))); + } + } + } + + Ok(None) + } } impl UseTypeIdent { - pub fn replacement_ident(&self) -> &Ident { + pub fn alias_ident(&self) -> &Ident { self.as_alias.as_ref().unwrap_or(&self.type_ident) } } From 5038241a3038a45836d1ffcd6a761e636e24b2d0 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 18 Feb 2026 13:15:12 +0100 Subject: [PATCH 2/6] Move type equality code to separate module --- crates/cgp-macro-lib/src/cgp_fn/mod.rs | 2 + .../cgp-macro-lib/src/cgp_fn/type_equality.rs | 90 +++++++++++++++++++ crates/cgp-macro-lib/src/cgp_fn/use_type.rs | 89 +----------------- 3 files changed, 93 insertions(+), 88 deletions(-) create mode 100644 crates/cgp-macro-lib/src/cgp_fn/type_equality.rs diff --git a/crates/cgp-macro-lib/src/cgp_fn/mod.rs b/crates/cgp-macro-lib/src/cgp_fn/mod.rs index 3c094c21..a33875ba 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/mod.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/mod.rs @@ -6,6 +6,7 @@ mod item_trait; mod parse_implicits; mod spec; mod substitute_type; +mod type_equality; mod use_type; pub use attributes::*; @@ -13,4 +14,5 @@ pub use derive::*; pub use parse_implicits::*; pub use spec::*; pub use substitute_type::*; +pub use type_equality::*; pub use use_type::*; diff --git a/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs b/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs new file mode 100644 index 00000000..7dd52486 --- /dev/null +++ b/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs @@ -0,0 +1,90 @@ +use proc_macro2::TokenStream; +use quote::{ToTokens, quote}; +use syn::punctuated::Punctuated; +use syn::token::Comma; +use syn::{Ident, Type, TypeParamBound, parse2}; + +use crate::cgp_fn::{UseTypeIdent, UseTypeSpec}; + +pub fn derive_use_type_trait_bounds( + context_type: &TokenStream, + specs: &[UseTypeSpec], +) -> syn::Result> { + let mut bounds = Vec::new(); + + let mut past_specs = Vec::new(); + + for use_type in specs.iter() { + let type_equalities = find_type_equalities(use_type, context_type, &past_specs)?; + + if type_equalities.is_empty() { + bounds.push(parse2(use_type.trait_path.to_token_stream())?); + past_specs.push(use_type); + } else { + let mut constraints: Punctuated = Punctuated::new(); + + for (alias_ident, equal_target) in type_equalities.into_iter() { + constraints.push(quote! { + #alias_ident = #equal_target + }); + } + + let trait_path = &use_type.trait_path; + let bound = quote! { + #trait_path < #constraints > + }; + + bounds.push(parse2(bound)?); + } + } + + Ok(bounds) +} + +pub fn find_type_equalities( + current_spec: &UseTypeSpec, + context_type: &TokenStream, + past_specs: &[&UseTypeSpec], +) -> syn::Result> { + let mut equalities = Vec::new(); + + for type_ident in current_spec.type_idents.iter() { + if let Some(equality) = find_type_equality(context_type, type_ident, past_specs)? { + equalities.push(equality); + } + } + + Ok(equalities) +} + +pub fn find_type_equality( + context_type: &TokenStream, + current_ident: &UseTypeIdent, + past_specs: &[&UseTypeSpec], +) -> syn::Result> { + for past_spec in past_specs.iter() { + for type_ident in past_spec.type_idents.iter() { + let current_alias = current_ident.alias_ident(); + + if current_alias == type_ident.alias_ident() { + if current_ident.as_alias.is_none() || type_ident.as_alias.is_none() { + return Err(syn::Error::new_spanned( + ¤t_ident.type_ident, + "Multiple abstract types with the same name must be aliased explicitly with `as`", + )); + } + + let trait_path = &past_spec.trait_path; + let type_ident = ¤t_ident.type_ident; + + let equal_target: Type = parse2(quote! { + <#context_type as #trait_path>::#type_ident + })?; + + return Ok(Some((current_alias.clone(), equal_target))); + } + } + } + + Ok(None) +} diff --git a/crates/cgp-macro-lib/src/cgp_fn/use_type.rs b/crates/cgp-macro-lib/src/cgp_fn/use_type.rs index 39d25400..28fcce74 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/use_type.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/use_type.rs @@ -1,9 +1,6 @@ -use proc_macro2::TokenStream; -use quote::{ToTokens, quote}; use syn::parse::{Parse, ParseStream}; -use syn::punctuated::Punctuated; use syn::token::{As, Brace, Colon, Comma, Gt, Lt}; -use syn::{Ident, Type, TypeParamBound, braced, parse2}; +use syn::{Ident, braced}; use crate::parse::SimpleType; @@ -29,90 +26,6 @@ impl UseTypeSpec { None } - - pub fn trait_bounds( - context_type: &TokenStream, - specs: &[Self], - ) -> syn::Result> { - let mut bounds = Vec::new(); - - let mut past_specs = Vec::new(); - - for use_type in specs.iter() { - let type_equalities = use_type.find_type_equalities(context_type, &past_specs)?; - - if type_equalities.is_empty() { - bounds.push(parse2(use_type.trait_path.to_token_stream())?); - past_specs.push(use_type); - } else { - let mut constraints: Punctuated = Punctuated::new(); - - for (alias_ident, equal_target) in type_equalities.into_iter() { - constraints.push(quote! { - #alias_ident = #equal_target - }); - } - - let trait_path = &use_type.trait_path; - let bound = quote! { - #trait_path < #constraints > - }; - - bounds.push(parse2(bound)?); - } - } - - Ok(bounds) - } - - pub fn find_type_equalities( - &self, - context_type: &TokenStream, - past_specs: &[&UseTypeSpec], - ) -> syn::Result> { - let mut equalities = Vec::new(); - - for type_ident in self.type_idents.iter() { - if let Some(equality) = Self::find_type_equality(context_type, type_ident, past_specs)? - { - equalities.push(equality); - } - } - - Ok(equalities) - } - - pub fn find_type_equality( - context_type: &TokenStream, - current_ident: &UseTypeIdent, - past_specs: &[&UseTypeSpec], - ) -> syn::Result> { - for past_spec in past_specs.iter() { - for type_ident in past_spec.type_idents.iter() { - let current_alias = current_ident.alias_ident(); - - if current_alias == type_ident.alias_ident() { - if current_ident.as_alias.is_none() || type_ident.as_alias.is_none() { - return Err(syn::Error::new_spanned( - ¤t_ident.type_ident, - "Multiple abstract types with the same name must be aliased explicitly with `as`", - )); - } - - let trait_path = &past_spec.trait_path; - let type_ident = ¤t_ident.type_ident; - - let equal_target: Type = parse2(quote! { - <#context_type as #trait_path>::#type_ident - })?; - - return Ok(Some((current_alias.clone(), equal_target))); - } - } - } - - Ok(None) - } } impl UseTypeIdent { From 79cb5691592bb80ff6914cc3dc59539d975692b6 Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 18 Feb 2026 13:27:50 +0100 Subject: [PATCH 3/6] Basic type equality test working --- crates/cgp-macro-lib/src/cgp_fn/item_impl.rs | 11 ++++---- .../cgp-macro-lib/src/cgp_fn/type_equality.rs | 4 +-- crates/cgp-tests/tests/cgp_fn_tests/mod.rs | 1 + .../tests/cgp_fn_tests/type_equality.rs | 28 +++++++++++++++++++ 4 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 crates/cgp-tests/tests/cgp_fn_tests/type_equality.rs diff --git a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs index ebef39e1..85625ef6 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs @@ -3,7 +3,9 @@ use syn::punctuated::Punctuated; use syn::token::Plus; use syn::{Generics, Ident, ItemFn, ItemImpl, TypeParamBound, parse2}; -use crate::cgp_fn::{FunctionAttributes, ImplicitArgField, substitute_abstract_type}; +use crate::cgp_fn::{ + FunctionAttributes, ImplicitArgField, derive_use_type_trait_bounds, substitute_abstract_type, +}; use crate::derive_getter::derive_getter_constraint; use crate::symbol::symbol_from_string; @@ -74,11 +76,8 @@ pub fn derive_item_impl( item_impl.to_token_stream(), ))?; - let mut bounds: Punctuated = Punctuated::default(); - - for use_type in attributes.use_type.iter() { - bounds.push(parse2(use_type.trait_path.to_token_stream())?); - } + let bounds = derive_use_type_trait_bounds("e! { Self }, &attributes.use_type)?; + let bounds = Punctuated::::from_iter(bounds.into_iter()); item_impl .generics diff --git a/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs b/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs index 7dd52486..8258d837 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs @@ -78,10 +78,10 @@ pub fn find_type_equality( let type_ident = ¤t_ident.type_ident; let equal_target: Type = parse2(quote! { - <#context_type as #trait_path>::#type_ident + <#context_type as #trait_path>::#current_alias })?; - return Ok(Some((current_alias.clone(), equal_target))); + return Ok(Some((type_ident.clone(), equal_target))); } } } diff --git a/crates/cgp-tests/tests/cgp_fn_tests/mod.rs b/crates/cgp-tests/tests/cgp_fn_tests/mod.rs index 90833d71..2bbb504f 100644 --- a/crates/cgp-tests/tests/cgp_fn_tests/mod.rs +++ b/crates/cgp-tests/tests/cgp_fn_tests/mod.rs @@ -4,6 +4,7 @@ pub mod extend; pub mod generics; pub mod multi; pub mod mutable; +pub mod type_equality; pub mod use_type; pub mod use_type_alias; pub mod uses; diff --git a/crates/cgp-tests/tests/cgp_fn_tests/type_equality.rs b/crates/cgp-tests/tests/cgp_fn_tests/type_equality.rs new file mode 100644 index 00000000..d5089f67 --- /dev/null +++ b/crates/cgp-tests/tests/cgp_fn_tests/type_equality.rs @@ -0,0 +1,28 @@ +use cgp::prelude::*; + +pub trait HasFooType { + type Foo; +} + +pub trait HasBarType { + type Bar; +} + +#[cgp_fn] +#[use_type(HasFooType::Foo)] +pub fn do_foo(&self) -> Foo { + todo!() +} + +#[cgp_fn] +#[use_type(HasBarType::Bar)] +pub fn do_bar(&self) -> Bar { + todo!() +} + +#[cgp_fn] +#[use_type(HasFooType::{Foo as Foo}, HasBarType::{Bar as Foo})] +#[uses(DoFoo, DoBar)] +fn return_foo_or_bar(&self, flag: bool) -> Foo { + if flag { self.do_foo() } else { self.do_bar() } +} From 4145e399e67692a610cd817a0f9ae9329b3042fb Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 18 Feb 2026 13:51:50 +0100 Subject: [PATCH 4/6] Draft add new type equality syntax --- .../cgp-macro-lib/src/cgp_fn/type_equality.rs | 84 ++++++++++++------- crates/cgp-macro-lib/src/cgp_fn/use_type.rs | 14 +++- .../tests/cgp_fn_tests/type_equality.rs | 12 +-- 3 files changed, 74 insertions(+), 36 deletions(-) diff --git a/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs b/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs index 8258d837..c255b10f 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs @@ -12,14 +12,11 @@ pub fn derive_use_type_trait_bounds( ) -> syn::Result> { let mut bounds = Vec::new(); - let mut past_specs = Vec::new(); - for use_type in specs.iter() { - let type_equalities = find_type_equalities(use_type, context_type, &past_specs)?; + let type_equalities = find_type_equalities(use_type, context_type, &specs)?; if type_equalities.is_empty() { bounds.push(parse2(use_type.trait_path.to_token_stream())?); - past_specs.push(use_type); } else { let mut constraints: Punctuated = Punctuated::new(); @@ -44,12 +41,16 @@ pub fn derive_use_type_trait_bounds( pub fn find_type_equalities( current_spec: &UseTypeSpec, context_type: &TokenStream, - past_specs: &[&UseTypeSpec], + specs: &[UseTypeSpec], ) -> syn::Result> { let mut equalities = Vec::new(); - for type_ident in current_spec.type_idents.iter() { - if let Some(equality) = find_type_equality(context_type, type_ident, past_specs)? { + for current_type_ident in current_spec.type_idents.iter() { + forbid_same_alias(current_type_ident, current_spec, specs)?; + + if let Some(equality) = + find_type_equality(context_type, current_type_ident, current_spec, specs)? + { equalities.push(equality); } } @@ -57,34 +58,61 @@ pub fn find_type_equalities( Ok(equalities) } -pub fn find_type_equality( +fn forbid_same_alias( + current_ident: &UseTypeIdent, + current_spec: &UseTypeSpec, + specs: &[UseTypeSpec], +) -> syn::Result<()> { + for spec in specs.iter() { + if core::ptr::eq(spec, current_spec) { + // Skip the current spec + continue; + } + + for type_ident in spec.type_idents.iter() { + if current_ident.alias_ident() == type_ident.alias_ident() { + return Err(syn::Error::new_spanned( + ¤t_ident.type_ident, + "Multiple abstract types cannot share the same identifier or alias", + )); + } + } + } + + Ok(()) +} + +fn find_type_equality( context_type: &TokenStream, current_ident: &UseTypeIdent, - past_specs: &[&UseTypeSpec], + current_spec: &UseTypeSpec, + specs: &[UseTypeSpec], ) -> syn::Result> { - for past_spec in past_specs.iter() { - for type_ident in past_spec.type_idents.iter() { - let current_alias = current_ident.alias_ident(); - - if current_alias == type_ident.alias_ident() { - if current_ident.as_alias.is_none() || type_ident.as_alias.is_none() { - return Err(syn::Error::new_spanned( - ¤t_ident.type_ident, - "Multiple abstract types with the same name must be aliased explicitly with `as`", - )); - } + if let Some(equal_target) = current_ident.equals.clone() { + for spec in specs.iter() { + if core::ptr::eq(spec, current_spec) { + // Skip the current spec + continue; + } - let trait_path = &past_spec.trait_path; - let type_ident = ¤t_ident.type_ident; + for type_ident in spec.type_idents.iter() { + let match_type: Type = parse2(type_ident.alias_ident().to_token_stream())?; + if match_type == equal_target { + let trait_path = &spec.trait_path; + let current_type_ident = ¤t_ident.type_ident; + let current_alias = current_ident.alias_ident(); - let equal_target: Type = parse2(quote! { - <#context_type as #trait_path>::#current_alias - })?; + let equal_target: Type = parse2(quote! { + <#context_type as #trait_path>::#current_alias + })?; - return Ok(Some((type_ident.clone(), equal_target))); + return Ok(Some((current_type_ident.clone(), equal_target))); + } } } - } - Ok(None) + Ok(Some((current_ident.type_ident.clone(), equal_target))) + } else { + Ok(None) + } } diff --git a/crates/cgp-macro-lib/src/cgp_fn/use_type.rs b/crates/cgp-macro-lib/src/cgp_fn/use_type.rs index 28fcce74..d36949c1 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/use_type.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/use_type.rs @@ -1,6 +1,6 @@ use syn::parse::{Parse, ParseStream}; -use syn::token::{As, Brace, Colon, Comma, Gt, Lt}; -use syn::{Ident, braced}; +use syn::token::{As, Brace, Colon, Comma, Eq, Gt, Lt}; +use syn::{Ident, Type, braced}; use crate::parse::SimpleType; @@ -12,6 +12,7 @@ pub struct UseTypeSpec { pub struct UseTypeIdent { pub type_ident: Ident, pub as_alias: Option, + pub equals: Option, } impl UseTypeSpec { @@ -64,6 +65,7 @@ impl Parse for UseTypeSpec { vec![UseTypeIdent { type_ident: ident, as_alias: None, + equals: None, }] }; @@ -85,9 +87,17 @@ impl Parse for UseTypeIdent { None }; + let equals = if input.peek(Eq) { + let _: Eq = input.parse()?; + Some(input.parse()?) + } else { + None + }; + Ok(Self { type_ident, as_alias, + equals, }) } } diff --git a/crates/cgp-tests/tests/cgp_fn_tests/type_equality.rs b/crates/cgp-tests/tests/cgp_fn_tests/type_equality.rs index d5089f67..e69c62e7 100644 --- a/crates/cgp-tests/tests/cgp_fn_tests/type_equality.rs +++ b/crates/cgp-tests/tests/cgp_fn_tests/type_equality.rs @@ -20,9 +20,9 @@ pub fn do_bar(&self) -> Bar { todo!() } -#[cgp_fn] -#[use_type(HasFooType::{Foo as Foo}, HasBarType::{Bar as Foo})] -#[uses(DoFoo, DoBar)] -fn return_foo_or_bar(&self, flag: bool) -> Foo { - if flag { self.do_foo() } else { self.do_bar() } -} +// #[cgp_fn] +// #[use_type(HasFooType::{Foo as Foo}, HasBarType::{Bar as Foo})] +// #[uses(DoFoo, DoBar)] +// fn return_foo_or_bar(&self, flag: bool) -> Foo { +// if flag { self.do_foo() } else { self.do_bar() } +// } From 62ad69baae5209add9174306e957206a562c0f3c Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 18 Feb 2026 14:05:43 +0100 Subject: [PATCH 5/6] Test with type equality constraints --- .../cgp-macro-lib/src/cgp_fn/type_equality.rs | 8 ++-- .../tests/cgp_fn_tests/type_equality.rs | 38 +++++++++++++++---- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs b/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs index c255b10f..3bde6b0a 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs @@ -95,15 +95,15 @@ fn find_type_equality( continue; } - for type_ident in spec.type_idents.iter() { - let match_type: Type = parse2(type_ident.alias_ident().to_token_stream())?; + for match_use_type in spec.type_idents.iter() { + let match_type: Type = parse2(match_use_type.alias_ident().to_token_stream())?; if match_type == equal_target { let trait_path = &spec.trait_path; let current_type_ident = ¤t_ident.type_ident; - let current_alias = current_ident.alias_ident(); + let match_type_ident = &match_use_type.type_ident; let equal_target: Type = parse2(quote! { - <#context_type as #trait_path>::#current_alias + <#context_type as #trait_path>::#match_type_ident })?; return Ok(Some((current_type_ident.clone(), equal_target))); diff --git a/crates/cgp-tests/tests/cgp_fn_tests/type_equality.rs b/crates/cgp-tests/tests/cgp_fn_tests/type_equality.rs index e69c62e7..8da2b1a3 100644 --- a/crates/cgp-tests/tests/cgp_fn_tests/type_equality.rs +++ b/crates/cgp-tests/tests/cgp_fn_tests/type_equality.rs @@ -1,11 +1,27 @@ +use std::fmt::Display; + use cgp::prelude::*; +#[cgp_type] +pub trait HasScalarType { + type Scalar; +} + +#[cgp_fn] +#[use_type(HasScalarType::{Scalar = f64})] +pub fn rectangle_area(&self, #[implicit] width: Scalar, #[implicit] height: Scalar) -> Scalar { + let res: f64 = width * height; + res +} + pub trait HasFooType { - type Foo; + // The `Ord + Clone` bounds are visible to both `Foo` and `Bar` because of `Bar = Foo` below + type Foo: Ord + Clone; } pub trait HasBarType { - type Bar; + // The `Display` bounds are hidden because of `Bar = Foo` below + type Bar: Display; } #[cgp_fn] @@ -20,9 +36,15 @@ pub fn do_bar(&self) -> Bar { todo!() } -// #[cgp_fn] -// #[use_type(HasFooType::{Foo as Foo}, HasBarType::{Bar as Foo})] -// #[uses(DoFoo, DoBar)] -// fn return_foo_or_bar(&self, flag: bool) -> Foo { -// if flag { self.do_foo() } else { self.do_bar() } -// } +#[cgp_fn] +#[use_type(HasBarType::{Bar as Baz = Foo}, HasFooType::Foo)] +#[uses(DoFoo, DoBar)] +fn return_foo_or_bar(&self, flag: bool, #[implicit] foo: &Foo, #[implicit] bar: &Baz) -> Foo { + if flag { + let res: Foo = self.do_foo(); + if &res < foo { res } else { foo.clone() } + } else { + let res: Baz = self.do_bar(); + if &res < bar { res } else { bar.clone() } + } +} From 03a09cac6b859339be3ca960ec1410191a59f71f Mon Sep 17 00:00:00 2001 From: Soares Chen Date: Wed, 18 Feb 2026 14:06:54 +0100 Subject: [PATCH 6/6] Fix clippy --- crates/cgp-macro-lib/src/cgp_fn/item_impl.rs | 2 +- crates/cgp-macro-lib/src/cgp_fn/type_equality.rs | 2 +- crates/cgp-tests/tests/cgp_fn.rs | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs index 85625ef6..23be35c9 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/item_impl.rs @@ -77,7 +77,7 @@ pub fn derive_item_impl( ))?; let bounds = derive_use_type_trait_bounds("e! { Self }, &attributes.use_type)?; - let bounds = Punctuated::::from_iter(bounds.into_iter()); + let bounds = Punctuated::::from_iter(bounds); item_impl .generics diff --git a/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs b/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs index 3bde6b0a..fd289ffc 100644 --- a/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs +++ b/crates/cgp-macro-lib/src/cgp_fn/type_equality.rs @@ -13,7 +13,7 @@ pub fn derive_use_type_trait_bounds( let mut bounds = Vec::new(); for use_type in specs.iter() { - let type_equalities = find_type_equalities(use_type, context_type, &specs)?; + let type_equalities = find_type_equalities(use_type, context_type, specs)?; if type_equalities.is_empty() { bounds.push(parse2(use_type.trait_path.to_token_stream())?); diff --git a/crates/cgp-tests/tests/cgp_fn.rs b/crates/cgp-tests/tests/cgp_fn.rs index f623a10a..5e7cd854 100644 --- a/crates/cgp-tests/tests/cgp_fn.rs +++ b/crates/cgp-tests/tests/cgp_fn.rs @@ -1 +1,3 @@ +#![allow(clippy::disallowed_names)] + pub mod cgp_fn_tests;