Commit 5a8367e892

Andrew Kelley <superjoe30@gmail.com>
2017-12-04 04:36:01
rename @EnumTagType to @TagType. add tests for union-enums
See #618
1 parent 0ad1239
src/all_types.hpp
@@ -1266,7 +1266,7 @@ enum BuiltinFnId {
     BuiltinFnIdIntToPtr,
     BuiltinFnIdPtrToInt,
     BuiltinFnIdTagName,
-    BuiltinFnIdEnumTagType,
+    BuiltinFnIdTagType,
     BuiltinFnIdFieldParentPtr,
     BuiltinFnIdOffsetOf,
     BuiltinFnIdInlineCall,
@@ -1889,8 +1889,8 @@ enum IrInstructionId {
     IrInstructionIdSetGlobalLinkage,
     IrInstructionIdDeclRef,
     IrInstructionIdPanic,
-    IrInstructionIdEnumTagName,
-    IrInstructionIdEnumTagType,
+    IrInstructionIdTagName,
+    IrInstructionIdTagType,
     IrInstructionIdFieldParentPtr,
     IrInstructionIdOffsetOf,
     IrInstructionIdTypeId,
@@ -2652,13 +2652,13 @@ struct IrInstructionPanic {
     IrInstruction *msg;
 };
 
-struct IrInstructionEnumTagName {
+struct IrInstructionTagName {
     IrInstruction base;
 
     IrInstruction *target;
 };
 
-struct IrInstructionEnumTagType {
+struct IrInstructionTagType {
     IrInstruction base;
 
     IrInstruction *target;
src/codegen.cpp
@@ -2717,7 +2717,7 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
 }
 
 static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable,
-        IrInstructionEnumTagName *instruction)
+        IrInstructionTagName *instruction)
 {
     TypeTableEntry *enum_type = instruction->target->value.type;
     assert(enum_type->id == TypeTableEntryIdEnum);
@@ -3484,7 +3484,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
         case IrInstructionIdOpaqueType:
         case IrInstructionIdSetAlignStack:
         case IrInstructionIdArgType:
-        case IrInstructionIdEnumTagType:
+        case IrInstructionIdTagType:
             zig_unreachable();
         case IrInstructionIdReturn:
             return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -3594,8 +3594,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
             return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction);
         case IrInstructionIdPanic:
             return ir_render_panic(g, executable, (IrInstructionPanic *)instruction);
-        case IrInstructionIdEnumTagName:
-            return ir_render_enum_tag_name(g, executable, (IrInstructionEnumTagName *)instruction);
+        case IrInstructionIdTagName:
+            return ir_render_enum_tag_name(g, executable, (IrInstructionTagName *)instruction);
         case IrInstructionIdFieldParentPtr:
             return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction);
         case IrInstructionIdAlignCast:
@@ -4963,7 +4963,7 @@ static void define_builtin_fns(CodeGen *g) {
     create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2);
     create_builtin_fn(g, BuiltinFnIdPtrToInt, "ptrToInt", 1);
     create_builtin_fn(g, BuiltinFnIdTagName, "tagName", 1);
-    create_builtin_fn(g, BuiltinFnIdEnumTagType, "EnumTagType", 1);
+    create_builtin_fn(g, BuiltinFnIdTagType, "TagType", 1);
     create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3);
     create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2);
     create_builtin_fn(g, BuiltinFnIdDivExact, "divExact", 2);
src/ir.cpp
@@ -539,12 +539,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPanic *) {
     return IrInstructionIdPanic;
 }
 
-static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTagName *) {
-    return IrInstructionIdEnumTagName;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionTagName *) {
+    return IrInstructionIdTagName;
 }
 
-static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTagType *) {
-    return IrInstructionIdEnumTagType;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionTagType *) {
+    return IrInstructionIdTagType;
 }
 
 static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldParentPtr *) {
@@ -2205,10 +2205,10 @@ static IrInstruction *ir_build_panic(IrBuilder *irb, Scope *scope, AstNode *sour
     return &instruction->base;
 }
 
-static IrInstruction *ir_build_enum_tag_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
+static IrInstruction *ir_build_tag_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
         IrInstruction *target)
 {
-    IrInstructionEnumTagName *instruction = ir_build_instruction<IrInstructionEnumTagName>(irb, scope, source_node);
+    IrInstructionTagName *instruction = ir_build_instruction<IrInstructionTagName>(irb, scope, source_node);
     instruction->target = target;
 
     ir_ref_instruction(target, irb->current_basic_block);
@@ -2216,10 +2216,10 @@ static IrInstruction *ir_build_enum_tag_name(IrBuilder *irb, Scope *scope, AstNo
     return &instruction->base;
 }
 
-static IrInstruction *ir_build_enum_tag_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
+static IrInstruction *ir_build_tag_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
         IrInstruction *target)
 {
-    IrInstructionEnumTagType *instruction = ir_build_instruction<IrInstructionEnumTagType>(irb, scope, source_node);
+    IrInstructionTagType *instruction = ir_build_instruction<IrInstructionTagType>(irb, scope, source_node);
     instruction->target = target;
 
     ir_ref_instruction(target, irb->current_basic_block);
@@ -3002,14 +3002,14 @@ static IrInstruction *ir_instruction_panic_get_dep(IrInstructionPanic *instructi
     }
 }
 
-static IrInstruction *ir_instruction_enumtagname_get_dep(IrInstructionEnumTagName *instruction, size_t index) {
+static IrInstruction *ir_instruction_enumtagname_get_dep(IrInstructionTagName *instruction, size_t index) {
     switch (index) {
         case 0: return instruction->target;
         default: return nullptr;
     }
 }
 
-static IrInstruction *ir_instruction_enumtagtype_get_dep(IrInstructionEnumTagType *instruction, size_t index) {
+static IrInstruction *ir_instruction_enumtagtype_get_dep(IrInstructionTagType *instruction, size_t index) {
     switch (index) {
         case 0: return instruction->target;
         default: return nullptr;
@@ -3270,10 +3270,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
             return ir_instruction_declref_get_dep((IrInstructionDeclRef *) instruction, index);
         case IrInstructionIdPanic:
             return ir_instruction_panic_get_dep((IrInstructionPanic *) instruction, index);
-        case IrInstructionIdEnumTagName:
-            return ir_instruction_enumtagname_get_dep((IrInstructionEnumTagName *) instruction, index);
-        case IrInstructionIdEnumTagType:
-            return ir_instruction_enumtagtype_get_dep((IrInstructionEnumTagType *) instruction, index);
+        case IrInstructionIdTagName:
+            return ir_instruction_enumtagname_get_dep((IrInstructionTagName *) instruction, index);
+        case IrInstructionIdTagType:
+            return ir_instruction_enumtagtype_get_dep((IrInstructionTagType *) instruction, index);
         case IrInstructionIdFieldParentPtr:
             return ir_instruction_fieldparentptr_get_dep((IrInstructionFieldParentPtr *) instruction, index);
         case IrInstructionIdOffsetOf:
@@ -4627,16 +4627,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
                     return arg0_value;
 
                 IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value);
-                return ir_build_enum_tag_name(irb, scope, node, actual_tag);
+                return ir_build_tag_name(irb, scope, node, actual_tag);
             }
-        case BuiltinFnIdEnumTagType:
+        case BuiltinFnIdTagType:
             {
                 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
                 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
                 if (arg0_value == irb->codegen->invalid_instruction)
                     return arg0_value;
 
-                return ir_build_enum_tag_type(irb, scope, node, arg0_value);
+                return ir_build_tag_type(irb, scope, node, arg0_value);
             }
         case BuiltinFnIdFieldParentPtr:
             {
@@ -13638,7 +13638,7 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc
     return str_type;
 }
 
-static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstructionEnumTagName *instruction) {
+static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstructionTagName *instruction) {
     IrInstruction *target = instruction->target->other;
     if (type_is_invalid(target->value.type))
         return ira->codegen->builtin_types.entry_invalid;
@@ -13658,7 +13658,7 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn
         ira->codegen->name_table_enums.append(target->value.type);
     }
 
-    IrInstruction *result = ir_build_enum_tag_name(&ira->new_irb, instruction->base.scope,
+    IrInstruction *result = ir_build_tag_name(&ira->new_irb, instruction->base.scope,
             instruction->base.source_node, target);
     ir_link_new_instruction(result, &instruction->base);
     TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
@@ -15838,22 +15838,43 @@ static TypeTableEntry *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruc
     return ira->codegen->builtin_types.entry_type;
 }
 
-static TypeTableEntry *ir_analyze_instruction_enum_tag_type(IrAnalyze *ira, IrInstructionEnumTagType *instruction) {
+static TypeTableEntry *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstructionTagType *instruction) {
     IrInstruction *target_inst = instruction->target->other;
     TypeTableEntry *enum_type = ir_resolve_type(ira, target_inst);
     if (type_is_invalid(enum_type))
         return ira->codegen->builtin_types.entry_invalid;
-    if (enum_type->id != TypeTableEntryIdEnum) {
-        ir_add_error(ira, target_inst, buf_sprintf("expected enum, found '%s'", buf_ptr(&enum_type->name)));
+
+    if (enum_type->id == TypeTableEntryIdEnum) {
+        ensure_complete_type(ira->codegen, enum_type);
+        if (type_is_invalid(enum_type))
+            return ira->codegen->builtin_types.entry_invalid;
+
+        ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+        out_val->data.x_type = enum_type->data.enumeration.tag_int_type;
+        return ira->codegen->builtin_types.entry_type;
+    } else if (enum_type->id == TypeTableEntryIdUnion) {
+        ensure_complete_type(ira->codegen, enum_type);
+        if (type_is_invalid(enum_type))
+            return ira->codegen->builtin_types.entry_invalid;
+
+        AstNode *decl_node = enum_type->data.unionation.decl_node;
+        if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
+            assert(enum_type->data.unionation.tag_type != nullptr);
+
+            ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+            out_val->data.x_type = enum_type->data.unionation.tag_type;
+            return ira->codegen->builtin_types.entry_type;
+        } else {
+            ErrorMsg *msg = ir_add_error(ira, target_inst, buf_sprintf("union '%s' has no tag",
+                buf_ptr(&enum_type->name)));
+            add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here"));
+            return ira->codegen->builtin_types.entry_invalid;
+        }
+    } else {
+        ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'",
+            buf_ptr(&enum_type->name)));
         return ira->codegen->builtin_types.entry_invalid;
     }
-    ensure_complete_type(ira->codegen, enum_type);
-    if (type_is_invalid(enum_type))
-        return ira->codegen->builtin_types.entry_invalid;
-
-    ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
-    out_val->data.x_type = enum_type->data.enumeration.tag_int_type;
-    return ira->codegen->builtin_types.entry_type;
 }
 
 static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
@@ -16032,8 +16053,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
             return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction);
         case IrInstructionIdPtrToInt:
             return ir_analyze_instruction_ptr_to_int(ira, (IrInstructionPtrToInt *)instruction);
-        case IrInstructionIdEnumTagName:
-            return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionEnumTagName *)instruction);
+        case IrInstructionIdTagName:
+            return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionTagName *)instruction);
         case IrInstructionIdFieldParentPtr:
             return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction);
         case IrInstructionIdOffsetOf:
@@ -16052,8 +16073,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
             return ir_analyze_instruction_set_align_stack(ira, (IrInstructionSetAlignStack *)instruction);
         case IrInstructionIdArgType:
             return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction);
-        case IrInstructionIdEnumTagType:
-            return ir_analyze_instruction_enum_tag_type(ira, (IrInstructionEnumTagType *)instruction);
+        case IrInstructionIdTagType:
+            return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction);
     }
     zig_unreachable();
 }
@@ -16230,14 +16251,14 @@ bool ir_has_side_effects(IrInstruction *instruction) {
         case IrInstructionIdDeclRef:
         case IrInstructionIdErrName:
         case IrInstructionIdTypeName:
-        case IrInstructionIdEnumTagName:
+        case IrInstructionIdTagName:
         case IrInstructionIdFieldParentPtr:
         case IrInstructionIdOffsetOf:
         case IrInstructionIdTypeId:
         case IrInstructionIdAlignCast:
         case IrInstructionIdOpaqueType:
         case IrInstructionIdArgType:
-        case IrInstructionIdEnumTagType:
+        case IrInstructionIdTagType:
             return false;
         case IrInstructionIdAsm:
             {
src/ir_print.cpp
@@ -872,8 +872,8 @@ static void ir_print_type_name(IrPrint *irp, IrInstructionTypeName *instruction)
     ir_print_other_instruction(irp, instruction->type_value);
 }
 
-static void ir_print_enum_tag_name(IrPrint *irp, IrInstructionEnumTagName *instruction) {
-    fprintf(irp->f, "enumtagname ");
+static void ir_print_tag_name(IrPrint *irp, IrInstructionTagName *instruction) {
+    fprintf(irp->f, "tagname ");
     ir_print_other_instruction(irp, instruction->target);
 }
 
@@ -981,8 +981,8 @@ static void ir_print_arg_type(IrPrint *irp, IrInstructionArgType *instruction) {
     fprintf(irp->f, ")");
 }
 
-static void ir_print_enum_tag_type(IrPrint *irp, IrInstructionEnumTagType *instruction) {
-    fprintf(irp->f, "@EnumTagType(");
+static void ir_print_enum_tag_type(IrPrint *irp, IrInstructionTagType *instruction) {
+    fprintf(irp->f, "@TagType(");
     ir_print_other_instruction(irp, instruction->target);
     fprintf(irp->f, ")");
 }
@@ -1254,8 +1254,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdTypeName:
             ir_print_type_name(irp, (IrInstructionTypeName *)instruction);
             break;
-        case IrInstructionIdEnumTagName:
-            ir_print_enum_tag_name(irp, (IrInstructionEnumTagName *)instruction);
+        case IrInstructionIdTagName:
+            ir_print_tag_name(irp, (IrInstructionTagName *)instruction);
             break;
         case IrInstructionIdCanImplicitCast:
             ir_print_can_implicit_cast(irp, (IrInstructionCanImplicitCast *)instruction);
@@ -1299,8 +1299,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
         case IrInstructionIdArgType:
             ir_print_arg_type(irp, (IrInstructionArgType *)instruction);
             break;
-        case IrInstructionIdEnumTagType:
-            ir_print_enum_tag_type(irp, (IrInstructionEnumTagType *)instruction);
+        case IrInstructionIdTagType:
+            ir_print_enum_tag_type(irp, (IrInstructionTagType *)instruction);
             break;
     }
     fprintf(irp->f, "\n");
test/cases/enum.zig
@@ -204,12 +204,12 @@ test "set enum tag type" {
     {
         var x = Small.One;
         x = Small.Two;
-        comptime assert(@EnumTagType(Small) == u2);
+        comptime assert(@TagType(Small) == u2);
     }
     {
         var x = Small2.One;
         x = Small2.Two;
-        comptime assert(@EnumTagType(Small2) == u2);
+        comptime assert(@TagType(Small2) == u2);
     }
 }
 
test/cases/union.zig
@@ -104,3 +104,36 @@ fn bar(value: &const Payload) -> i32 {
         Payload.C => |x| if (x) i32(30) else 31,
     };
 }
+
+const MultipleChoice2 = union(enum(u32)) {
+    Unspecified1: i32,
+    A: f32 = 20,
+    Unspecified2: void,
+    B: bool = 40,
+    Unspecified3: i32,
+    C: i8 = 60,
+    Unspecified4: void,
+    D: void = 1000,
+    Unspecified5: i32,
+};
+
+test "union(enum(u32)) with specified and unspecified tag values" {
+    comptime assert(@TagType(@TagType(MultipleChoice2)) == u32);
+    testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 {.C = 123});
+    comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 { .C = 123} );
+}
+
+fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) {
+    assert(u32(@TagType(MultipleChoice2)(*x)) == 60);
+    assert(1123 == switch (*x) {
+        MultipleChoice2.A => 1,
+        MultipleChoice2.B => 2,
+        MultipleChoice2.C => |v| i32(1000) + v,
+        MultipleChoice2.D => 4,
+        MultipleChoice2.Unspecified1 => 5,
+        MultipleChoice2.Unspecified2 => 6,
+        MultipleChoice2.Unspecified3 => 7,
+        MultipleChoice2.Unspecified4 => 8,
+        MultipleChoice2.Unspecified5 => 9,
+    });
+}