| author | |
| committer | |
| log | 22e39e1e5ab42c2c3d33eeb6797f5835b2004fe3 |
| tree | c5c9dc35157c268c7196abdc83aa45e1bdad10ee |
| parent | 77fd147b26b8213038ea60dc9eb990bbf871f3d6 |
| signature |
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 | 5483 | <p> |
| 5484 | 5484 | Converts an enumeration value into its integer tag type. |
| 5485 | 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 | 5490 | {#see_also|@intToEnum#} |
| 5487 | 5491 | {#header_close#} |
| 5488 | 5492 |
src/analyze.cpp+10-1| ... | ... | @@ -2450,6 +2450,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2450 | 2450 | ZigType *tag_int_type; |
| 2451 | 2451 | if (enum_type->data.enumeration.layout == ContainerLayoutExtern) { |
| 2452 | 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 | 2455 | } else { |
| 2454 | 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 | 2515 | continue; |
| 2514 | 2516 | } |
| 2515 | 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 | 2520 | auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value); |
| 2518 | 2521 | if (entry == nullptr) { |
| 2519 | 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 | 2779 | union_type->data.unionation.is_invalid = true; |
| 2777 | 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 | 2784 | } else { |
| 2780 | 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 | 2814 | buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name))); |
| 2810 | 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 | 2821 | tag_type = enum_type; |
| 2813 | 2822 | abi_alignment_so_far = get_abi_alignment(g, enum_type); // this populates src_field_count |
| 2814 | 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 | 10113 | IrInstruction *target, ZigType *wanted_type) |
| 10114 | 10114 | { |
| 10115 | 10115 | Error err; |
| 10116 | assert(wanted_type->id == ZigTypeIdInt); | |
| 10116 | assert(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt); | |
| 10117 | 10117 | |
| 10118 | 10118 | ZigType *actual_type = target->value.type; |
| 10119 | 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 | 10139 | return result; |
| 10140 | 10140 | } |
| 10141 | 10141 | |
| 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 | 10154 | IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope, |
| 10143 | 10155 | source_instr->source_node, target); |
| 10144 | 10156 | result->value.type = wanted_type; |
| ... | ... | @@ -10164,6 +10176,19 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou |
| 10164 | 10176 | return result; |
| 10165 | 10177 | } |
| 10166 | 10178 | |
| 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 | 10192 | IrInstruction *result = ir_build_union_tag(&ira->new_irb, source_instr->scope, |
| 10168 | 10193 | source_instr->source_node, target); |
| 10169 | 10194 | result->value.type = wanted_type; |
test/cases/union.zig+39| ... | ... | @@ -324,3 +324,42 @@ test "tagged union with no payloads" { |
| 324 | 324 | @TagType(UnionEnumNoPayloads).B => {}, |
| 325 | 325 | } |
| 326 | 326 | } |
| 327 | ||
| 328 | test "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 | ||
| 345 | test "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 | } |