mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
pull request fixups
This commit is contained in:
parent
9b3013d2f6
commit
7a84fe79b9
@ -2221,8 +2221,9 @@ test "packed enum" {
|
|||||||
{#header_close#}
|
{#header_close#}
|
||||||
{#header_open|union#}
|
{#header_open|union#}
|
||||||
{#code_begin|test|union#}
|
{#code_begin|test|union#}
|
||||||
const assert = @import("std").debug.assert;
|
const std = @import("std");
|
||||||
const mem = @import("std").mem;
|
const assert = std.debug.assert;
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
// A union has only 1 active field at a time.
|
// A union has only 1 active field at a time.
|
||||||
const Payload = union {
|
const Payload = union {
|
||||||
@ -2231,16 +2232,19 @@ const Payload = union {
|
|||||||
Bool: bool,
|
Bool: bool,
|
||||||
};
|
};
|
||||||
test "simple union" {
|
test "simple union" {
|
||||||
var payload = Payload {.Int = 1234};
|
var payload = Payload{ .Int = 1234 };
|
||||||
// payload.Float = 12.34; // ERROR! field not active
|
// payload.Float = 12.34; // ERROR! field not active
|
||||||
assert(payload.Int == 1234);
|
assert(payload.Int == 1234);
|
||||||
// You can activate another field by assigning the entire union.
|
// You can activate another field by assigning the entire union.
|
||||||
payload = Payload {.Float = 12.34};
|
payload = Payload{ .Float = 12.34 };
|
||||||
assert(payload.Float == 12.34);
|
assert(payload.Float == 12.34);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unions can be given an enum tag type:
|
// Unions can be given an enum tag type:
|
||||||
const ComplexTypeTag = enum { Ok, NotOk };
|
const ComplexTypeTag = enum {
|
||||||
|
Ok,
|
||||||
|
NotOk,
|
||||||
|
};
|
||||||
const ComplexType = union(ComplexTypeTag) {
|
const ComplexType = union(ComplexTypeTag) {
|
||||||
Ok: u8,
|
Ok: u8,
|
||||||
NotOk: void,
|
NotOk: void,
|
||||||
@ -2248,11 +2252,11 @@ const ComplexType = union(ComplexTypeTag) {
|
|||||||
|
|
||||||
// Declare a specific instance of the union variant.
|
// Declare a specific instance of the union variant.
|
||||||
test "declare union value" {
|
test "declare union value" {
|
||||||
const c = ComplexType { .Ok = 0 };
|
const c = ComplexType{ .Ok = 0 };
|
||||||
assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);
|
assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TagType can be used to access the enum tag type of a union.
|
// @TagType can be used to access the enum tag type of a tagged union.
|
||||||
test "@TagType" {
|
test "@TagType" {
|
||||||
assert(@TagType(ComplexType) == ComplexTypeTag);
|
assert(@TagType(ComplexType) == ComplexTypeTag);
|
||||||
}
|
}
|
||||||
@ -2266,7 +2270,7 @@ const Foo = union(enum) {
|
|||||||
None,
|
None,
|
||||||
};
|
};
|
||||||
test "union variant switch" {
|
test "union variant switch" {
|
||||||
const p = Foo { .Number = 54 };
|
const p = Foo{ .Number = 54 };
|
||||||
const what_is_it = switch (p) {
|
const what_is_it = switch (p) {
|
||||||
// Capture by reference
|
// Capture by reference
|
||||||
Foo.String => |*x| blk: {
|
Foo.String => |*x| blk: {
|
||||||
@ -2301,14 +2305,13 @@ const Variant = union(enum) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
test "union method" {
|
test "union method" {
|
||||||
var v1 = Variant { .Int = 1 };
|
var v1 = Variant{ .Int = 1 };
|
||||||
var v2 = Variant { .Bool = false };
|
var v2 = Variant{ .Bool = false };
|
||||||
|
|
||||||
assert(v1.truthy());
|
assert(v1.truthy());
|
||||||
assert(!v2.truthy());
|
assert(!v2.truthy());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Small = union {
|
const Small = union {
|
||||||
A: i32,
|
A: i32,
|
||||||
B: bool,
|
B: bool,
|
||||||
@ -5660,12 +5663,13 @@ test "main" {
|
|||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@enumToInt#}
|
{#header_open|@enumToInt#}
|
||||||
<pre>{#syntax#}@enumToInt(enum_value: var) var{#endsyntax#}</pre>
|
<pre>{#syntax#}@enumToInt(enum_or_tagged_union: var) var{#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
Converts an enumeration or tagged union value into its integer tag type.
|
Converts an enumeration value into its integer tag type. When a tagged union is passed,
|
||||||
|
the tag value is used as the enumeration value.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
If the enum has only 1 possible value, the resut is a {#syntax#}comptime_int{#endsyntax#}
|
If there is only one possible enum value, the resut is a {#syntax#}comptime_int{#endsyntax#}
|
||||||
known at {#link|comptime#}.
|
known at {#link|comptime#}.
|
||||||
</p>
|
</p>
|
||||||
{#see_also|@intToEnum#}
|
{#see_also|@intToEnum#}
|
||||||
|
|||||||
137
src/ir.cpp
137
src/ir.cpp
@ -10305,63 +10305,75 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr,
|
static ZigType *ir_resolve_union_tag_type(IrAnalyze *ira, IrInstruction *source_instr, ZigType *union_type) {
|
||||||
IrInstruction *target, ZigType *wanted_type)
|
assert(union_type->id == ZigTypeIdUnion);
|
||||||
{
|
|
||||||
Error err;
|
Error err;
|
||||||
assert(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt);
|
if ((err = type_resolve(ira->codegen, union_type, ResolveStatusSizeKnown)))
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
|
||||||
ZigType *actual_type = target->value.type;
|
AstNode *decl_node = union_type->data.unionation.decl_node;
|
||||||
|
if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
|
||||||
|
assert(union_type->data.unionation.tag_type != nullptr);
|
||||||
|
return union_type->data.unionation.tag_type;
|
||||||
|
} else {
|
||||||
|
ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("union '%s' has no tag",
|
||||||
|
buf_ptr(&union_type->name)));
|
||||||
|
add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here"));
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (actual_type->id == ZigTypeIdUnion)
|
static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target) {
|
||||||
actual_type = actual_type->data.unionation.tag_type;
|
Error err;
|
||||||
|
|
||||||
if ((err = ensure_complete_type(ira->codegen, actual_type)))
|
IrInstruction *enum_target;
|
||||||
return ira->codegen->invalid_instruction;
|
ZigType *enum_type;
|
||||||
|
if (target->value.type->id == ZigTypeIdUnion) {
|
||||||
if (wanted_type != actual_type->data.enumeration.tag_int_type) {
|
enum_type = ir_resolve_union_tag_type(ira, target, target->value.type);
|
||||||
ir_add_error(ira, source_instr,
|
if (type_is_invalid(enum_type))
|
||||||
buf_sprintf("enum to integer cast to '%s' instead of its tag type, '%s'",
|
return ira->codegen->invalid_instruction;
|
||||||
buf_ptr(&wanted_type->name),
|
enum_target = ir_implicit_cast(ira, target, enum_type);
|
||||||
buf_ptr(&actual_type->data.enumeration.tag_int_type->name)));
|
if (type_is_invalid(enum_target->value.type))
|
||||||
|
return ira->codegen->invalid_instruction;
|
||||||
|
} else if (target->value.type->id == ZigTypeIdEnum) {
|
||||||
|
enum_target = target;
|
||||||
|
enum_type = target->value.type;
|
||||||
|
} else {
|
||||||
|
ir_add_error(ira, target,
|
||||||
|
buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name)));
|
||||||
return ira->codegen->invalid_instruction;
|
return ira->codegen->invalid_instruction;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(actual_type->id == ZigTypeIdEnum);
|
if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusSizeKnown)))
|
||||||
|
return ira->codegen->invalid_instruction;
|
||||||
|
|
||||||
if (instr_is_comptime(target)) {
|
ZigType *tag_type = enum_type->data.enumeration.tag_int_type;
|
||||||
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
|
assert(tag_type->id == ZigTypeIdInt || tag_type->id == ZigTypeIdComptimeInt);
|
||||||
|
|
||||||
|
if (instr_is_comptime(enum_target)) {
|
||||||
|
ConstExprValue *val = ir_resolve_const(ira, enum_target, UndefBad);
|
||||||
if (!val)
|
if (!val)
|
||||||
return ira->codegen->invalid_instruction;
|
return ira->codegen->invalid_instruction;
|
||||||
IrInstruction *result = ir_const(ira, source_instr, wanted_type);
|
IrInstruction *result = ir_const(ira, source_instr, tag_type);
|
||||||
if (target->value.type->id == ZigTypeIdUnion)
|
init_const_bigint(&result->value, tag_type, &val->data.x_enum_tag);
|
||||||
init_const_bigint(&result->value, wanted_type, &val->data.x_union.tag);
|
|
||||||
else
|
|
||||||
init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is only one possible tag, then we know at comptime what it is.
|
// If there is only one possible tag, then we know at comptime what it is.
|
||||||
if (actual_type->data.enumeration.layout == ContainerLayoutAuto &&
|
if (enum_type->data.enumeration.layout == ContainerLayoutAuto &&
|
||||||
actual_type->data.enumeration.src_field_count == 1)
|
enum_type->data.enumeration.src_field_count == 1)
|
||||||
{
|
{
|
||||||
assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int);
|
assert(tag_type == ira->codegen->builtin_types.entry_num_lit_int);
|
||||||
IrInstruction *result = ir_const(ira, source_instr, wanted_type);
|
IrInstruction *result = ir_const(ira, source_instr, tag_type);
|
||||||
init_const_bigint(&result->value, wanted_type,
|
init_const_bigint(&result->value, tag_type,
|
||||||
&actual_type->data.enumeration.fields[0].value);
|
&enum_type->data.enumeration.fields[0].value);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
IrInstruction *result = nullptr;
|
IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
|
||||||
if (target->value.type->id == ZigTypeIdUnion)
|
source_instr->source_node, enum_target);
|
||||||
result = ir_build_union_tag(&ira->new_irb, source_instr->scope,
|
result->value.type = tag_type;
|
||||||
source_instr->source_node, target);
|
|
||||||
else
|
|
||||||
result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
|
|
||||||
source_instr->source_node, target);
|
|
||||||
result->value.type = wanted_type;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21378,20 +21390,10 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct
|
|||||||
|
|
||||||
return ir_const_type(ira, &instruction->base, enum_type->data.enumeration.tag_int_type);
|
return ir_const_type(ira, &instruction->base, enum_type->data.enumeration.tag_int_type);
|
||||||
} else if (enum_type->id == ZigTypeIdUnion) {
|
} else if (enum_type->id == ZigTypeIdUnion) {
|
||||||
if ((err = ensure_complete_type(ira->codegen, enum_type)))
|
ZigType *tag_type = ir_resolve_union_tag_type(ira, instruction->target, enum_type);
|
||||||
|
if (type_is_invalid(tag_type))
|
||||||
return ira->codegen->invalid_instruction;
|
return ira->codegen->invalid_instruction;
|
||||||
|
return ir_const_type(ira, &instruction->base, tag_type);
|
||||||
AstNode *decl_node = enum_type->data.unionation.decl_node;
|
|
||||||
if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
|
|
||||||
assert(enum_type->data.unionation.tag_type != nullptr);
|
|
||||||
|
|
||||||
return ir_const_type(ira, &instruction->base, enum_type->data.unionation.tag_type);
|
|
||||||
} else {
|
|
||||||
ErrorMsg *msg = ir_add_error(ira, target_inst, buf_sprintf("union '%s' has no tag",
|
|
||||||
buf_ptr(&enum_type->name)));
|
|
||||||
add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here"));
|
|
||||||
return ira->codegen->invalid_instruction;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'",
|
ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'",
|
||||||
buf_ptr(&enum_type->name)));
|
buf_ptr(&enum_type->name)));
|
||||||
@ -21972,38 +21974,11 @@ static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstr
|
|||||||
|
|
||||||
|
|
||||||
static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) {
|
static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) {
|
||||||
Error err;
|
|
||||||
IrInstruction *target = instruction->target->child;
|
IrInstruction *target = instruction->target->child;
|
||||||
ZigType *enum_type = target->value.type;
|
if (type_is_invalid(target->value.type))
|
||||||
if (type_is_invalid(enum_type))
|
|
||||||
return ira->codegen->invalid_instruction;
|
return ira->codegen->invalid_instruction;
|
||||||
|
|
||||||
if (enum_type->id == ZigTypeIdUnion) {
|
return ir_analyze_enum_to_int(ira, &instruction->base, target);
|
||||||
if ((err = ensure_complete_type(ira->codegen, enum_type)))
|
|
||||||
return ira->codegen->invalid_instruction;
|
|
||||||
|
|
||||||
AstNode *decl_node = enum_type->data.unionation.decl_node;
|
|
||||||
if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
|
|
||||||
assert(enum_type->data.unionation.tag_type != nullptr);
|
|
||||||
enum_type = target->value.type->data.unionation.tag_type;
|
|
||||||
} else {
|
|
||||||
ErrorMsg *msg = ir_add_error(ira, target, buf_sprintf("union '%s' has no tag",
|
|
||||||
buf_ptr(&enum_type->name)));
|
|
||||||
add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here"));
|
|
||||||
return ira->codegen->invalid_instruction;
|
|
||||||
}
|
|
||||||
} else if (enum_type->id != ZigTypeIdEnum) {
|
|
||||||
ir_add_error(ira, instruction->target,
|
|
||||||
buf_sprintf("expected enum or union(enum), found type '%s'", buf_ptr(&enum_type->name)));
|
|
||||||
return ira->codegen->invalid_instruction;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusZeroBitsKnown)))
|
|
||||||
return ira->codegen->invalid_instruction;
|
|
||||||
|
|
||||||
ZigType *int_type = enum_type->data.enumeration.tag_int_type;
|
|
||||||
|
|
||||||
return ir_analyze_enum_to_int(ira, &instruction->base, target, int_type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static IrInstruction *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) {
|
static IrInstruction *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) {
|
||||||
|
|||||||
@ -126,7 +126,7 @@ const MultipleChoice = union(enum(u32)) {
|
|||||||
test "simple union(enum(u32))" {
|
test "simple union(enum(u32))" {
|
||||||
var x = MultipleChoice.C;
|
var x = MultipleChoice.C;
|
||||||
expect(x == MultipleChoice.C);
|
expect(x == MultipleChoice.C);
|
||||||
expect(@enumToInt(x) == 60);
|
expect(@enumToInt(@TagType(MultipleChoice)(x)) == 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MultipleChoice2 = union(enum(u32)) {
|
const MultipleChoice2 = union(enum(u32)) {
|
||||||
@ -148,7 +148,7 @@ test "union(enum(u32)) with specified and unspecified tag values" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
|
fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
|
||||||
expect(@enumToInt(x) == 60);
|
expect(@enumToInt(@TagType(MultipleChoice2)(x)) == 60);
|
||||||
expect(1123 == switch (x) {
|
expect(1123 == switch (x) {
|
||||||
MultipleChoice2.A => 1,
|
MultipleChoice2.A => 1,
|
||||||
MultipleChoice2.B => 2,
|
MultipleChoice2.B => 2,
|
||||||
@ -345,7 +345,23 @@ test "union with only 1 field casted to its enum type which has enum value speci
|
|||||||
|
|
||||||
var e = Expr{ .Literal = Literal{ .Bool = true } };
|
var e = Expr{ .Literal = Literal{ .Bool = true } };
|
||||||
comptime expect(@TagType(Tag) == comptime_int);
|
comptime expect(@TagType(Tag) == comptime_int);
|
||||||
expect(Tag(e) == Expr.Literal);
|
var t = Tag(e);
|
||||||
expect(@enumToInt(e) == 33);
|
expect(t == Expr.Literal);
|
||||||
comptime expect(@enumToInt(e) == 33);
|
expect(@enumToInt(t) == 33);
|
||||||
|
comptime expect(@enumToInt(t) == 33);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "@enumToInt works on unions" {
|
||||||
|
const Bar = union(enum) {
|
||||||
|
A: bool,
|
||||||
|
B: u8,
|
||||||
|
C,
|
||||||
|
};
|
||||||
|
|
||||||
|
const a = Bar{ .A = true };
|
||||||
|
var b = Bar{ .B = undefined };
|
||||||
|
var c = Bar.C;
|
||||||
|
expect(@enumToInt(a) == 0);
|
||||||
|
expect(@enumToInt(b) == 1);
|
||||||
|
expect(@enumToInt(c) == 2);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -572,9 +572,7 @@ pub const CompileErrorContext = struct {
|
|||||||
const source_file = ".tmp_source.zig";
|
const source_file = ".tmp_source.zig";
|
||||||
|
|
||||||
fn init(input: []const u8) ErrLineIter {
|
fn init(input: []const u8) ErrLineIter {
|
||||||
return ErrLineIter {
|
return ErrLineIter{ .lines = mem.separate(input, "\n") };
|
||||||
.lines = mem.separate(input, "\n"),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(self: *ErrLineIter) ?[]const u8 {
|
fn next(self: *ErrLineIter) ?[]const u8 {
|
||||||
@ -718,11 +716,10 @@ pub const CompileErrorContext = struct {
|
|||||||
for (self.case.expected_errors.toSliceConst()) |expected| {
|
for (self.case.expected_errors.toSliceConst()) |expected| {
|
||||||
if (mem.indexOf(u8, stderr, expected) == null) {
|
if (mem.indexOf(u8, stderr, expected) == null) {
|
||||||
warn(
|
warn(
|
||||||
\\=========== Expected compile error: ============
|
\\\n=========== Expected compile error: ============
|
||||||
\\{}
|
\\{}
|
||||||
\\
|
\\
|
||||||
, expected
|
, expected);
|
||||||
);
|
|
||||||
ok = false;
|
ok = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -734,8 +731,7 @@ pub const CompileErrorContext = struct {
|
|||||||
\\================= Full output: =================
|
\\================= Full output: =================
|
||||||
\\{}
|
\\{}
|
||||||
\\
|
\\
|
||||||
, stderr
|
, stderr);
|
||||||
);
|
|
||||||
return error.TestFailed;
|
return error.TestFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user