Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

forward default typeparam #319

Merged
merged 2 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion derive_builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@
//! - Tuple structs and unit structs are not supported as they have no field
//! names.
//! - Generic setters introduce a type parameter `VALUE: Into<_>`. Therefore you can't use
//! `VALUE` as a type parameter on a generic struct in combination with generic setters.
//! `VALUE` as a type parameter on a generic struct in combination with generic setters.
//! - The `try_setter` attribute and `owned` builder pattern are not compatible in practice;
//! an error during building will consume the builder, making it impossible to continue
//! construction.
Expand Down
30 changes: 30 additions & 0 deletions derive_builder/tests/run-pass/default_typeparams.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//! Test ensuring that default type params gets forwarded to Builder.

#[macro_use]
extern crate derive_builder;

#[derive(Builder)]
#[builder(setter(strip_option))]
struct Settings<T, U = (), C = fn(T) -> U> {
first: T,
#[builder(default)]
second: Option<U>,
#[builder(default)]
third: Option<C>,
}

fn main() {
SettingsBuilder::<usize>::default()
.first(1)
.second(())
.third(|_: usize| ())
.build()
.unwrap();

SettingsBuilder::<usize, usize>::default()
.first(1)
.second(2)
.third(|_: usize| 3)
.build()
.unwrap();
}
80 changes: 71 additions & 9 deletions derive_builder_core/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,14 @@ impl<'a> ToTokens for Builder<'a> {
let crate_root = self.crate_root;
let builder_vis = &self.visibility;
let builder_ident = &self.ident;
// Splitting because Generics doesn't output WhereClause, see dtolnay/syn#782
let (struct_generics, struct_where_clause) = (
self.generics,
self.generics.and_then(|g| g.where_clause.as_ref()),
);
let bounded_generics = self.compute_impl_bounds();
let (impl_generics, _, _) = bounded_generics.split_for_impl();
let (struct_generics, ty_generics, where_clause) = self
.generics
.map(syn::Generics::split_for_impl)
.map(|(i, t, w)| (Some(i), Some(t), Some(w)))
.unwrap_or((None, None, None));
let (impl_generics, impl_ty_generics, impl_where_clause) =
bounded_generics.split_for_impl();
let builder_fields = &self.fields;
let builder_field_initializers = &self.field_initializers;
let create_empty = &self.create_empty;
Expand Down Expand Up @@ -203,7 +204,7 @@ impl<'a> ToTokens for Builder<'a> {
#derive_attr
#(#struct_attrs)*
#builder_doc_comment
#builder_vis struct #builder_ident #struct_generics #where_clause {
#builder_vis struct #builder_ident #struct_generics #struct_where_clause {
#(#builder_fields)*
}
));
Expand All @@ -214,7 +215,7 @@ impl<'a> ToTokens for Builder<'a> {
tokens.append_all(quote!(
#(#impl_attrs)*
#[allow(dead_code)]
impl #impl_generics #builder_ident #ty_generics #where_clause {
impl #impl_generics #builder_ident #impl_ty_generics #impl_where_clause {
#(#functions)*
#deprecation_notes

Expand All @@ -229,7 +230,7 @@ impl<'a> ToTokens for Builder<'a> {

if self.impl_default {
tokens.append_all(quote!(
impl #impl_generics #crate_root::export::core::default::Default for #builder_ident #ty_generics #where_clause {
impl #impl_generics #crate_root::export::core::default::Default for #builder_ident #impl_ty_generics #impl_where_clause {
fn default() -> Self {
Self::#create_empty()
}
Expand Down Expand Up @@ -675,6 +676,67 @@ mod tests {
);
}

// This test depends on the exact formatting of the `stringify`'d code,
// so we don't automatically format the test
#[rustfmt::skip]
#[test]
fn generic_with_default_type() {
let ast: syn::DeriveInput = parse_quote! {
struct Lorem<T = ()> { }
};

let generics = ast.generics;
let mut builder = default_builder!();
builder.generics = Some(&generics);

assert_eq!(
quote!(#builder).to_string(),
{
let mut result = quote!();

#[cfg(not(feature = "clippy"))]
result.append_all(quote!(#[allow(clippy::all)]));

result.append_all(quote!(
#[derive(Clone)]
pub struct FooBuilder<T = ()> {
foo: u32,
}
));

#[cfg(not(feature = "clippy"))]
result.append_all(quote!(#[allow(clippy::all)]));

result.append_all(quote!(
#[allow(dead_code)]
impl<T: ::db::export::core::clone::Clone> FooBuilder<T>
{
fn bar() -> {
unimplemented!()
}

/// Create an empty builder, with all fields set to `None` or `PhantomData`.
fn create_empty() -> Self {
Self {
foo: ::db::export::core::default::Default::default(),
}
}
}

impl<T: ::db::export::core::clone::Clone> ::db::export::core::default::Default for FooBuilder<T> {
fn default() -> Self {
Self::create_empty()
}
}
));

add_generated_error(&mut result);

result
}.to_string()
);
}

// This test depends on the exact formatting of the `stringify`'d code,
// so we don't automatically format the test
#[rustfmt::skip]
Expand Down
2 changes: 1 addition & 1 deletion derive_builder_core/src/macro_options/darling_opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ pub struct BuildFn {
/// * `validation_error = bool` - Whether to generate `ValidationError(String)` as a variant
/// of the build error type. Setting this to `false` will prevent `derive_builder` from
/// using the `validate` function but this also means it does not generate any usage of the
/// `alloc` crate (useful when disabling the `alloc` feature in `no_std`).
/// `alloc` crate (useful when disabling the `alloc` feature in `no_std`).
///
/// # Type Bounds for Custom Error
/// This type's bounds depend on other settings of the builder.
Expand Down
2 changes: 1 addition & 1 deletion derive_builder_no_alloc_tests/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![no_std]
#![allow(unused, clippy::blacklisted_name)]
#![allow(unused, clippy::disallowed_names)]

use derive_builder::{self, Builder};

Expand Down