From 65185016f15ca69363113f85537542b0bdebe33f Mon Sep 17 00:00:00 2001 From: xackus <14938807+xackus@users.noreply.github.com> Date: Sun, 31 May 2020 19:15:21 +0200 Subject: [PATCH] stage1: fix non-exhaustive enums with one field --- src/analyze.cpp | 9 ++++++++- src/ir.cpp | 11 +++++++---- test/stage1/behavior/enum.zig | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 6a4a2ec052..4920571438 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -7303,7 +7303,14 @@ void render_const_value(CodeGen *g, Buf *buf, ZigValue *const_val) { case ZigTypeIdEnum: { TypeEnumField *field = find_enum_field_by_tag(type_entry, &const_val->data.x_enum_tag); - buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(field->name)); + if(field != nullptr){ + buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(field->name)); + } else { + // untagged value in a non-exhaustive enum + buf_appendf(buf, "%s.(", buf_ptr(&type_entry->name)); + bigint_append_buf(buf, &const_val->data.x_enum_tag, 10); + buf_appendf(buf, ")"); + } return; } case ZigTypeIdErrorUnion: diff --git a/src/ir.cpp b/src/ir.cpp index 40be4e147b..f56a0681df 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14096,7 +14096,8 @@ static IrInstGen *ir_analyze_enum_to_int(IrAnalyze *ira, IrInst *source_instr, I // If there is only one possible tag, then we know at comptime what it is. if (enum_type->data.enumeration.layout == ContainerLayoutAuto && - enum_type->data.enumeration.src_field_count == 1) + enum_type->data.enumeration.src_field_count == 1 && + !enum_type->data.enumeration.non_exhaustive) { IrInstGen *result = ir_const(ira, source_instr, tag_type); init_const_bigint(result->value, tag_type, @@ -14136,7 +14137,8 @@ static IrInstGen *ir_analyze_union_to_tag(IrAnalyze *ira, IrInst* source_instr, // If there is only 1 possible tag, then we know at comptime what it is. if (wanted_type->data.enumeration.layout == ContainerLayoutAuto && - wanted_type->data.enumeration.src_field_count == 1) + wanted_type->data.enumeration.src_field_count == 1 && + !wanted_type->data.enumeration.non_exhaustive) // TODO are non-exhaustive union tag types supposed to be allowed? { IrInstGen *result = ir_const(ira, source_instr, wanted_type); result->value->special = ConstValSpecialStatic; @@ -23814,7 +23816,8 @@ static IrInstGen *ir_analyze_instruction_switch_target(IrAnalyze *ira, bigint_init_bigint(&result->value->data.x_enum_tag, &pointee_val->data.x_union.tag); return result; } - if (tag_type->data.enumeration.src_field_count == 1) { + // TODO are non-exhaustive union tag types supposed to be allowed? + if (tag_type->data.enumeration.src_field_count == 1 && !tag_type->data.enumeration.non_exhaustive) { IrInstGen *result = ir_const(ira, &switch_target_instruction->base.base, tag_type); TypeEnumField *only_field = &tag_type->data.enumeration.fields[0]; bigint_init_bigint(&result->value->data.x_enum_tag, &only_field->value); @@ -23829,7 +23832,7 @@ static IrInstGen *ir_analyze_instruction_switch_target(IrAnalyze *ira, case ZigTypeIdEnum: { if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_inst_gen; - if (target_type->data.enumeration.src_field_count == 1) { + if (target_type->data.enumeration.src_field_count == 1 && !target_type->data.enumeration.non_exhaustive) { TypeEnumField *only_field = &target_type->data.enumeration.fields[0]; IrInstGen *result = ir_const(ira, &switch_target_instruction->base.base, target_type); bigint_init_bigint(&result->value->data.x_enum_tag, &only_field->value); diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index f569264520..1d424d6e39 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -85,6 +85,43 @@ test "empty non-exhaustive enum" { comptime 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; + expect(switch (e) { + .a => true, + _ => false, + }); + e = @intToEnum(E, 12); + expect(switch (e) { + .a => false, + _ => true, + }); + + expect(switch (e) { + .a => false, + else => true, + }); + e = .a; + expect(switch (e) { + .a => true, + else => false, + }); + + expect(@enumToInt(@intToEnum(E, y)) == y); + expect(@typeInfo(E).Enum.fields.len == 1); + expect(@typeInfo(E).Enum.is_exhaustive == false); + } + }; + S.doTheTest(23); + comptime S.doTheTest(23); +} + test "enum type" { const foo1 = Foo{ .One = 13 }; const foo2 = Foo{