authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-18 12:56:17-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-18 13:05:26-05:00
log7a84fe79b9d61bb3d4e21c169cc2b58722b194ce
tree1d44cdfafe00762e388d3114a0b9d44bb3bc0c4d
parent9b3013d2f6e416f31610f3dc94c5ff8b44836463
signaturelock-open Commit is signed but in an unrecognized format.

pull request fixups


4 files changed, 98 insertions(+), 107 deletions(-)

doc/langref.html.in+18-14
......@@ -2221,8 +2221,9 @@ test "packed enum" {
22212221 {#header_close#}
22222222 {#header_open|union#}
22232223 {#code_begin|test|union#}
2224const assert = @import("std").debug.assert;
2225const mem = @import("std").mem;
2224const std = @import("std");
2225const assert = std.debug.assert;
2226const mem = std.mem;
22262227
22272228// A union has only 1 active field at a time.
22282229const Payload = union {
......@@ -2231,16 +2232,19 @@ const Payload = union {
22312232 Bool: bool,
22322233};
22332234test "simple union" {
2234 var payload = Payload {.Int = 1234};
2235 var payload = Payload{ .Int = 1234 };
22352236 // payload.Float = 12.34; // ERROR! field not active
22362237 assert(payload.Int == 1234);
22372238 // You can activate another field by assigning the entire union.
2238 payload = Payload {.Float = 12.34};
2239 payload = Payload{ .Float = 12.34 };
22392240 assert(payload.Float == 12.34);
22402241}
22412242
22422243// Unions can be given an enum tag type:
2243const ComplexTypeTag = enum { Ok, NotOk };
2244const ComplexTypeTag = enum {
2245 Ok,
2246 NotOk,
2247};
22442248const ComplexType = union(ComplexTypeTag) {
22452249 Ok: u8,
22462250 NotOk: void,
......@@ -2248,11 +2252,11 @@ const ComplexType = union(ComplexTypeTag) {
22482252
22492253// Declare a specific instance of the union variant.
22502254test "declare union value" {
2251 const c = ComplexType { .Ok = 0 };
2255 const c = ComplexType{ .Ok = 0 };
22522256 assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);
22532257}
22542258
2255// @TagType can be used to access the enum tag type of a union.
2259// @TagType can be used to access the enum tag type of a tagged union.
22562260test "@TagType" {
22572261 assert(@TagType(ComplexType) == ComplexTypeTag);
22582262}
......@@ -2266,7 +2270,7 @@ const Foo = union(enum) {
22662270 None,
22672271};
22682272test "union variant switch" {
2269 const p = Foo { .Number = 54 };
2273 const p = Foo{ .Number = 54 };
22702274 const what_is_it = switch (p) {
22712275 // Capture by reference
22722276 Foo.String => |*x| blk: {
......@@ -2301,14 +2305,13 @@ const Variant = union(enum) {
23012305};
23022306
23032307test "union method" {
2304 var v1 = Variant { .Int = 1 };
2305 var v2 = Variant { .Bool = false };
2308 var v1 = Variant{ .Int = 1 };
2309 var v2 = Variant{ .Bool = false };
23062310
23072311 assert(v1.truthy());
23082312 assert(!v2.truthy());
23092313}
23102314
2311
23122315const Small = union {
23132316 A: i32,
23142317 B: bool,
......@@ -5660,12 +5663,13 @@ test "main" {
56605663 {#header_close#}
56615664
56625665 {#header_open|@enumToInt#}
5663 <pre>{#syntax#}@enumToInt(enum_value: var) var{#endsyntax#}</pre>
5666 <pre>{#syntax#}@enumToInt(enum_or_tagged_union: var) var{#endsyntax#}</pre>
56645667 <p>
5665 Converts an enumeration or tagged union value into its integer tag type.
5668 Converts an enumeration value into its integer tag type. When a tagged union is passed,
5669 the tag value is used as the enumeration value.
56665670 </p>
56675671 <p>
5668 If the enum has only 1 possible value, the resut is a {#syntax#}comptime_int{#endsyntax#}
5672 If there is only one possible enum value, the resut is a {#syntax#}comptime_int{#endsyntax#}
56695673 known at {#link|comptime#}.
56705674 </p>
56715675 {#see_also|@intToEnum#}
src/ir.cpp+55-80
......@@ -10305,63 +10305,75 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
1030510305 return result;
1030610306}
1030710307
10308static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr,
10309 IrInstruction *target, ZigType *wanted_type)
10310{
10308static ZigType *ir_resolve_union_tag_type(IrAnalyze *ira, IrInstruction *source_instr, ZigType *union_type) {
10309 assert(union_type->id == ZigTypeIdUnion);
10310
1031110311 Error err;
10312 assert(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt);
10312 if ((err = type_resolve(ira->codegen, union_type, ResolveStatusSizeKnown)))
10313 return ira->codegen->builtin_types.entry_invalid;
1031310314
10314 ZigType *actual_type = target->value.type;
10315 AstNode *decl_node = union_type->data.unionation.decl_node;
10316 if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
10317 assert(union_type->data.unionation.tag_type != nullptr);
10318 return union_type->data.unionation.tag_type;
10319 } else {
10320 ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("union '%s' has no tag",
10321 buf_ptr(&union_type->name)));
10322 add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here"));
10323 return ira->codegen->builtin_types.entry_invalid;
10324 }
10325}
1031510326
10316 if (actual_type->id == ZigTypeIdUnion)
10317 actual_type = actual_type->data.unionation.tag_type;
10327static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target) {
10328 Error err;
1031810329
10319 if ((err = ensure_complete_type(ira->codegen, actual_type)))
10330 IrInstruction *enum_target;
10331 ZigType *enum_type;
10332 if (target->value.type->id == ZigTypeIdUnion) {
10333 enum_type = ir_resolve_union_tag_type(ira, target, target->value.type);
10334 if (type_is_invalid(enum_type))
10335 return ira->codegen->invalid_instruction;
10336 enum_target = ir_implicit_cast(ira, target, enum_type);
10337 if (type_is_invalid(enum_target->value.type))
10338 return ira->codegen->invalid_instruction;
10339 } else if (target->value.type->id == ZigTypeIdEnum) {
10340 enum_target = target;
10341 enum_type = target->value.type;
10342 } else {
10343 ir_add_error(ira, target,
10344 buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name)));
1032010345 return ira->codegen->invalid_instruction;
10346 }
1032110347
10322 if (wanted_type != actual_type->data.enumeration.tag_int_type) {
10323 ir_add_error(ira, source_instr,
10324 buf_sprintf("enum to integer cast to '%s' instead of its tag type, '%s'",
10325 buf_ptr(&wanted_type->name),
10326 buf_ptr(&actual_type->data.enumeration.tag_int_type->name)));
10348 if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusSizeKnown)))
1032710349 return ira->codegen->invalid_instruction;
10328 }
1032910350
10330 assert(actual_type->id == ZigTypeIdEnum);
10351 ZigType *tag_type = enum_type->data.enumeration.tag_int_type;
10352 assert(tag_type->id == ZigTypeIdInt || tag_type->id == ZigTypeIdComptimeInt);
1033110353
10332 if (instr_is_comptime(target)) {
10333 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
10354 if (instr_is_comptime(enum_target)) {
10355 ConstExprValue *val = ir_resolve_const(ira, enum_target, UndefBad);
1033410356 if (!val)
1033510357 return ira->codegen->invalid_instruction;
10336 IrInstruction *result = ir_const(ira, source_instr, wanted_type);
10337 if (target->value.type->id == ZigTypeIdUnion)
10338 init_const_bigint(&result->value, wanted_type, &val->data.x_union.tag);
10339 else
10340 init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag);
10341
10358 IrInstruction *result = ir_const(ira, source_instr, tag_type);
10359 init_const_bigint(&result->value, tag_type, &val->data.x_enum_tag);
1034210360 return result;
1034310361 }
1034410362
1034510363 // If there is only one possible tag, then we know at comptime what it is.
10346 if (actual_type->data.enumeration.layout == ContainerLayoutAuto &&
10347 actual_type->data.enumeration.src_field_count == 1)
10364 if (enum_type->data.enumeration.layout == ContainerLayoutAuto &&
10365 enum_type->data.enumeration.src_field_count == 1)
1034810366 {
10349 assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int);
10350 IrInstruction *result = ir_const(ira, source_instr, wanted_type);
10351 init_const_bigint(&result->value, wanted_type,
10352 &actual_type->data.enumeration.fields[0].value);
10353
10367 assert(tag_type == ira->codegen->builtin_types.entry_num_lit_int);
10368 IrInstruction *result = ir_const(ira, source_instr, tag_type);
10369 init_const_bigint(&result->value, tag_type,
10370 &enum_type->data.enumeration.fields[0].value);
1035410371 return result;
1035510372 }
1035610373
10357 IrInstruction *result = nullptr;
10358 if (target->value.type->id == ZigTypeIdUnion)
10359 result = ir_build_union_tag(&ira->new_irb, source_instr->scope,
10360 source_instr->source_node, target);
10361 else
10362 result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
10363 source_instr->source_node, target);
10364 result->value.type = wanted_type;
10374 IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
10375 source_instr->source_node, enum_target);
10376 result->value.type = tag_type;
1036510377 return result;
1036610378}
1036710379
......@@ -21378,20 +21390,10 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct
2137821390
2137921391 return ir_const_type(ira, &instruction->base, enum_type->data.enumeration.tag_int_type);
2138021392 } else if (enum_type->id == ZigTypeIdUnion) {
21381 if ((err = ensure_complete_type(ira->codegen, enum_type)))
21382 return ira->codegen->invalid_instruction;
21383
21384 AstNode *decl_node = enum_type->data.unionation.decl_node;
21385 if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
21386 assert(enum_type->data.unionation.tag_type != nullptr);
21387
21388 return ir_const_type(ira, &instruction->base, enum_type->data.unionation.tag_type);
21389 } else {
21390 ErrorMsg *msg = ir_add_error(ira, target_inst, buf_sprintf("union '%s' has no tag",
21391 buf_ptr(&enum_type->name)));
21392 add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here"));
21393 ZigType *tag_type = ir_resolve_union_tag_type(ira, instruction->target, enum_type);
21394 if (type_is_invalid(tag_type))
2139321395 return ira->codegen->invalid_instruction;
21394 }
21396 return ir_const_type(ira, &instruction->base, tag_type);
2139521397 } else {
2139621398 ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'",
2139721399 buf_ptr(&enum_type->name)));
......@@ -21972,38 +21974,11 @@ static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstr
2197221974
2197321975
2197421976static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) {
21975 Error err;
2197621977 IrInstruction *target = instruction->target->child;
21977 ZigType *enum_type = target->value.type;
21978 if (type_is_invalid(enum_type))
21979 return ira->codegen->invalid_instruction;
21980
21981 if (enum_type->id == ZigTypeIdUnion) {
21982 if ((err = ensure_complete_type(ira->codegen, enum_type)))
21983 return ira->codegen->invalid_instruction;
21984
21985 AstNode *decl_node = enum_type->data.unionation.decl_node;
21986 if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
21987 assert(enum_type->data.unionation.tag_type != nullptr);
21988 enum_type = target->value.type->data.unionation.tag_type;
21989 } else {
21990 ErrorMsg *msg = ir_add_error(ira, target, buf_sprintf("union '%s' has no tag",
21991 buf_ptr(&enum_type->name)));
21992 add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here"));
21993 return ira->codegen->invalid_instruction;
21994 }
21995 } else if (enum_type->id != ZigTypeIdEnum) {
21996 ir_add_error(ira, instruction->target,
21997 buf_sprintf("expected enum or union(enum), found type '%s'", buf_ptr(&enum_type->name)));
21998 return ira->codegen->invalid_instruction;
21999 }
22000
22001 if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusZeroBitsKnown)))
21978 if (type_is_invalid(target->value.type))
2200221979 return ira->codegen->invalid_instruction;
2200321980
22004 ZigType *int_type = enum_type->data.enumeration.tag_int_type;
22005
22006 return ir_analyze_enum_to_int(ira, &instruction->base, target, int_type);
21981 return ir_analyze_enum_to_int(ira, &instruction->base, target);
2200721982}
2200821983
2200921984static IrInstruction *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) {
test/stage1/behavior/union.zig+21-5
......@@ -126,7 +126,7 @@ const MultipleChoice = union(enum(u32)) {
126126test "simple union(enum(u32))" {
127127 var x = MultipleChoice.C;
128128 expect(x == MultipleChoice.C);
129 expect(@enumToInt(x) == 60);
129 expect(@enumToInt(@TagType(MultipleChoice)(x)) == 60);
130130}
131131
132132const MultipleChoice2 = union(enum(u32)) {
......@@ -148,7 +148,7 @@ test "union(enum(u32)) with specified and unspecified tag values" {
148148}
149149
150150fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
151 expect(@enumToInt(x) == 60);
151 expect(@enumToInt(@TagType(MultipleChoice2)(x)) == 60);
152152 expect(1123 == switch (x) {
153153 MultipleChoice2.A => 1,
154154 MultipleChoice2.B => 2,
......@@ -345,7 +345,23 @@ test "union with only 1 field casted to its enum type which has enum value speci
345345
346346 var e = Expr{ .Literal = Literal{ .Bool = true } };
347347 comptime expect(@TagType(Tag) == comptime_int);
348 expect(Tag(e) == Expr.Literal);
349 expect(@enumToInt(e) == 33);
350 comptime expect(@enumToInt(e) == 33);
348 var t = Tag(e);
349 expect(t == Expr.Literal);
350 expect(@enumToInt(t) == 33);
351 comptime expect(@enumToInt(t) == 33);
352}
353
354test "@enumToInt works on unions" {
355 const Bar = union(enum) {
356 A: bool,
357 B: u8,
358 C,
359 };
360
361 const a = Bar{ .A = true };
362 var b = Bar{ .B = undefined };
363 var c = Bar.C;
364 expect(@enumToInt(a) == 0);
365 expect(@enumToInt(b) == 1);
366 expect(@enumToInt(c) == 2);
351367}
test/tests.zig+4-8
......@@ -572,9 +572,7 @@ pub const CompileErrorContext = struct {
572572 const source_file = ".tmp_source.zig";
573573
574574 fn init(input: []const u8) ErrLineIter {
575 return ErrLineIter {
576 .lines = mem.separate(input, "\n"),
577 };
575 return ErrLineIter{ .lines = mem.separate(input, "\n") };
578576 }
579577
580578 fn next(self: *ErrLineIter) ?[]const u8 {
......@@ -718,11 +716,10 @@ pub const CompileErrorContext = struct {
718716 for (self.case.expected_errors.toSliceConst()) |expected| {
719717 if (mem.indexOf(u8, stderr, expected) == null) {
720718 warn(
721 \\=========== Expected compile error: ============
719 \\\n=========== Expected compile error: ============
722720 \\{}
723721 \\
724 , expected
725 );
722 , expected);
726723 ok = false;
727724 break;
728725 }
......@@ -734,8 +731,7 @@ pub const CompileErrorContext = struct {
734731 \\================= Full output: =================
735732 \\{}
736733 \\
737 , stderr
738 );
734 , stderr);
739735 return error.TestFailed;
740736 }
741737