Skip to content

Comments

Support #[use_provider] attribute inside #[cgp_impl] for higher order providers#204

Merged
soareschen merged 2 commits intomainfrom
use-provider
Feb 23, 2026
Merged

Support #[use_provider] attribute inside #[cgp_impl] for higher order providers#204
soareschen merged 2 commits intomainfrom
use-provider

Conversation

@soareschen
Copy link
Collaborator

@soareschen soareschen commented Feb 23, 2026

This PR introduces a new #[use_provider] attribute that can be used to improve the ergonomics of using higher order providers, by hiding the Self parameter at the first position of the generic parameter of the provider trait.

For example, the ScaledArea provider can be rewritten as:

#[cgp_impl(ScaledArea<InnerCalculator>)]
#[use_provider(InnerCalculator: AreaCalculator)]
impl AreaCalculator
{
    fn area(&self, #[implicit] scale_factor: f64) -> f64 {
        #[use_provider(InnerCalculator)] self.area() * scale_factor * scale_factor
    }
}

which would be desugared to:

#[cgp_impl(ScaledArea<InnerCalculator>)]
impl AreaCalculator
where
    InnerCalculator: AreaCalculator<Self>,
{
    fn area(&self, #[implicit] scale_factor: f64) -> f64 {
        InnerCalculator::area(self) * scale_factor * scale_factor
    }
}

The outer #[use_provider] attribute automatically adds the Self parameter to the generic parameter of InnerCalculator, so that the user only needs to write InnerCalculator: AreaCalculator instead of InnerCalculator: AreaCalculator<Self>. The trait bound is then added to the where clause of the impl block.

The inner #[use_provider] attribute accepts a Provider type and can be applied on a method call expression. It converts the expression from the form receiver.method(args) to Provider::method(receiver, args), so that the method call is dispatched to the specified provider instead of through the context.

It is strongly recommended to always use #[use_provider] when implementing higher order providers, as it significantly reduces the boilerplate of writing higher order providers, and makes the code much more readable. Without it, the reader may be confused by the extra Self generic parameter at the first position of the provider trait, which breaks the illusion that the provider trait appears

@soareschen soareschen merged commit 4489daa into main Feb 23, 2026
5 of 8 checks passed
@soareschen soareschen deleted the use-provider branch February 23, 2026 20:17
@soareschen
Copy link
Collaborator Author

Note that there is a bug at rust-lang/rust#152765 that breaks the formatting when the #[use_provider] attribute is used on method expressions. For example:

#[cgp_impl(new ScaledArea<Inner>)]
#[use_provider(Inner: AreaCalculator)]
impl<Inner> AreaCalculator {
    fn area(&self, #[implicit] scale_factor: f64) -> f64 {
        let base_area = #[use_provider(Inner)]
        self.area();

        base_area * scale_factor * scale_factor
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant