Transitive failure

What am I doing wrong here?

const std = @import("std");

const testing = std.testing;

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    const value = toValue(10)(allocator, 20);
    std.debug.print("All your {s} are belong to us.\n", .{value});
}

fn toValue(comptime value: anytype) fn (std.mem.Allocator, anytype) anyerror!@TypeOf(value) {
    return struct {
        fn toValue(_: std.mem.Allocator, _: anytype) !@TypeOf(value) {
            return value;
        }
    }.toValue;
}

test "toValue" {
    const allocator = testing.failing_allocator;
    try testing.expectEqual(10, toValue(10)(allocator, 20));
    try testing.expectEqualStrings("foo", toValue("foo")(allocator, "bar"));
}

Because I get a transitive failure, even though I’m not using any dependencies.

❯ zig build
install
└─ install test
   └─ zig build-exe test Debug native failure
error: the following command terminated unexpectedly:
/usr/local/bin/zig build-exe -ODebug -Mroot=/Users/joelr/Work/Zig/test/src/main.zig --cache-dir /Users/joelr/Work/Zig/test/.zig-cache --global-cache-dir /Users/joelr/.cache/zig --name test --zig-lib-dir /usr/local/lib/zig/ --listen=-
Build Summary: 0/3 steps succeeded; 1 failed
install transitive failure
└─ install test transitive failure
   └─ zig build-exe test Debug native failure
error: the following build command failed with exit code 1:
/Users/joelr/Work/Zig/test/.zig-cache/o/4ae0111ced83033f2da7f7f079d783c5/build /usr/local/bin/zig /usr/local/lib/zig /Users/joelr/Work/Zig/test /Users/joelr/Work/Zig/test/.zig-cache /Users/joelr/.cache/zig --seed 0xe512834 -Zd0358ae2a1e6601d

Not an issue with testing because building this

const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    const value = toValue(10)(allocator, 20);
    std.debug.print("All your {s} are belong to us.\n", .{value});
}

fn toValue(comptime value: anytype) fn (std.mem.Allocator, anytype) anyerror!@TypeOf(value) {
    return struct {
        fn toValue(_: std.mem.Allocator, _: anytype) !@TypeOf(value) {
            return value;
        }
    }.toValue;
}

still gives me this error

❯ zig build
install
└─ install test
   └─ zig build-exe test Debug native failure
error: the following command terminated unexpectedly:
/usr/local/bin/zig build-exe -ODebug -Mroot=/Users/joelr/Work/Zig/test/src/main.zig --cache-dir /Users/joelr/Work/Zig/test/.zig-cache --global-cache-dir /Users/joelr/.cache/zig --name test --zig-lib-dir /usr/local/lib/zig/ --listen=-
Build Summary: 0/3 steps succeeded; 1 failed
install transitive failure
└─ install test transitive failure
   └─ zig build-exe test Debug native failure
error: the following build command failed with exit code 1:
/Users/joelr/Work/Zig/test/.zig-cache/o/4ae0111ced83033f2da7f7f079d783c5/build /usr/local/bin/zig /usr/local/lib/zig /Users/joelr/Work/Zig/test /Users/joelr/Work/Zig/test/.zig-cache /Users/joelr/.cache/zig --seed 0x55c54982 -Z381019e07a3ef546

I’ve tried reducing your program, and at some point the transitive failure turns into an OutOfMemory error. I think this is a Zig bug:

const std = @import("std");

pub fn main() void {
    _ = &toValue(10);
}

fn toValue(comptime value: anytype) fn (anytype) @TypeOf(value) {
    return struct {
        fn toValue(_: anytype) @TypeOf(value) {
            return value;
        }
    }.toValue;
}
$ zig build run
run
└─ run t
   └─ zig build-exe t Debug native failure
error: error: OutOfMemory

error: the following command exited with error code 1:
/home/joe/.local/bin/zig build-exe -ODebug -Mroot=/home/joe/dev/test/t/src/main.zig --cache-dir /home/joe/dev/test/t/.zig-cache --global-cache-dir /home/joe/.cache/zig --name t --zig-lib-dir /home/joe/.local/lib/zig/ --listen=-
Build Summary: 2/7 steps succeeded; 1 failed
run transitive failure
└─ run t transitive failure
   ├─ zig build-exe t Debug native failure
   └─ install transitive failure
      └─ install t transitive failure
         └─ zig build-exe t Debug native (reused)
error: the following build command failed with exit code 1:
/home/joe/dev/test/t/.zig-cache/o/d6ab6ac316016b1fb96986f35985df59/build /home/joe/.local/bin/zig /home/joe/.local/lib/zig /home/joe/dev/test/t /home/joe/dev/test/t/.zig-cache /home/joe/.cache/zig --seed 0xcf2b4b4d -Zfb3c70f1c60d0fa9 run

Possibly an issue with resolving the type of the anytype parameter.

Let report it then…

Also, any suggestions on how I can achieve what I’m trying to do, i.e. return a value from a closure?

What are you trying to achieve with toValue?

I’m not clear on what exactly your intent is with this, but I have a suspicion that you meant to take a type parameter for toValue rather than anytype (“a value of any type”).

I’m trying to have a Mecha parser return a given value, e.g.

const eqOp = m.oneOf(.{
    _eq.map(toValue(.eq)),
    _neq.map(toValue(.neq)),
});

const EqOp = enum { eq, neq };

There’s a toEnum conversion function but that requires me to use eq and neq in expressions I’m trying to parse, not == and !=.

The value I want to return is specified at parse construction (compile) time and I’m ignoring the allocator and parsed value given to me at runtime by Mecha.

P.S. I filed a bug report.

This works but depends on the parser feeding in a string.

fn toValue(comptime T: type, value: T) fn (std.mem.Allocator, []const u8) anyerror!T {
    return struct {
        fn toValue(_: std.mem.Allocator, _: []const u8) anyerror!T {
            return value;
        }
    }.toValue;
}