Hello everyone, I would like to show off my recent abuse of comptime:
fn ParseRecursiveError(MaybeArena: type) type {
return switch (MaybeArena) {
std.mem.Allocator => ParseAllocError,
@TypeOf(null) => ParseError,
else => comptime unreachable,
};
}
fn parseRecursive(
comptime command: Command,
/// Provide comptime null if we know we won't allocate,
/// otherwise provide std.mem.Allocator (arena suggested).
maybe_arena: anytype,
iter: *Iterator,
options: ParseOptions,
) ParseRecursiveError(@TypeOf(maybe_arena))!Parsed(command) {
...
}
In this example, I can restrict the type of maybe_arena to comptime @TypeOf(null) or std.mem.Allocator. If I attempt to allocate when I don’t want to (when I pass null to maybe_alloc), I will get a compile error. So i’ve got complicated logic that hides all my allocations at comptime and if I violate that I get a compile error because maybe_alloc will be comptime-known.
I can also restrict the error set of ParseRecursive to not have error.OutOfMemory when I pass comptime null to maybe_alloc so I can delete it from my error switches and I don’t have to mark them unreachable when I know they are comptime unreachable.
So I think I have modeled something like this:
const MaybeArena = union(enum) {
Arena: std.mem.Allocator,
Null: @typeOf(Null),
}
Where the union tag is comptime known.