From 9b3013d2f6e416f31610f3dc94c5ff8b44836463 Mon Sep 17 00:00:00 2001 From: emekoi Date: Sat, 9 Feb 2019 18:04:38 -0600 Subject: [PATCH] make @enumToInt work on union(enum) closes #1711 --- doc/langref.html.in | 2 +- src/ir.cpp | 55 ++++++++++++++++++++++++++-------- src/target.cpp | 3 +- test/stage1/behavior/union.zig | 11 ++++--- 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 1341bf1be5..0d71dbc593 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5662,7 +5662,7 @@ test "main" { {#header_open|@enumToInt#}
{#syntax#}@enumToInt(enum_value: var) var{#endsyntax#}

- Converts an enumeration value into its integer tag type. + Converts an enumeration or tagged union value into its integer tag type.

If the enum has only 1 possible value, the resut is a {#syntax#}comptime_int{#endsyntax#} diff --git a/src/ir.cpp b/src/ir.cpp index 063be4e952..a33ba13eed 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10312,6 +10312,10 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour assert(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt); ZigType *actual_type = target->value.type; + + if (actual_type->id == ZigTypeIdUnion) + actual_type = actual_type->data.unionation.tag_type; + if ((err = ensure_complete_type(ira->codegen, actual_type))) return ira->codegen->invalid_instruction; @@ -10330,7 +10334,11 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour if (!val) return ira->codegen->invalid_instruction; IrInstruction *result = ir_const(ira, source_instr, wanted_type); - init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag); + if (target->value.type->id == ZigTypeIdUnion) + init_const_bigint(&result->value, wanted_type, &val->data.x_union.tag); + else + init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag); + return result; } @@ -10341,12 +10349,18 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int); IrInstruction *result = ir_const(ira, source_instr, wanted_type); init_const_bigint(&result->value, wanted_type, - &actual_type->data.enumeration.fields[0].value); + &actual_type->data.enumeration.fields[0].value); + return result; } - IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope, - source_instr->source_node, target); + IrInstruction *result = nullptr; + if (target->value.type->id == ZigTypeIdUnion) + result = ir_build_union_tag(&ira->new_irb, source_instr->scope, + source_instr->source_node, target); + else + result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope, + source_instr->source_node, target); result->value.type = wanted_type; return result; } @@ -14358,12 +14372,12 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source if (dst_size == 0) return ErrorNone; opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("attempt to read %zu bytes from null pointer", + buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from null pointer", dst_size)); return ErrorSemanticAnalyzeFail; case ConstPtrSpecialRef: { opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes", + buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from pointer to %s which is %" ZIG_PRI_usize " bytes", dst_size, buf_ptr(&pointee->type->name), src_size)); return ErrorSemanticAnalyzeFail; } @@ -14377,7 +14391,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source src_size = elem_size * (array_val->type->data.array.len - elem_index); if (dst_size > src_size) { opt_ir_add_error_node(ira, codegen, source_node, - buf_sprintf("attempt to read %zu bytes from %s at index %" ZIG_PRI_usize " which is %zu bytes", + buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes", dst_size, buf_ptr(&array_val->type->name), elem_index, src_size)); return ErrorSemanticAnalyzeFail; } @@ -21960,21 +21974,36 @@ static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstr static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) { Error err; IrInstruction *target = instruction->target->child; - if (type_is_invalid(target->value.type)) + ZigType *enum_type = target->value.type; + if (type_is_invalid(enum_type)) return ira->codegen->invalid_instruction; - if (target->value.type->id != ZigTypeIdEnum) { + if (enum_type->id == ZigTypeIdUnion) { + if ((err = ensure_complete_type(ira->codegen, enum_type))) + return ira->codegen->invalid_instruction; + + 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); + enum_type = target->value.type->data.unionation.tag_type; + } else { + ErrorMsg *msg = ir_add_error(ira, target, 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->invalid_instruction; + } + } else if (enum_type->id != ZigTypeIdEnum) { ir_add_error(ira, instruction->target, - buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name))); + buf_sprintf("expected enum or union(enum), found type '%s'", buf_ptr(&enum_type->name))); return ira->codegen->invalid_instruction; } - if ((err = type_resolve(ira->codegen, target->value.type, ResolveStatusZeroBitsKnown))) + if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; - ZigType *tag_type = target->value.type->data.enumeration.tag_int_type; + ZigType *int_type = enum_type->data.enumeration.tag_int_type; - return ir_analyze_enum_to_int(ira, &instruction->base, target, tag_type); + return ir_analyze_enum_to_int(ira, &instruction->base, target, int_type); } static IrInstruction *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) { diff --git a/src/target.cpp b/src/target.cpp index cea7826313..5352a21826 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -9,6 +9,7 @@ #include "error.hpp" #include "target.hpp" #include "util.hpp" +#include "os.hpp" #include @@ -848,7 +849,7 @@ const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t versio if (is_static) { return ".a"; } else { - return buf_ptr(buf_sprintf(".so.%zu", version_major)); + return buf_ptr(buf_sprintf(".so.%" ZIG_PRI_usize, version_major)); } } } diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index 0a4e2cfb92..f18cdf13ff 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -126,7 +126,7 @@ const MultipleChoice = union(enum(u32)) { test "simple union(enum(u32))" { var x = MultipleChoice.C; expect(x == MultipleChoice.C); - expect(@enumToInt(@TagType(MultipleChoice)(x)) == 60); + expect(@enumToInt(x) == 60); } const MultipleChoice2 = union(enum(u32)) { @@ -148,7 +148,7 @@ test "union(enum(u32)) with specified and unspecified tag values" { } fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void { - expect(@enumToInt(@TagType(MultipleChoice2)(x)) == 60); + expect(@enumToInt(x) == 60); expect(1123 == switch (x) { MultipleChoice2.A => 1, MultipleChoice2.B => 2, @@ -345,8 +345,7 @@ test "union with only 1 field casted to its enum type which has enum value speci var e = Expr{ .Literal = Literal{ .Bool = true } }; comptime expect(@TagType(Tag) == comptime_int); - var t = Tag(e); - expect(t == Expr.Literal); - expect(@enumToInt(t) == 33); - comptime expect(@enumToInt(t) == 33); + expect(Tag(e) == Expr.Literal); + expect(@enumToInt(e) == 33); + comptime expect(@enumToInt(e) == 33); }