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" {...@@ -2221,8 +2221,9 @@ test "packed enum" {
2221 {#header_close#}2221 {#header_close#}
2222 {#header_open|union#}2222 {#header_open|union#}
2223 {#code_begin|test|union#}2223 {#code_begin|test|union#}
2224const assert = @import("std").debug.assert;2224const std = @import("std");
2225const mem = @import("std").mem;2225const assert = std.debug.assert;
2226const mem = std.mem;
22262227
2227// A union has only 1 active field at a time.2228// A union has only 1 active field at a time.
2228const Payload = union {2229const Payload = union {
...@@ -2231,16 +2232,19 @@ const Payload = union {...@@ -2231,16 +2232,19 @@ const Payload = union {
2231 Bool: bool,2232 Bool: bool,
2232};2233};
2233test "simple union" {2234test "simple union" {
2234 var payload = Payload {.Int = 1234};2235 var payload = Payload{ .Int = 1234 };
2235 // payload.Float = 12.34; // ERROR! field not active2236 // payload.Float = 12.34; // ERROR! field not active
2236 assert(payload.Int == 1234);2237 assert(payload.Int == 1234);
2237 // You can activate another field by assigning the entire union.2238 // You can activate another field by assigning the entire union.
2238 payload = Payload {.Float = 12.34};2239 payload = Payload{ .Float = 12.34 };
2239 assert(payload.Float == 12.34);2240 assert(payload.Float == 12.34);
2240}2241}
22412242
2242// Unions can be given an enum tag type:2243// Unions can be given an enum tag type:
2243const ComplexTypeTag = enum { Ok, NotOk }; 2244const ComplexTypeTag = enum {
2245 Ok,
2246 NotOk,
2247};
2244const ComplexType = union(ComplexTypeTag) {2248const ComplexType = union(ComplexTypeTag) {
2245 Ok: u8,2249 Ok: u8,
2246 NotOk: void,2250 NotOk: void,
...@@ -2248,11 +2252,11 @@ const ComplexType = union(ComplexTypeTag) {...@@ -2248,11 +2252,11 @@ const ComplexType = union(ComplexTypeTag) {
22482252
2249// Declare a specific instance of the union variant.2253// Declare a specific instance of the union variant.
2250test "declare union value" {2254test "declare union value" {
2251 const c = ComplexType { .Ok = 0 };2255 const c = ComplexType{ .Ok = 0 };
2252 assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);2256 assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);
2253}2257}
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.
2256test "@TagType" {2260test "@TagType" {
2257 assert(@TagType(ComplexType) == ComplexTypeTag);2261 assert(@TagType(ComplexType) == ComplexTypeTag);
2258}2262}
...@@ -2266,7 +2270,7 @@ const Foo = union(enum) {...@@ -2266,7 +2270,7 @@ const Foo = union(enum) {
2266 None,2270 None,
2267};2271};
2268test "union variant switch" {2272test "union variant switch" {
2269 const p = Foo { .Number = 54 };2273 const p = Foo{ .Number = 54 };
2270 const what_is_it = switch (p) {2274 const what_is_it = switch (p) {
2271 // Capture by reference2275 // Capture by reference
2272 Foo.String => |*x| blk: {2276 Foo.String => |*x| blk: {
...@@ -2301,14 +2305,13 @@ const Variant = union(enum) {...@@ -2301,14 +2305,13 @@ const Variant = union(enum) {
2301};2305};
23022306
2303test "union method" {2307test "union method" {
2304 var v1 = Variant { .Int = 1 };2308 var v1 = Variant{ .Int = 1 };
2305 var v2 = Variant { .Bool = false };2309 var v2 = Variant{ .Bool = false };
23062310
2307 assert(v1.truthy());2311 assert(v1.truthy());
2308 assert(!v2.truthy());2312 assert(!v2.truthy());
2309}2313}
23102314
2311
2312const Small = union {2315const Small = union {
2313 A: i32,2316 A: i32,
2314 B: bool,2317 B: bool,
...@@ -5660,12 +5663,13 @@ test "main" {...@@ -5660,12 +5663,13 @@ test "main" {
5660 {#header_close#}5663 {#header_close#}
56615664
5662 {#header_open|@enumToInt#}5665 {#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>
5664 <p>5667 <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.
5666 </p>5670 </p>
5667 <p>5671 <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#}
5669 known at {#link|comptime#}.5673 known at {#link|comptime#}.
5670 </p>5674 </p>
5671 {#see_also|@intToEnum#}5675 {#see_also|@intToEnum#}
src/ir.cpp+55-80
...@@ -10305,63 +10305,75 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s...@@ -10305,63 +10305,75 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
10305 return result;10305 return result;
10306}10306}
1030710307
10308static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr,10308static ZigType *ir_resolve_union_tag_type(IrAnalyze *ira, IrInstruction *source_instr, ZigType *union_type) {
10309 IrInstruction *target, ZigType *wanted_type)10309 assert(union_type->id == ZigTypeIdUnion);
10310{10310
10311 Error err;10311 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)10327static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target) {
10317 actual_type = actual_type->data.unionation.tag_type;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)));
10320 return ira->codegen->invalid_instruction;10345 return ira->codegen->invalid_instruction;
10346 }
1032110347
10322 if (wanted_type != actual_type->data.enumeration.tag_int_type) {10348 if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusSizeKnown)))
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)));
10327 return ira->codegen->invalid_instruction;10349 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)) {10354 if (instr_is_comptime(enum_target)) {
10333 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);10355 ConstExprValue *val = ir_resolve_const(ira, enum_target, UndefBad);
10334 if (!val)10356 if (!val)
10335 return ira->codegen->invalid_instruction;10357 return ira->codegen->invalid_instruction;
10336 IrInstruction *result = ir_const(ira, source_instr, wanted_type);10358 IrInstruction *result = ir_const(ira, source_instr, tag_type);
10337 if (target->value.type->id == ZigTypeIdUnion)10359 init_const_bigint(&result->value, tag_type, &val->data.x_enum_tag);
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
10342 return result;10360 return result;
10343 }10361 }
1034410362
10345 // If there is only one possible tag, then we know at comptime what it is.10363 // If there is only one possible tag, then we know at comptime what it is.
10346 if (actual_type->data.enumeration.layout == ContainerLayoutAuto &&10364 if (enum_type->data.enumeration.layout == ContainerLayoutAuto &&
10347 actual_type->data.enumeration.src_field_count == 1)10365 enum_type->data.enumeration.src_field_count == 1)
10348 {10366 {
10349 assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int);10367 assert(tag_type == ira->codegen->builtin_types.entry_num_lit_int);
10350 IrInstruction *result = ir_const(ira, source_instr, wanted_type);10368 IrInstruction *result = ir_const(ira, source_instr, tag_type);
10351 init_const_bigint(&result->value, wanted_type,10369 init_const_bigint(&result->value, tag_type,
10352 &actual_type->data.enumeration.fields[0].value);10370 &enum_type->data.enumeration.fields[0].value);
10353
10354 return result;10371 return result;
10355 }10372 }
1035610373
10357 IrInstruction *result = nullptr;10374 IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
10358 if (target->value.type->id == ZigTypeIdUnion)10375 source_instr->source_node, enum_target);
10359 result = ir_build_union_tag(&ira->new_irb, source_instr->scope,10376 result->value.type = tag_type;
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;
10365 return result;10377 return result;
10366}10378}
1036710379
...@@ -21378,20 +21390,10 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct...@@ -21378,20 +21390,10 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct
2137821390
21379 return ir_const_type(ira, &instruction->base, enum_type->data.enumeration.tag_int_type);21391 return ir_const_type(ira, &instruction->base, enum_type->data.enumeration.tag_int_type);
21380 } else if (enum_type->id == ZigTypeIdUnion) {21392 } else if (enum_type->id == ZigTypeIdUnion) {
21381 if ((err = ensure_complete_type(ira->codegen, enum_type)))21393 ZigType *tag_type = ir_resolve_union_tag_type(ira, instruction->target, enum_type);
21382 return ira->codegen->invalid_instruction;21394 if (type_is_invalid(tag_type))
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 return ira->codegen->invalid_instruction;21395 return ira->codegen->invalid_instruction;
21394 }21396 return ir_const_type(ira, &instruction->base, tag_type);
21395 } else {21397 } else {
21396 ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'",21398 ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'",
21397 buf_ptr(&enum_type->name)));21399 buf_ptr(&enum_type->name)));
...@@ -21972,38 +21974,11 @@ static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstr...@@ -21972,38 +21974,11 @@ static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstr
2197221974
2197321975
21974static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) {21976static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) {
21975 Error err;
21976 IrInstruction *target = instruction->target->child;21977 IrInstruction *target = instruction->target->child;
21977 ZigType *enum_type = target->value.type;21978 if (type_is_invalid(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)))
22002 return ira->codegen->invalid_instruction;21979 return ira->codegen->invalid_instruction;
2200321980
22004 ZigType *int_type = enum_type->data.enumeration.tag_int_type;21981 return ir_analyze_enum_to_int(ira, &instruction->base, target);
22005
22006 return ir_analyze_enum_to_int(ira, &instruction->base, target, int_type);
22007}21982}
2200821983
22009static IrInstruction *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) {21984static 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)) {...@@ -126,7 +126,7 @@ const MultipleChoice = union(enum(u32)) {
126test "simple union(enum(u32))" {126test "simple union(enum(u32))" {
127 var x = MultipleChoice.C;127 var x = MultipleChoice.C;
128 expect(x == MultipleChoice.C);128 expect(x == MultipleChoice.C);
129 expect(@enumToInt(x) == 60);129 expect(@enumToInt(@TagType(MultipleChoice)(x)) == 60);
130}130}
131131
132const MultipleChoice2 = union(enum(u32)) {132const MultipleChoice2 = union(enum(u32)) {
...@@ -148,7 +148,7 @@ test "union(enum(u32)) with specified and unspecified tag values" {...@@ -148,7 +148,7 @@ test "union(enum(u32)) with specified and unspecified tag values" {
148}148}
149149
150fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {150fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
151 expect(@enumToInt(x) == 60);151 expect(@enumToInt(@TagType(MultipleChoice2)(x)) == 60);
152 expect(1123 == switch (x) {152 expect(1123 == switch (x) {
153 MultipleChoice2.A => 1,153 MultipleChoice2.A => 1,
154 MultipleChoice2.B => 2,154 MultipleChoice2.B => 2,
...@@ -345,7 +345,23 @@ test "union with only 1 field casted to its enum type which has enum value speci...@@ -345,7 +345,23 @@ test "union with only 1 field casted to its enum type which has enum value speci
345345
346 var e = Expr{ .Literal = Literal{ .Bool = true } };346 var e = Expr{ .Literal = Literal{ .Bool = true } };
347 comptime expect(@TagType(Tag) == comptime_int);347 comptime expect(@TagType(Tag) == comptime_int);
348 expect(Tag(e) == Expr.Literal);348 var t = Tag(e);
349 expect(@enumToInt(e) == 33);349 expect(t == Expr.Literal);
350 comptime expect(@enumToInt(e) == 33);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);
351}367}
test/tests.zig+4-8
...@@ -572,9 +572,7 @@ pub const CompileErrorContext = struct {...@@ -572,9 +572,7 @@ pub const CompileErrorContext = struct {
572 const source_file = ".tmp_source.zig";572 const source_file = ".tmp_source.zig";
573573
574 fn init(input: []const u8) ErrLineIter {574 fn init(input: []const u8) ErrLineIter {
575 return ErrLineIter {575 return ErrLineIter{ .lines = mem.separate(input, "\n") };
576 .lines = mem.separate(input, "\n"),
577 };
578 }576 }
579577
580 fn next(self: *ErrLineIter) ?[]const u8 {578 fn next(self: *ErrLineIter) ?[]const u8 {
...@@ -718,11 +716,10 @@ pub const CompileErrorContext = struct {...@@ -718,11 +716,10 @@ pub const CompileErrorContext = struct {
718 for (self.case.expected_errors.toSliceConst()) |expected| {716 for (self.case.expected_errors.toSliceConst()) |expected| {
719 if (mem.indexOf(u8, stderr, expected) == null) {717 if (mem.indexOf(u8, stderr, expected) == null) {
720 warn(718 warn(
721 \\=========== Expected compile error: ============719 \\\n=========== Expected compile error: ============
722 \\{}720 \\{}
723 \\721 \\
724 , expected722 , expected);
725 );
726 ok = false;723 ok = false;
727 break;724 break;
728 }725 }
...@@ -734,8 +731,7 @@ pub const CompileErrorContext = struct {...@@ -734,8 +731,7 @@ pub const CompileErrorContext = struct {
734 \\================= Full output: =================731 \\================= Full output: =================
735 \\{}732 \\{}
736 \\733 \\
737 , stderr734 , stderr);
738 );
739 return error.TestFailed;735 return error.TestFailed;
740 }736 }
741737