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" {...@@ -5483,6 +5483,10 @@ test "main" {
5483 <p>5483 <p>
5484 Converts an enumeration value into its integer tag type.5484 Converts an enumeration value into its integer tag type.
5485 </p>5485 </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>
5486 {#see_also|@intToEnum#}5490 {#see_also|@intToEnum#}
5487 {#header_close#}5491 {#header_close#}
54885492
src/analyze.cpp+10-1
...@@ -2450,6 +2450,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {...@@ -2450,6 +2450,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
2450 ZigType *tag_int_type;2450 ZigType *tag_int_type;
2451 if (enum_type->data.enumeration.layout == ContainerLayoutExtern) {2451 if (enum_type->data.enumeration.layout == ContainerLayoutExtern) {
2452 tag_int_type = get_c_int_type(g, CIntTypeInt);2452 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;
2453 } else {2455 } else {
2454 tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);2456 tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
2455 }2457 }
...@@ -2513,7 +2515,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {...@@ -2513,7 +2515,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
2513 continue;2515 continue;
2514 }2516 }
2515 assert(result_inst->value.special != ConstValSpecialRuntime);2517 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);
2517 auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);2520 auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
2518 if (entry == nullptr) {2521 if (entry == nullptr) {
2519 bigint_init_bigint(&type_enum_field->value, &result_inst->value.data.x_bigint);2522 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) {...@@ -2776,6 +2779,8 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
2776 union_type->data.unionation.is_invalid = true;2779 union_type->data.unionation.is_invalid = true;
2777 return ErrorSemanticAnalyzeFail;2780 return ErrorSemanticAnalyzeFail;
2778 }2781 }
2782 } else if (auto_layout && field_count == 1) {
2783 tag_int_type = g->builtin_types.entry_num_lit_int;
2779 } else {2784 } else {
2780 tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);2785 tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
2781 }2786 }
...@@ -2809,6 +2814,10 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {...@@ -2809,6 +2814,10 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
2809 buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));2814 buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
2810 return ErrorSemanticAnalyzeFail;2815 return ErrorSemanticAnalyzeFail;
2811 }2816 }
2817 if ((err = type_ensure_zero_bits_known(g, enum_type))) {
2818 assert(g->errors.length != 0);
2819 return err;
2820 }
2812 tag_type = enum_type;2821 tag_type = enum_type;
2813 abi_alignment_so_far = get_abi_alignment(g, enum_type); // this populates src_field_count2822 abi_alignment_so_far = get_abi_alignment(g, enum_type); // this populates src_field_count
2814 covered_enum_fields = allocate<bool>(enum_type->data.enumeration.src_field_count);2823 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...@@ -10113,7 +10113,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
10113 IrInstruction *target, ZigType *wanted_type)10113 IrInstruction *target, ZigType *wanted_type)
10114{10114{
10115 Error err;10115 Error err;
10116 assert(wanted_type->id == ZigTypeIdInt);10116 assert(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt);
1011710117
10118 ZigType *actual_type = target->value.type;10118 ZigType *actual_type = target->value.type;
10119 if ((err = ensure_complete_type(ira->codegen, actual_type)))10119 if ((err = ensure_complete_type(ira->codegen, actual_type)))
...@@ -10139,6 +10139,18 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour...@@ -10139,6 +10139,18 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
10139 return result;10139 return result;
10140 }10140 }
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
10142 IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,10154 IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
10143 source_instr->source_node, target);10155 source_instr->source_node, target);
10144 result->value.type = wanted_type;10156 result->value.type = wanted_type;
...@@ -10164,6 +10176,19 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou...@@ -10164,6 +10176,19 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou
10164 return result;10176 return result;
10165 }10177 }
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
10167 IrInstruction *result = ir_build_union_tag(&ira->new_irb, source_instr->scope,10192 IrInstruction *result = ir_build_union_tag(&ira->new_irb, source_instr->scope,
10168 source_instr->source_node, target);10193 source_instr->source_node, target);
10169 result->value.type = wanted_type;10194 result->value.type = wanted_type;
test/cases/union.zig+39
...@@ -324,3 +324,42 @@ test "tagged union with no payloads" {...@@ -324,3 +324,42 @@ test "tagged union with no payloads" {
324 @TagType(UnionEnumNoPayloads).B => {},324 @TagType(UnionEnumNoPayloads).B => {},
325 }325 }
326}326}
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}