Skip to content

Commit 21ed939

Browse files
committed
support enum literals implicit casting to tagged unions
1 parent 163a8e9 commit 21ed939

File tree

2 files changed

+57
-15
lines changed

2 files changed

+57
-15
lines changed

src/ir.cpp

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8993,6 +8993,13 @@ static bool slice_is_const(ZigType *type) {
89938993
return type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
89948994
}
89958995

8996+
static bool is_tagged_union(ZigType *type) {
8997+
if (type->id != ZigTypeIdUnion)
8998+
return false;
8999+
return (type->data.unionation.decl_node->data.container_decl.auto_enum ||
9000+
type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr);
9001+
}
9002+
89969003
static void populate_error_set_table(ErrorTableEntry **errors, ZigType *set) {
89979004
assert(set->id == ZigTypeIdErrorSet);
89989005
for (uint32_t i = 0; i < set->data.error_set.err_count; i += 1) {
@@ -9676,6 +9683,12 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
96769683
continue;
96779684
}
96789685
}
9686+
if (is_tagged_union(prev_type) && cur_type->id == ZigTypeIdEnumLiteral) {
9687+
TypeUnionField *field = find_union_type_field(prev_type, cur_inst->value.data.x_enum_literal);
9688+
if (field != nullptr) {
9689+
continue;
9690+
}
9691+
}
96799692

96809693
if (cur_type->id == ZigTypeIdEnum && prev_type->id == ZigTypeIdEnumLiteral) {
96819694
TypeEnumField *field = find_enum_type_field(cur_type, prev_inst->value.data.x_enum_literal);
@@ -9685,6 +9698,14 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
96859698
}
96869699
}
96879700

9701+
if (is_tagged_union(cur_type) && prev_type->id == ZigTypeIdEnumLiteral) {
9702+
TypeUnionField *field = find_union_type_field(cur_type, prev_inst->value.data.x_enum_literal);
9703+
if (field != nullptr) {
9704+
prev_inst = cur_inst;
9705+
continue;
9706+
}
9707+
}
9708+
96889709
if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenC &&
96899710
(cur_type->id == ZigTypeIdComptimeInt || cur_type->id == ZigTypeIdInt))
96909711
{
@@ -10907,11 +10928,17 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc
1090710928
}
1090810929

1090910930
static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *source_instr,
10910-
IrInstruction *target, ZigType *wanted_type)
10931+
IrInstruction *uncasted_target, ZigType *wanted_type)
1091110932
{
1091210933
Error err;
1091310934
assert(wanted_type->id == ZigTypeIdUnion);
10914-
assert(target->value.type->id == ZigTypeIdEnum);
10935+
10936+
if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusZeroBitsKnown)))
10937+
return ira->codegen->invalid_instruction;
10938+
10939+
IrInstruction *target = ir_implicit_cast(ira, uncasted_target, wanted_type->data.unionation.tag_type);
10940+
if (type_is_invalid(target->value.type))
10941+
return ira->codegen->invalid_instruction;
1091510942

1091610943
if (instr_is_comptime(target)) {
1091710944
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
@@ -11788,17 +11815,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1178811815
}
1178911816
}
1179011817

11791-
// enum to union which has the enum as the tag type
11792-
if (wanted_type->id == ZigTypeIdUnion && actual_type->id == ZigTypeIdEnum &&
11793-
(wanted_type->data.unionation.decl_node->data.container_decl.auto_enum ||
11794-
wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
11818+
// enum to union which has the enum as the tag type, or
11819+
// enum literal to union which has a matching enum as the tag type
11820+
if (is_tagged_union(wanted_type) && (actual_type->id == ZigTypeIdEnum ||
11821+
actual_type->id == ZigTypeIdEnumLiteral))
1179511822
{
11796-
if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusZeroBitsKnown)))
11797-
return ira->codegen->invalid_instruction;
11798-
11799-
if (wanted_type->data.unionation.tag_type == actual_type) {
11800-
return ir_analyze_enum_to_union(ira, source_instr, value, wanted_type);
11801-
}
11823+
return ir_analyze_enum_to_union(ira, source_instr, value, wanted_type);
1180211824
}
1180311825

1180411826
// cast from *T to *[1]T

test/stage1/behavior/enum.zig

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -930,9 +930,9 @@ test "enum literal in array literal" {
930930
two,
931931
};
932932

933-
const array = []Items {
934-
.one,
935-
.two,
933+
const array = []Items{
934+
.one,
935+
.two,
936936
};
937937

938938
expect(array[0] == .one);
@@ -962,3 +962,23 @@ test "enum value allocation" {
962962
expect(@enumToInt(LargeEnum.A1) == 0x80000001);
963963
expect(@enumToInt(LargeEnum.A2) == 0x80000002);
964964
}
965+
966+
test "enum literal casting to tagged union" {
967+
const Arch = union(enum) {
968+
x86_64,
969+
arm: Arm32,
970+
971+
const Arm32 = enum {
972+
v8_5a,
973+
v8_4a,
974+
};
975+
};
976+
977+
var t = true;
978+
var x: Arch = .x86_64;
979+
var y = if (t) x else .x86_64;
980+
switch (y) {
981+
.x86_64 => {},
982+
else => @panic("fail"),
983+
}
984+
}

0 commit comments

Comments
 (0)