Commit 21ed939117

Andrew Kelley <andrew@ziglang.org>
2019-05-26 18:59:30
support enum literals implicit casting to tagged unions
1 parent 163a8e9
Changed files (2)
src
test
stage1
behavior
src/ir.cpp
@@ -8993,6 +8993,13 @@ static bool slice_is_const(ZigType *type) {
     return type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
 }
 
+static bool is_tagged_union(ZigType *type) {
+    if (type->id != ZigTypeIdUnion)
+        return false;
+    return (type->data.unionation.decl_node->data.container_decl.auto_enum ||
+        type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr);
+}
+
 static void populate_error_set_table(ErrorTableEntry **errors, ZigType *set) {
     assert(set->id == ZigTypeIdErrorSet);
     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
                 continue;
             }
         }
+        if (is_tagged_union(prev_type) && cur_type->id == ZigTypeIdEnumLiteral) {
+            TypeUnionField *field = find_union_type_field(prev_type, cur_inst->value.data.x_enum_literal);
+            if (field != nullptr) {
+                continue;
+            }
+        }
 
         if (cur_type->id == ZigTypeIdEnum && prev_type->id == ZigTypeIdEnumLiteral) {
             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
             }
         }
 
+        if (is_tagged_union(cur_type) && prev_type->id == ZigTypeIdEnumLiteral) {
+            TypeUnionField *field = find_union_type_field(cur_type, prev_inst->value.data.x_enum_literal);
+            if (field != nullptr) {
+                prev_inst = cur_inst;
+                continue;
+            }
+        }
+
         if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenC &&
             (cur_type->id == ZigTypeIdComptimeInt || cur_type->id == ZigTypeIdInt))
         {
@@ -10907,11 +10928,17 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc
 }
 
 static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *source_instr,
-        IrInstruction *target, ZigType *wanted_type)
+        IrInstruction *uncasted_target, ZigType *wanted_type)
 {
     Error err;
     assert(wanted_type->id == ZigTypeIdUnion);
-    assert(target->value.type->id == ZigTypeIdEnum);
+
+    if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusZeroBitsKnown)))
+        return ira->codegen->invalid_instruction;
+
+    IrInstruction *target = ir_implicit_cast(ira, uncasted_target, wanted_type->data.unionation.tag_type);
+    if (type_is_invalid(target->value.type))
+        return ira->codegen->invalid_instruction;
 
     if (instr_is_comptime(target)) {
         ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
@@ -11788,17 +11815,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
         }
     }
 
-    // enum to union which has the enum as the tag type
-    if (wanted_type->id == ZigTypeIdUnion && actual_type->id == ZigTypeIdEnum &&
-        (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum ||
-        wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
+    // enum to union which has the enum as the tag type, or
+    // enum literal to union which has a matching enum as the tag type
+    if (is_tagged_union(wanted_type) && (actual_type->id == ZigTypeIdEnum ||
+                actual_type->id == ZigTypeIdEnumLiteral))
     {
-        if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusZeroBitsKnown)))
-            return ira->codegen->invalid_instruction;
-
-        if (wanted_type->data.unionation.tag_type == actual_type) {
-            return ir_analyze_enum_to_union(ira, source_instr, value, wanted_type);
-        }
+        return ir_analyze_enum_to_union(ira, source_instr, value, wanted_type);
     }
 
     // cast from *T to *[1]T
test/stage1/behavior/enum.zig
@@ -930,9 +930,9 @@ test "enum literal in array literal" {
         two,
     };
 
-    const array = []Items {
-      .one,
-      .two,
+    const array = []Items{
+        .one,
+        .two,
     };
 
     expect(array[0] == .one);
@@ -962,3 +962,23 @@ test "enum value allocation" {
     expect(@enumToInt(LargeEnum.A1) == 0x80000001);
     expect(@enumToInt(LargeEnum.A2) == 0x80000002);
 }
+
+test "enum literal casting to tagged union" {
+    const Arch = union(enum) {
+        x86_64,
+        arm: Arm32,
+
+        const Arm32 = enum {
+            v8_5a,
+            v8_4a,
+        };
+    };
+
+    var t = true;
+    var x: Arch = .x86_64;
+    var y = if (t) x else .x86_64;
+    switch (y) {
+        .x86_64 => {},
+        else => @panic("fail"),
+    }
+}