Search code examples
zig

Why does `std.meta.stringToEnum` using identical input fail in one context but not another?


I'm playing around with zig trying to make a toy comptime assembler, using std.meta.stringToEnum which appears to be succeeding in one context while failing in another, seemingly with identical inputs. See the following example, where "test a" fails but "test b" succeeds.

const std = @import("std");

const Mnemonic = enum { ADC, SBC, AND };

fn readMnemonic(comptime input: []const u8) struct { Mnemonic, []const u8 } {
    const mnemonic = std.meta.stringToEnum(Mnemonic, input[0..3]) orelse {
        @compileError("Invalid mnemonic encountered: " ++ input[0..3]);
    };

    return .{ mnemonic, input[3..] };
}

test "test a" {
    const mnemonic = readMnemonic("ADCBE");
    try std.testing.expectEqual(Mnemonic.ADC, mnemonic.@"0");
}

test "test b" {
    const mnemonic = std.meta.stringToEnum(Mnemonic, "ADCBE"[0..3]) orelse {
        std.debug.panic("conversion failed", .{});
    };
    try std.testing.expectEqual(Mnemonic.ADC, mnemonic);
}

In "test a", stringToEnum is called in readMnemonic, while it's being called directly in "test b". As far as I can tell, the value supplied to stringToEnum should be identical in both places. Is there some subtle difference between the two?


Solution

  • In "test a", invoke readMnemonic as:

    const mnemonic = comptime readMnemonic("ADCBE");
    

    and the test passes. Alternatively, you can comptime invoke std.meta.stringToEnum in readMnemonic, i.e.

    const mnemonic = comptime std.meta.stringToEnum ...
    

    Comptime interactions with runtime function invocations can be a bit strange.