Sema: fix enum tag type not initialized when 0 fields

This commit is contained in:
Andrew Kelley
2021-12-26 21:36:12 -07:00
parent 629a54c711
commit f41b9cdb6d
3 changed files with 62 additions and 59 deletions

View File

@@ -1759,6 +1759,11 @@ fn zirEnumDecl(
const body = sema.code.extra[extra_index..][0..body_len];
if (fields_len == 0) {
assert(body.len == 0);
if (tag_type_ref != .none) {
// TODO better source location
const ty = try sema.resolveType(block, src, tag_type_ref);
enum_obj.tag_ty = try ty.copy(new_decl_arena_allocator);
}
try new_decl.finalizeNewArena(&new_decl_arena);
return sema.analyzeDeclVal(block, src, new_decl);
}
@@ -1810,7 +1815,8 @@ fn zirEnumDecl(
const tag_ty = blk: {
if (tag_type_ref != .none) {
// TODO better source location
break :blk try sema.resolveType(block, src, tag_type_ref);
const ty = try sema.resolveType(block, src, tag_type_ref);
break :blk try ty.copy(new_decl_arena_allocator);
}
const bits = std.math.log2_int_ceil(usize, fields_len);
break :blk try Type.Tag.int_unsigned.create(new_decl_arena_allocator, bits);

View File

@@ -646,3 +646,56 @@ test "non-exhaustive enum" {
try S.doTheTest(52);
comptime try S.doTheTest(52);
}
test "empty non-exhaustive enum" {
const S = struct {
const E = enum(u8) { _ };
fn doTheTest(y: u8) !void {
var e = @intToEnum(E, y);
try expect(switch (e) {
_ => true,
});
try expect(@enumToInt(e) == y);
try expect(@typeInfo(E).Enum.fields.len == 0);
try expect(@typeInfo(E).Enum.is_exhaustive == false);
}
};
try S.doTheTest(42);
comptime try S.doTheTest(42);
}
test "single field non-exhaustive enum" {
const S = struct {
const E = enum(u8) { a, _ };
fn doTheTest(y: u8) !void {
var e: E = .a;
try expect(switch (e) {
.a => true,
_ => false,
});
e = @intToEnum(E, 12);
try expect(switch (e) {
.a => false,
_ => true,
});
try expect(switch (e) {
.a => false,
else => true,
});
e = .a;
try expect(switch (e) {
.a => true,
else => false,
});
try expect(@enumToInt(@intToEnum(E, y)) == y);
try expect(@typeInfo(E).Enum.fields.len == 1);
try expect(@typeInfo(E).Enum.is_exhaustive == false);
}
};
try S.doTheTest(23);
comptime try S.doTheTest(23);
}

View File

@@ -2,64 +2,6 @@ const expect = @import("std").testing.expect;
const mem = @import("std").mem;
const Tag = @import("std").meta.Tag;
test "empty non-exhaustive enum" {
const S = struct {
const E = enum(u8) {
_,
};
fn doTheTest(y: u8) !void {
var e = @intToEnum(E, y);
try expect(switch (e) {
_ => true,
});
try expect(@enumToInt(e) == y);
try expect(@typeInfo(E).Enum.fields.len == 0);
try expect(@typeInfo(E).Enum.is_exhaustive == false);
}
};
try S.doTheTest(42);
comptime try S.doTheTest(42);
}
test "single field non-exhaustive enum" {
const S = struct {
const E = enum(u8) { a, _ };
fn doTheTest(y: u8) !void {
var e: E = .a;
try expect(switch (e) {
.a => true,
_ => false,
});
e = @intToEnum(E, 12);
try expect(switch (e) {
.a => false,
_ => true,
});
try expect(switch (e) {
.a => false,
else => true,
});
e = .a;
try expect(switch (e) {
.a => true,
else => false,
});
try expect(@enumToInt(@intToEnum(E, y)) == y);
try expect(@typeInfo(E).Enum.fields.len == 1);
try expect(@typeInfo(E).Enum.is_exhaustive == false);
}
};
try S.doTheTest(23);
comptime try S.doTheTest(23);
}
const Bar = enum { A, B, C, D };
const Number = enum { Zero, One, Two, Three, Four };
test "@tagName" {
try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
@@ -304,6 +246,8 @@ test "enum with one member and custom tag type" {
try expect(@enumToInt(E2.One) == 2);
}
const Bar = enum { A, B, C, D };
test "enum literal casting to optional" {
var bar: ?Bar = undefined;
bar = .B;