idanarye/rust-typed-builder

`const fn` doesn't work

Opened this issue · 5 comments

use typed_builder::TypedBuilder;

#[derive(TypedBuilder)]
struct Foo {
    // Mandatory Field:
    x: i32,

    // #[builder(default)] without parameter - use the type's default
    // #[builder(setter(strip_option))] - wrap the setter argument with `Some(...)`
    #[builder(default, setter(strip_option))]
    y: Option<i32>,

    // Or you can set the default
    #[builder(default=20)]
    z: i32,
}

fn f() {
    const X: Foo = Foo::builder().z(1).x(2).y(3).build();
}

fn main() {}
error[E0015]: cannot call non-const fn `Foo::builder` in constants
  --> src/main.rs:19:20
   |
19 |     const X: Foo = Foo::builder().z(1).x(2).y(3).build();
   |                    ^^^^^^^^^^^^^^
   |
   = note: calls in constants are limited to constant functions, tuple structs and tuple variants

error[E0015]: cannot call non-const fn `FooBuilder::z` in constants
  --> src/main.rs:19:35
   |
19 |     const X: Foo = Foo::builder().z(1).x(2).y(3).build();
   |                                   ^^^^
   |
   = note: calls in constants are limited to constant functions, tuple structs and tuple variants

I can try adding a top-level #[builder(const)] attribute to make all the generated functions const. Keep in mind though that with the current version of Rust this example could never work, because Default::default is not const. So having a const builder would forbid bare #[builder(default)]s - the one for y will have to change to #[builder(default = None)].

also there are some problems with const fn:

struct Foo {
    s: Option<String>,
}

impl Foo {
    const fn new() -> Self {
        Self { s: None }
    }

    const fn s(mut self, s: String) -> Self {
        self.s = Some(s); //error[E0493]: destructor of `Option<String>` cannot be evaluated at compile-time
        self
    }
}

I don't think that'd be a problem. Typed builder's setters do not override fields, so they don't need to invoke destructors.

Due to the way I parse things, it's going to have to be #[builder(const_)] and not #[builder(const)].

Problem - I can't implement this until const traits get stabilized (rust-lang/rust#67792)

The issue is that I'm using traits in the build method. Unset fields are represented as () and set fields as (T,), and I define a trait that allows me to return a default for the former and the contained value for the latter. With current stable Rust, the method from that trait cannot be const.