idanarye/rust-typed-builder

Const generics with other generics yields compilation error

Closed this issue · 1 comments

use typed_builder::TypedBuilder;

// works
#[derive(TypedBuilder)]
struct TestA<const A: usize> {
    data: [u32; A],
}

// works
#[derive(TypedBuilder)]
struct TestB<A, B> {
    data: [A; 3],
    data2: [B; 3],
}

// doesn't work
// #[derive(TypedBuilder)]
// struct TestC<const NUM_COLS: usize, const NUM_ROWS: usize> {
//     data: [[u32; NUM_ROWS]; NUM_COLS],
// }

// doesn't work
// #[derive(TypedBuilder)]
// struct TestD<const A: usize, const B: usize> {
//     data: [u32; A],
//     data2: [u32; B],
// }

// doesn't work
// #[derive(TypedBuilder)]
// struct TestE<const A: usize, B> {
//     data: [u32; A],
//     data2: [B; 3],
// }

deriving on struct TestC yields this:

impl<const NUM_COLS: usize, const NUM_ROWS: usize> TestC<NUM_COLS, NUM_ROWS> {
    #[doc = "\n                Create a builder for building `TestC`.\n                On the builder, call `.data(...)` to set the values of the fields.\n                Finally, call `.build()` to create the instance of `TestC`.\n                "]
    #[allow(dead_code, clippy::default_trait_access)]
    fn builder() -> TestCBuilder<NUM_COLS, NUM_ROWS, ((),)> {
        TestCBuilder {
            fields: ((),),
            phantom: ::core::default::Default::default(),
        }
    }
}
#[must_use]
#[doc(hidden)]
#[allow(dead_code, non_camel_case_types, non_snake_case)]
struct TestCBuilder<const NUM_COLS: usize, const NUM_ROWS: usize, TypedBuilderFields = ((),)> {
    fields: TypedBuilderFields,
    phantom: ::core::marker::PhantomData<(,)>, // ERROR HERE
}
impl<const NUM_COLS: usize, const NUM_ROWS: usize, TypedBuilderFields> Clone
    for TestCBuilder<NUM_COLS, NUM_ROWS, TypedBuilderFields>
where
    TypedBuilderFields: Clone,
{
    #[allow(clippy::default_trait_access)]
    fn clone(&self) -> Self {
        Self {
            fields: self.fields.clone(),
            phantom: ::core::marker::PhantomData,
        }
    }
}
#[allow(dead_code, non_camel_case_types, missing_docs)]
impl<const NUM_COLS: usize, const NUM_ROWS: usize> TestCBuilder<NUM_COLS, NUM_ROWS, ((),)> {
    pub fn data(
        self,
        data: [[u32; NUM_ROWS]; NUM_COLS],
    ) -> TestCBuilder<NUM_COLS, NUM_ROWS, (([[u32; NUM_ROWS]; NUM_COLS],),)> {
        let data = (data,);
        let (_,) = self.fields;
        TestCBuilder {
            fields: (data,),
            phantom: self.phantom,
        }
    }
}
#[doc(hidden)]
#[allow(dead_code, non_camel_case_types, non_snake_case)]
pub enum TestCBuilder_Error_Repeated_field_data {}

#[doc(hidden)]
#[allow(dead_code, non_camel_case_types, missing_docs)]
impl<const NUM_COLS: usize, const NUM_ROWS: usize>
    TestCBuilder<NUM_COLS, NUM_ROWS, (([[u32; NUM_ROWS]; NUM_COLS],),)>
{
    #[deprecated(note = "Repeated field data")]
    pub fn data(
        self,
        _: TestCBuilder_Error_Repeated_field_data,
    ) -> TestCBuilder<NUM_COLS, NUM_ROWS, (([[u32; NUM_ROWS]; NUM_COLS],),)> {
        self
    }
}
#[doc(hidden)]
#[allow(dead_code, non_camel_case_types, non_snake_case)]
pub enum TestCBuilder_Error_Missing_required_field_data {}

#[doc(hidden)]
#[allow(dead_code, non_camel_case_types, missing_docs, clippy::panic)]
impl<const NUM_COLS: usize, const NUM_ROWS: usize> TestCBuilder<NUM_COLS, NUM_ROWS, ((),)> {
    #[deprecated(note = "Missing required field data")]
    pub fn build(self, _: TestCBuilder_Error_Missing_required_field_data) -> ! {
        panic!()
    }
}
#[allow(dead_code, non_camel_case_types, missing_docs)]
impl<const NUM_COLS: usize, const NUM_ROWS: usize>
    TestCBuilder<NUM_COLS, NUM_ROWS, (([[u32; NUM_ROWS]; NUM_COLS],),)>
{
    #[allow(clippy::default_trait_access)]
    pub fn build(self) -> TestC<NUM_COLS, NUM_ROWS> {
        let (data,) = self.fields;
        let data = data.0;
        #[allow(deprecated)]
        TestC { data }.into()
    }
}

We can see in the "ERROR HERE" comment, it generates an extra "," in the phantom which breaks everything

Fixed with a48ed34