std/json: parse* cannot handle `?noreturn`
Zig Version
0.12.0-dev.2928+6fddc9cd3
Steps to Reproduce and Observed Behavior
Minimum reproducible example:
const std = @import("std");
const json = std.json;
pub const Foo = struct {
can_only_be_null: ?noreturn,
};
pub fn main() !void {
const foo = Foo{ .can_only_be_null = null };
try std.json.stringify(foo, .{}, std.io.getStdOut().writer());
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const bar = try std.json.parseFromSlice(Foo, gpa.allocator(), "{\"can_only_be_null\":null}", .{});
std.debug.print("{}", .{bar});
}
Gives the compile-time error:
An error occurred:
/usr/local/bin/lib/std/json/static.zig:506:17: error: Unable to parse into type 'noreturn'
Expected Behavior
While noreturn on its own can't be parsed into, ?noreturn and fn (T: type) type { return union(enum) { x: SomeType, y: T }} (where T is noreturn) are useful. For instance, see Discord's Role Tags Structure, which with an fn Omittable(T) helper, can be represented as Omittable(?noreturn)
Workaround for now can be to use enum{} instead of noreturn, which both represent a type that has 0 possible values. Another workaround is of course to just make a custom type with its own jsonParse and jsonStringify methods.
should specify that Discord's Role Tags Structure is incredibly cursed, but alas, I must parse it. And it'd be very convenient to use Omittable(?noreturn) 😄
Does Omittable(@TypeOf(null)) not work for this usecase? @TypeOf(null) gives you a zero sized type that can only be the value null:
test {
const S = struct {
f: @TypeOf(null),
};
const s = S{ .f = null };
try std.testing.expectEqual(null, s.f);
}
const std = @import("std");
On a sidenote, this is kinda funny:
src/main.zig:7:44: error: no size available for type '@TypeOf(null)'
try std.testing.expectEqual(0, @sizeOf(@TypeOf(null)));
But @sizeOf(S) return 0. Seems like a bug. Is there an issue for this?
Aah no, you cannot have fields of type @TypeOf(null) at runtime. My bad:
test {
const S = struct {
f: @TypeOf(null),
};
var s = S{ .f = null };
try std.testing.expectEqual(0, @sizeOf(@TypeOf(S)));
try std.testing.expectEqual(null, s.f);
s = s;
}
const std = @import("std");
src/main.zig:5:9: error: variable of type 'main.test_0.S' must be const or comptime
var s = S{ .f = null };
^
src/main.zig:3:12: note: struct requires comptime because of this field
f: @TypeOf(null),
Not sure when this changed
@Hejsil I also think of @TypeOf(null) as a runtime-valid type, but it seems like the opposite was invalidly assumed at some point when stage2 was written.
For arguments and return values this has been reported and fixed before: https://github.com/ziglang/zig/pull/16104.
I haven't found an open issue about using it as struct field, but IMO there shouldn't be any disparity between those usages.
Regarding @sizeOf on comptime-only types erroring, that's proposal https://github.com/ziglang/zig/issues/4211 ; currently the langref states that 0 is returned.