Closed Zizico2 closed 1 month ago
I've tried this, and it really showed that error:
use std::ops::Add;
use typed_builder::TypedBuilder;
#[derive(TypedBuilder)]
struct Foo<T: Add<T> + Default> {
#[builder(
via_mutators,
mutators(
fn add(self, amount: T) {
self.bar += amount;
}
)
)]
bar: T,
}
Using cargo expand
to expand the derive macro and then try to build on it, the problem is from here:
#[allow(dead_code, non_camel_case_types, missing_docs)]
#[automatically_derived]
impl<T: Add<T> + Default> FooBuilder<T, ((T,),)> {
#[allow(clippy::used_underscore_binding, clippy::no_effect_underscore_binding)]
fn add(self, amount: T) -> FooBuilder<T, ((T,),)> {
struct TypedBuilderFieldMutator {
bar: T,
}
impl TypedBuilderFieldMutator {
fn add(&mut self, amount: T) {
self.bar += amount;
}
}
let __args = (amount);
let ((bar,),) = self.fields;
let mut __mutator = TypedBuilderFieldMutator { bar };
{
let (amount) = __args;
__mutator.add(amount);
}
let TypedBuilderFieldMutator { bar } = __mutator;
FooBuilder {
fields: ((bar,),),
phantom: self.phantom,
}
}
}
Specifically - TypedBuilderFieldMutator
which uses T
. Rust does not like that - inline types are only "inline" for visibility purposes (and ergonomics, of course) - they don't actually share the generic parametrization of whatever they are defined in.
I'll have to change it to emit this:
struct TypedBuilderFieldMutator<T: Add<T> + Default> {
bar: T,
_phantom: ::core::marker::PhantomData<T>,
}
Note that in this specific case we don't need the phantom data, but since the mutator does not necessarily include all the fields it may not use all the generic parameters, and I really don't want to start diagnosing the generics and see which ones are needed so I'm just going to add them all.
Using mutators on a generic field doesn't compile:
error[E0401]: can't use generic parameters from outer item
.