Skip to content

Missing source location for enum literal that can't coerce into union(enum) #16508

@ghost

Description

Zig Version

0.11.0-dev.4059+17255bed4

Steps to Reproduce and Observed Output

const Opcode = enum {
    i32_const,
    i32_add,
};
const Operand = union(enum) {
    none: void,
    i32: i32,
};

const Instruction = struct {
    opcode: Opcode,
    operand: Operand,
};

fn test_execute(comptime instructions: []const struct { Opcode, Operand }) void {
    comptime var real_instructions: []const Instruction = &.{};
    inline for (instructions) |instruction| {
        real_instructions = real_instructions ++ .{.{ .opcode = instruction[0], .operand = instruction[1] }};
    }
}

test {
    test_execute(&.{
        .{ .i32_const, .{ .i32 = 64 } },
        .{ .i32_const, .{ .i32 = 64 } },
        .{ .i32_add, .{ .none } },
        .{ .i32_const, .{ .i32 = 128 } },
        .{ .i32_add, .{ .none = {} } },
    });
}
$ zig test x.zig -freference-trace
x.zig:25:18: error: expected type 'x.Operand', found 'struct{comptime @TypeOf(.enum_literal) = .none}'
    test_execute(&.{
                 ^
x.zig:5:17: note: union declared here
const Operand = union(enum) {
                ^~~~~
referenced by:
    test_0: x.zig:25:5

Can you spot the mistake?

In

        .{ .i32_add, .{ .none } },

.none has to be .none = {} and then:

$ zig test x.zig -freference-trace
All 1 tests passed.

If I have a much longer list of instructions, this would be even more confusing. It would be really helpful if the compiler pointed at the line where something didn't coerce right.

Expected Output

It might be enough if it just points at a different line instead of the top &.{:

$ zig test x.zig -freference-trace
x.zig:28:25: error: expected type 'x.Operand', found 'struct{comptime @TypeOf(.enum_literal) = .none}'
        .{ .i32_add, .{ .none } },
                     ^~~~~~~~~
x.zig:5:17: note: union declared here
const Operand = union(enum) {
                ^~~~~
referenced by:
    test_0: x.zig:25:5

Even nicer would be if it checks if the union(enum) has a field of the name of the enum literal and if the type is void so it can directly tell you to note: use '.none = {}' instead.

This might be a duplicate of something else but I think the example I provided certainly makes for a nice test case when this is fixed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    error messageThis issue points out an error message that is unhelpful and should be improved.frontendTokenization, parsing, AstGen, Sema, and Liveness.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions