Commit 22e39e1e5a
Changed files (4)
doc/langref.html.in
@@ -5483,6 +5483,10 @@ test "main" {
<p>
Converts an enumeration value into its integer tag type.
</p>
+ <p>
+ If the enum has only 1 possible value, the resut is a <code class="zig">comptime_int</code>
+ known at {#link|comptime#}.
+ </p>
{#see_also|@intToEnum#}
{#header_close#}
src/analyze.cpp
@@ -2450,6 +2450,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
ZigType *tag_int_type;
if (enum_type->data.enumeration.layout == ContainerLayoutExtern) {
tag_int_type = get_c_int_type(g, CIntTypeInt);
+ } else if (enum_type->data.enumeration.layout == ContainerLayoutAuto && field_count == 1) {
+ tag_int_type = g->builtin_types.entry_num_lit_int;
} else {
tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
}
@@ -2513,7 +2515,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
continue;
}
assert(result_inst->value.special != ConstValSpecialRuntime);
- assert(result_inst->value.type->id == ZigTypeIdInt);
+ assert(result_inst->value.type->id == ZigTypeIdInt ||
+ result_inst->value.type->id == ZigTypeIdComptimeInt);
auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
if (entry == nullptr) {
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) {
union_type->data.unionation.is_invalid = true;
return ErrorSemanticAnalyzeFail;
}
+ } else if (auto_layout && field_count == 1) {
+ tag_int_type = g->builtin_types.entry_num_lit_int;
} else {
tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
}
@@ -2809,6 +2814,10 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
return ErrorSemanticAnalyzeFail;
}
+ if ((err = type_ensure_zero_bits_known(g, enum_type))) {
+ assert(g->errors.length != 0);
+ return err;
+ }
tag_type = enum_type;
abi_alignment_so_far = get_abi_alignment(g, enum_type); // this populates src_field_count
covered_enum_fields = allocate<bool>(enum_type->data.enumeration.src_field_count);
src/ir.cpp
@@ -10113,7 +10113,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
IrInstruction *target, ZigType *wanted_type)
{
Error err;
- assert(wanted_type->id == ZigTypeIdInt);
+ assert(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt);
ZigType *actual_type = target->value.type;
if ((err = ensure_complete_type(ira->codegen, actual_type)))
@@ -10139,6 +10139,18 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
return result;
}
+ // If there is only one possible tag, then we know at comptime what it is.
+ if (actual_type->data.enumeration.layout == ContainerLayoutAuto &&
+ actual_type->data.enumeration.src_field_count == 1)
+ {
+ assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int);
+ IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, wanted_type);
+ init_const_bigint(&result->value, wanted_type,
+ &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);
result->value.type = wanted_type;
@@ -10164,6 +10176,19 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou
return result;
}
+ // 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)
+ {
+ IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, wanted_type);
+ result->value.special = ConstValSpecialStatic;
+ result->value.type = wanted_type;
+ TypeEnumField *enum_field = target->value.type->data.unionation.fields[0].enum_field;
+ bigint_init_bigint(&result->value.data.x_enum_tag, &enum_field->value);
+ return result;
+ }
+
IrInstruction *result = ir_build_union_tag(&ira->new_irb, source_instr->scope,
source_instr->source_node, target);
result->value.type = wanted_type;
test/cases/union.zig
@@ -324,3 +324,42 @@ test "tagged union with no payloads" {
@TagType(UnionEnumNoPayloads).B => {},
}
}
+
+test "union with only 1 field casted to its enum type" {
+ const Literal = union(enum) {
+ Number: f64,
+ Bool: bool,
+ };
+
+ const Expr = union(enum) {
+ Literal: Literal,
+ };
+
+ var e = Expr{ .Literal = Literal{ .Bool = true } };
+ const Tag = @TagType(Expr);
+ comptime assert(@TagType(Tag) == comptime_int);
+ var t = Tag(e);
+ assert(t == Expr.Literal);
+}
+
+test "union with only 1 field casted to its enum type which has enum value specified" {
+ const Literal = union(enum) {
+ Number: f64,
+ Bool: bool,
+ };
+
+ const Tag = enum {
+ Literal = 33,
+ };
+
+ const Expr = union(Tag) {
+ Literal: Literal,
+ };
+
+ var e = Expr{ .Literal = Literal{ .Bool = true } };
+ comptime assert(@TagType(Tag) == comptime_int);
+ var t = Tag(e);
+ assert(t == Expr.Literal);
+ assert(@enumToInt(t) == 33);
+ comptime assert(@enumToInt(t) == 33);
+}