mirror of
https://github.com/ziglang/zig.git
synced 2025-12-27 16:43:07 +00:00
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.
This commit is contained in:
parent
77fd147b26
commit
22e39e1e5a
@ -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#}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
27
src/ir.cpp
27
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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user