authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-13 13:29:43-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-13 13:33:11-04:00
log22e39e1e5ab42c2c3d33eeb6797f5835b2004fe3
treec5c9dc35157c268c7196abdc83aa45e1bdad10ee
parent77fd147b26b8213038ea60dc9eb990bbf871f3d6
signaturelock-open Commit is signed but in an unrecognized format.

fix tagged union with only 1 field tripping assertion

closes #1495 now the tag type of an enum with only 1 item is comptime_int.

4 files changed, 79 insertions(+), 2 deletions(-)

doc/langref.html.in+4
......@@ -5483,6 +5483,10 @@ test "main" {
54835483 <p>
54845484 Converts an enumeration value into its integer tag type.
54855485 </p>
5486 <p>
5487 If the enum has only 1 possible value, the resut is a <code class="zig">comptime_int</code>
5488 known at {#link|comptime#}.
5489 </p>
54865490 {#see_also|@intToEnum#}
54875491 {#header_close#}
54885492
src/analyze.cpp+10-1
......@@ -2450,6 +2450,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
24502450 ZigType *tag_int_type;
24512451 if (enum_type->data.enumeration.layout == ContainerLayoutExtern) {
24522452 tag_int_type = get_c_int_type(g, CIntTypeInt);
2453 } else if (enum_type->data.enumeration.layout == ContainerLayoutAuto && field_count == 1) {
2454 tag_int_type = g->builtin_types.entry_num_lit_int;
24532455 } else {
24542456 tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
24552457 }
......@@ -2513,7 +2515,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
25132515 continue;
25142516 }
25152517 assert(result_inst->value.special != ConstValSpecialRuntime);
2516 assert(result_inst->value.type->id == ZigTypeIdInt);
2518 assert(result_inst->value.type->id == ZigTypeIdInt ||
2519 result_inst->value.type->id == ZigTypeIdComptimeInt);
25172520 auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
25182521 if (entry == nullptr) {
25192522 bigint_init_bigint(&type_enum_field->value, &result_inst->value.data.x_bigint);
......@@ -2776,6 +2779,8 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
27762779 union_type->data.unionation.is_invalid = true;
27772780 return ErrorSemanticAnalyzeFail;
27782781 }
2782 } else if (auto_layout && field_count == 1) {
2783 tag_int_type = g->builtin_types.entry_num_lit_int;
27792784 } else {
27802785 tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
27812786 }
......@@ -2809,6 +2814,10 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
28092814 buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
28102815 return ErrorSemanticAnalyzeFail;
28112816 }
2817 if ((err = type_ensure_zero_bits_known(g, enum_type))) {
2818 assert(g->errors.length != 0);
2819 return err;
2820 }
28122821 tag_type = enum_type;
28132822 abi_alignment_so_far = get_abi_alignment(g, enum_type); // this populates src_field_count
28142823 covered_enum_fields = allocate<bool>(enum_type->data.enumeration.src_field_count);
src/ir.cpp+26-1
......@@ -10113,7 +10113,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
1011310113 IrInstruction *target, ZigType *wanted_type)
1011410114{
1011510115 Error err;
10116 assert(wanted_type->id == ZigTypeIdInt);
10116 assert(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt);
1011710117
1011810118 ZigType *actual_type = target->value.type;
1011910119 if ((err = ensure_complete_type(ira->codegen, actual_type)))
......@@ -10139,6 +10139,18 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
1013910139 return result;
1014010140 }
1014110141
10142 // If there is only one possible tag, then we know at comptime what it is.
10143 if (actual_type->data.enumeration.layout == ContainerLayoutAuto &&
10144 actual_type->data.enumeration.src_field_count == 1)
10145 {
10146 assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int);
10147 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
10148 source_instr->source_node, wanted_type);
10149 init_const_bigint(&result->value, wanted_type,
10150 &actual_type->data.enumeration.fields[0].value);
10151 return result;
10152 }
10153
1014210154 IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
1014310155 source_instr->source_node, target);
1014410156 result->value.type = wanted_type;
......@@ -10164,6 +10176,19 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou
1016410176 return result;
1016510177 }
1016610178
10179 // If there is only 1 possible tag, then we know at comptime what it is.
10180 if (wanted_type->data.enumeration.layout == ContainerLayoutAuto &&
10181 wanted_type->data.enumeration.src_field_count == 1)
10182 {
10183 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
10184 source_instr->source_node, wanted_type);
10185 result->value.special = ConstValSpecialStatic;
10186 result->value.type = wanted_type;
10187 TypeEnumField *enum_field = target->value.type->data.unionation.fields[0].enum_field;
10188 bigint_init_bigint(&result->value.data.x_enum_tag, &enum_field->value);
10189 return result;
10190 }
10191
1016710192 IrInstruction *result = ir_build_union_tag(&ira->new_irb, source_instr->scope,
1016810193 source_instr->source_node, target);
1016910194 result->value.type = wanted_type;
test/cases/union.zig+39
......@@ -324,3 +324,42 @@ test "tagged union with no payloads" {
324324 @TagType(UnionEnumNoPayloads).B => {},
325325 }
326326}
327
328test "union with only 1 field casted to its enum type" {
329 const Literal = union(enum) {
330 Number: f64,
331 Bool: bool,
332 };
333
334 const Expr = union(enum) {
335 Literal: Literal,
336 };
337
338 var e = Expr{ .Literal = Literal{ .Bool = true } };
339 const Tag = @TagType(Expr);
340 comptime assert(@TagType(Tag) == comptime_int);
341 var t = Tag(e);
342 assert(t == Expr.Literal);
343}
344
345test "union with only 1 field casted to its enum type which has enum value specified" {
346 const Literal = union(enum) {
347 Number: f64,
348 Bool: bool,
349 };
350
351 const Tag = enum {
352 Literal = 33,
353 };
354
355 const Expr = union(Tag) {
356 Literal: Literal,
357 };
358
359 var e = Expr{ .Literal = Literal{ .Bool = true } };
360 comptime assert(@TagType(Tag) == comptime_int);
361 var t = Tag(e);
362 assert(t == Expr.Literal);
363 assert(@enumToInt(t) == 33);
364 comptime assert(@enumToInt(t) == 33);
365}