1const builtin = @import("builtin");
2const std = @import("std");
3const expect = std.testing.expect;
4const assert = std.debug.assert;
5const mem = std.mem;
6const Tag = std.meta.Tag;
7
8const Number = enum { Zero, One, Two, Three, Four };
9
10fn shouldEqual(n: Number, expected: u3) !void {
11 try expect(@backingInt(n) == expected);
12}
13
14test "enum to int" {
15 try shouldEqual(Number.Zero, 0);
16 try shouldEqual(Number.One, 1);
17 try shouldEqual(Number.Two, 2);
18 try shouldEqual(Number.Three, 3);
19 try shouldEqual(Number.Four, 4);
20}
21
22fn testEnumFromIntEval(x: i32) !void {
23 try expect(@as(EnumFromIntNumber, @fromBackingInt(@intCast(x))) == EnumFromIntNumber.Three);
24}
25const EnumFromIntNumber = enum { Zero, One, Two, Three, Four };
26
27test "int to enum" {
28 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
29
30 try testEnumFromIntEval(3);
31}
32
33const ValueCount1 = enum {
34 I0,
35};
36const ValueCount2 = enum {
37 I0,
38 I1,
39};
40const ValueCount256 = enum {
41 I0,
42 I1,
43 I2,
44 I3,
45 I4,
46 I5,
47 I6,
48 I7,
49 I8,
50 I9,
51 I10,
52 I11,
53 I12,
54 I13,
55 I14,
56 I15,
57 I16,
58 I17,
59 I18,
60 I19,
61 I20,
62 I21,
63 I22,
64 I23,
65 I24,
66 I25,
67 I26,
68 I27,
69 I28,
70 I29,
71 I30,
72 I31,
73 I32,
74 I33,
75 I34,
76 I35,
77 I36,
78 I37,
79 I38,
80 I39,
81 I40,
82 I41,
83 I42,
84 I43,
85 I44,
86 I45,
87 I46,
88 I47,
89 I48,
90 I49,
91 I50,
92 I51,
93 I52,
94 I53,
95 I54,
96 I55,
97 I56,
98 I57,
99 I58,
100 I59,
101 I60,
102 I61,
103 I62,
104 I63,
105 I64,
106 I65,
107 I66,
108 I67,
109 I68,
110 I69,
111 I70,
112 I71,
113 I72,
114 I73,
115 I74,
116 I75,
117 I76,
118 I77,
119 I78,
120 I79,
121 I80,
122 I81,
123 I82,
124 I83,
125 I84,
126 I85,
127 I86,
128 I87,
129 I88,
130 I89,
131 I90,
132 I91,
133 I92,
134 I93,
135 I94,
136 I95,
137 I96,
138 I97,
139 I98,
140 I99,
141 I100,
142 I101,
143 I102,
144 I103,
145 I104,
146 I105,
147 I106,
148 I107,
149 I108,
150 I109,
151 I110,
152 I111,
153 I112,
154 I113,
155 I114,
156 I115,
157 I116,
158 I117,
159 I118,
160 I119,
161 I120,
162 I121,
163 I122,
164 I123,
165 I124,
166 I125,
167 I126,
168 I127,
169 I128,
170 I129,
171 I130,
172 I131,
173 I132,
174 I133,
175 I134,
176 I135,
177 I136,
178 I137,
179 I138,
180 I139,
181 I140,
182 I141,
183 I142,
184 I143,
185 I144,
186 I145,
187 I146,
188 I147,
189 I148,
190 I149,
191 I150,
192 I151,
193 I152,
194 I153,
195 I154,
196 I155,
197 I156,
198 I157,
199 I158,
200 I159,
201 I160,
202 I161,
203 I162,
204 I163,
205 I164,
206 I165,
207 I166,
208 I167,
209 I168,
210 I169,
211 I170,
212 I171,
213 I172,
214 I173,
215 I174,
216 I175,
217 I176,
218 I177,
219 I178,
220 I179,
221 I180,
222 I181,
223 I182,
224 I183,
225 I184,
226 I185,
227 I186,
228 I187,
229 I188,
230 I189,
231 I190,
232 I191,
233 I192,
234 I193,
235 I194,
236 I195,
237 I196,
238 I197,
239 I198,
240 I199,
241 I200,
242 I201,
243 I202,
244 I203,
245 I204,
246 I205,
247 I206,
248 I207,
249 I208,
250 I209,
251 I210,
252 I211,
253 I212,
254 I213,
255 I214,
256 I215,
257 I216,
258 I217,
259 I218,
260 I219,
261 I220,
262 I221,
263 I222,
264 I223,
265 I224,
266 I225,
267 I226,
268 I227,
269 I228,
270 I229,
271 I230,
272 I231,
273 I232,
274 I233,
275 I234,
276 I235,
277 I236,
278 I237,
279 I238,
280 I239,
281 I240,
282 I241,
283 I242,
284 I243,
285 I244,
286 I245,
287 I246,
288 I247,
289 I248,
290 I249,
291 I250,
292 I251,
293 I252,
294 I253,
295 I254,
296 I255,
297};
298const ValueCount257 = enum {
299 I0,
300 I1,
301 I2,
302 I3,
303 I4,
304 I5,
305 I6,
306 I7,
307 I8,
308 I9,
309 I10,
310 I11,
311 I12,
312 I13,
313 I14,
314 I15,
315 I16,
316 I17,
317 I18,
318 I19,
319 I20,
320 I21,
321 I22,
322 I23,
323 I24,
324 I25,
325 I26,
326 I27,
327 I28,
328 I29,
329 I30,
330 I31,
331 I32,
332 I33,
333 I34,
334 I35,
335 I36,
336 I37,
337 I38,
338 I39,
339 I40,
340 I41,
341 I42,
342 I43,
343 I44,
344 I45,
345 I46,
346 I47,
347 I48,
348 I49,
349 I50,
350 I51,
351 I52,
352 I53,
353 I54,
354 I55,
355 I56,
356 I57,
357 I58,
358 I59,
359 I60,
360 I61,
361 I62,
362 I63,
363 I64,
364 I65,
365 I66,
366 I67,
367 I68,
368 I69,
369 I70,
370 I71,
371 I72,
372 I73,
373 I74,
374 I75,
375 I76,
376 I77,
377 I78,
378 I79,
379 I80,
380 I81,
381 I82,
382 I83,
383 I84,
384 I85,
385 I86,
386 I87,
387 I88,
388 I89,
389 I90,
390 I91,
391 I92,
392 I93,
393 I94,
394 I95,
395 I96,
396 I97,
397 I98,
398 I99,
399 I100,
400 I101,
401 I102,
402 I103,
403 I104,
404 I105,
405 I106,
406 I107,
407 I108,
408 I109,
409 I110,
410 I111,
411 I112,
412 I113,
413 I114,
414 I115,
415 I116,
416 I117,
417 I118,
418 I119,
419 I120,
420 I121,
421 I122,
422 I123,
423 I124,
424 I125,
425 I126,
426 I127,
427 I128,
428 I129,
429 I130,
430 I131,
431 I132,
432 I133,
433 I134,
434 I135,
435 I136,
436 I137,
437 I138,
438 I139,
439 I140,
440 I141,
441 I142,
442 I143,
443 I144,
444 I145,
445 I146,
446 I147,
447 I148,
448 I149,
449 I150,
450 I151,
451 I152,
452 I153,
453 I154,
454 I155,
455 I156,
456 I157,
457 I158,
458 I159,
459 I160,
460 I161,
461 I162,
462 I163,
463 I164,
464 I165,
465 I166,
466 I167,
467 I168,
468 I169,
469 I170,
470 I171,
471 I172,
472 I173,
473 I174,
474 I175,
475 I176,
476 I177,
477 I178,
478 I179,
479 I180,
480 I181,
481 I182,
482 I183,
483 I184,
484 I185,
485 I186,
486 I187,
487 I188,
488 I189,
489 I190,
490 I191,
491 I192,
492 I193,
493 I194,
494 I195,
495 I196,
496 I197,
497 I198,
498 I199,
499 I200,
500 I201,
501 I202,
502 I203,
503 I204,
504 I205,
505 I206,
506 I207,
507 I208,
508 I209,
509 I210,
510 I211,
511 I212,
512 I213,
513 I214,
514 I215,
515 I216,
516 I217,
517 I218,
518 I219,
519 I220,
520 I221,
521 I222,
522 I223,
523 I224,
524 I225,
525 I226,
526 I227,
527 I228,
528 I229,
529 I230,
530 I231,
531 I232,
532 I233,
533 I234,
534 I235,
535 I236,
536 I237,
537 I238,
538 I239,
539 I240,
540 I241,
541 I242,
542 I243,
543 I244,
544 I245,
545 I246,
546 I247,
547 I248,
548 I249,
549 I250,
550 I251,
551 I252,
552 I253,
553 I254,
554 I255,
555 I256,
556};
557
558test "enum sizes" {
559 comptime {
560 try expect(@sizeOf(ValueCount1) == 0);
561 try expect(@sizeOf(ValueCount2) == 1);
562 try expect(@sizeOf(ValueCount256) == 1);
563 try expect(@sizeOf(ValueCount257) == 2);
564 }
565}
566
567test "enum literal equality" {
568 const x = .hi;
569 const y = .ok;
570 const z = .hi;
571
572 try expect(x != y);
573 try expect(x == z);
574}
575
576test "enum literal cast to enum" {
577 const Color = enum { Auto, Off, On };
578
579 var color1: Color = .Auto;
580 var color2 = Color.Auto;
581 _ = .{ &color1, &color2 };
582 try expect(color1 == color2);
583}
584
585test "peer type resolution with enum literal" {
586 const Items = enum { one, two };
587
588 try expect(Items.two == .two);
589 try expect(.two == Items.two);
590}
591
592const MultipleChoice = enum(u32) {
593 A = 20,
594 B = 40,
595 C = 60,
596 D = 1000,
597};
598
599fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
600 try expect(@backingInt(x) == 60);
601 try expect(1234 == switch (x) {
602 MultipleChoice.A => 1,
603 MultipleChoice.B => 2,
604 MultipleChoice.C => @as(u32, 1234),
605 MultipleChoice.D => 4,
606 });
607}
608
609test "enum with specified tag values" {
610 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
611
612 try testEnumWithSpecifiedTagValues(MultipleChoice.C);
613 try comptime testEnumWithSpecifiedTagValues(MultipleChoice.C);
614}
615
616test "non-exhaustive enum" {
617 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
618
619 const S = struct {
620 const E = enum(u8) { a, b, _ };
621
622 fn doTheTest(y: u8) !void {
623 var e: E = .b;
624 try expect(switch (e) {
625 .a => false,
626 .b => true,
627 _ => false,
628 });
629 e = @as(E, @fromBackingInt(@intCast(12)));
630 try expect(switch (e) {
631 .a => false,
632 .b => false,
633 _ => true,
634 });
635
636 try expect(switch (e) {
637 .a => false,
638 .b => false,
639 else => true,
640 });
641 e = .b;
642 try expect(switch (e) {
643 .a => false,
644 else => true,
645 });
646
647 try expect(@typeInfo(E).@"enum".field_names.len == 2);
648 e = @as(E, @fromBackingInt(@intCast(12)));
649 try expect(@backingInt(e) == 12);
650 e = @as(E, @fromBackingInt(@intCast(y)));
651 try expect(@backingInt(e) == 52);
652 try expect(@typeInfo(E).@"enum".mode == .nonexhaustive);
653 }
654 };
655 try S.doTheTest(52);
656 try comptime S.doTheTest(52);
657}
658
659test "empty non-exhaustive enum" {
660 const S = struct {
661 const E = enum(u8) { _ };
662
663 fn doTheTest(y: u8) !void {
664 var e: E = @fromBackingInt(@intCast(y));
665 _ = &e;
666 try expect(switch (e) {
667 _ => true,
668 });
669 try expect(@backingInt(e) == y);
670
671 try expect(@typeInfo(E).@"enum".field_names.len == 0);
672 try expect(@typeInfo(E).@"enum".field_values.len == 0);
673 try expect(@typeInfo(E).@"enum".mode == .nonexhaustive);
674 }
675 };
676 try S.doTheTest(42);
677 try comptime S.doTheTest(42);
678}
679
680test "single field non-exhaustive enum" {
681 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
682
683 const S = struct {
684 const E = enum(u8) { a, _ };
685 fn doTheTest(y: u8) !void {
686 var e: E = .a;
687 try expect(switch (e) {
688 .a => true,
689 _ => false,
690 });
691 e = @as(E, @fromBackingInt(@intCast(12)));
692 try expect(switch (e) {
693 .a => false,
694 _ => true,
695 });
696
697 try expect(switch (e) {
698 .a => false,
699 else => true,
700 });
701 e = .a;
702 try expect(switch (e) {
703 .a => true,
704 else => false,
705 });
706
707 try expect(@backingInt(@as(E, @fromBackingInt(@intCast(y)))) == y);
708 try expect(@typeInfo(E).@"enum".field_names.len == 1);
709 try expect(@typeInfo(E).@"enum".field_values.len == 1);
710 try expect(@typeInfo(E).@"enum".mode == .nonexhaustive);
711 }
712 };
713 try S.doTheTest(23);
714 try comptime S.doTheTest(23);
715}
716
717const EnumWithTagValues = enum(u4) {
718 A = 1 << 0,
719 B = 1 << 1,
720 C = 1 << 2,
721 D = 1 << 3,
722};
723test "enum with tag values don't require parens" {
724 try expect(@backingInt(EnumWithTagValues.C) == 0b0100);
725}
726
727const MultipleChoice2 = enum(u32) {
728 Unspecified1,
729 A = 20,
730 Unspecified2,
731 B = 40,
732 Unspecified3,
733 C = 60,
734 Unspecified4,
735 D = 1000,
736 Unspecified5,
737};
738
739test "cast integer literal to enum" {
740 try expect(@as(MultipleChoice2, @fromBackingInt(@intCast(0))) == MultipleChoice2.Unspecified1);
741 try expect(@as(MultipleChoice2, @fromBackingInt(@intCast(40))) == MultipleChoice2.B);
742}
743
744test "enum with specified and unspecified tag values" {
745 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
746
747 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
748 try comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
749}
750
751fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
752 try expect(@backingInt(x) == 1000);
753 try expect(1234 == switch (x) {
754 MultipleChoice2.A => 1,
755 MultipleChoice2.B => 2,
756 MultipleChoice2.C => 3,
757 MultipleChoice2.D => @as(u32, 1234),
758 MultipleChoice2.Unspecified1 => 5,
759 MultipleChoice2.Unspecified2 => 6,
760 MultipleChoice2.Unspecified3 => 7,
761 MultipleChoice2.Unspecified4 => 8,
762 MultipleChoice2.Unspecified5 => 9,
763 });
764}
765
766const Small2 = enum(u2) { One, Two };
767const Small = enum(u2) { One, Two, Three, Four };
768
769test "set enum tag type" {
770 {
771 var x = Small.One;
772 x = Small.Two;
773 comptime assert(Tag(Small) == u2);
774 }
775 {
776 var x = Small2.One;
777 x = Small2.Two;
778 comptime assert(Tag(Small2) == u2);
779 }
780}
781
782test "casting enum to its tag type" {
783 try testCastEnumTag(Small2.Two);
784 try comptime testCastEnumTag(Small2.Two);
785}
786
787fn testCastEnumTag(value: Small2) !void {
788 try expect(@backingInt(value) == 1);
789}
790
791test "enum with 1 field but explicit tag type should still have the tag type" {
792 const Enum = enum(u8) {
793 B = 2,
794 };
795 comptime assert(@sizeOf(Enum) == @sizeOf(u8));
796}
797
798test "signed integer as enum tag" {
799 const SignedEnum = enum(i2) {
800 A0 = -1,
801 A1 = 0,
802 A2 = 1,
803 };
804
805 try expect(@backingInt(SignedEnum.A0) == -1);
806 try expect(@backingInt(SignedEnum.A1) == 0);
807 try expect(@backingInt(SignedEnum.A2) == 1);
808}
809
810test "enum with one member and custom tag type" {
811 const E = enum(u2) {
812 One,
813 };
814 try expect(@backingInt(E.One) == 0);
815 const E2 = enum(u2) {
816 One = 2,
817 };
818 try expect(@backingInt(E2.One) == 2);
819}
820
821test "enum with one member and u1 tag type @intFromEnum" {
822 const Enum = enum(u1) {
823 Test,
824 };
825 try expect(@backingInt(Enum.Test) == 0);
826}
827
828test "enum with one member default to u0 tag type" {
829 const E0 = enum { X };
830 comptime assert(Tag(E0) == u0);
831}
832
833const EnumWithOneMember = enum { Eof };
834
835fn doALoopThing(id: EnumWithOneMember) void {
836 while (true) {
837 if (id == EnumWithOneMember.Eof) {
838 break;
839 }
840 @compileError("above if condition should be comptime");
841 }
842}
843
844test "comparison operator on enum with one member is comptime-known" {
845 doALoopThing(EnumWithOneMember.Eof);
846}
847
848const State = enum { Start };
849test "switch on enum with one member is comptime-known" {
850 var state = State.Start;
851 _ = &state;
852 switch (state) {
853 State.Start => return,
854 }
855 @compileError("analysis should not reach here");
856}
857
858test "method call on an enum" {
859 const S = struct {
860 const E = enum {
861 one,
862 two,
863
864 fn method(self: *E) bool {
865 return self.* == .two;
866 }
867
868 fn generic_method(self: *E, foo: anytype) bool {
869 return self.* == .two and foo == bool;
870 }
871 };
872 fn doTheTest() !void {
873 var e = E.two;
874 try expect(e.method());
875 try expect(e.generic_method(bool));
876 }
877 };
878 try S.doTheTest();
879 try comptime S.doTheTest();
880}
881
882test "enum value allocation" {
883 const LargeEnum = enum(u32) {
884 A0 = 0x80000000,
885 A1,
886 A2,
887 };
888
889 try expect(@backingInt(LargeEnum.A0) == 0x80000000);
890 try expect(@backingInt(LargeEnum.A1) == 0x80000001);
891 try expect(@backingInt(LargeEnum.A2) == 0x80000002);
892}
893
894test "enum literal casting to tagged union" {
895 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
896 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
897
898 const Arch = union(enum) {
899 x86_64,
900 arm: Arm32,
901
902 const Arm32 = enum {
903 v8_5a,
904 v8_4a,
905 };
906 };
907
908 var t = true;
909 var x: Arch = .x86_64;
910 _ = .{ &t, &x };
911 const y = if (t) x else .x86_64;
912 switch (y) {
913 .x86_64 => {},
914 else => @panic("fail"),
915 }
916}
917
918const Bar = enum { A, B, C, D };
919
920test "enum literal casting to error union with payload enum" {
921 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
922
923 var bar: error{B}!Bar = undefined;
924 bar = .B; // should never cast to the error set
925
926 try expect((try bar) == Bar.B);
927}
928
929test "constant enum initialization with differing sizes" {
930 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
931 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
932 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
933 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
934 try test3_1(test3_foo);
935 try test3_2(test3_bar);
936}
937const Test3Foo = union(enum) {
938 One: void,
939 Two: f32,
940 Three: Test3Point,
941};
942const Test3Point = struct {
943 x: i32,
944 y: i32,
945};
946const test3_foo = Test3Foo{
947 .Three = Test3Point{
948 .x = 3,
949 .y = 4,
950 },
951};
952const test3_bar = Test3Foo{ .Two = 13 };
953fn test3_1(f: Test3Foo) !void {
954 switch (f) {
955 Test3Foo.Three => |pt| {
956 try expect(pt.x == 3);
957 try expect(pt.y == 4);
958 },
959 else => unreachable,
960 }
961}
962fn test3_2(f: Test3Foo) !void {
963 switch (f) {
964 Test3Foo.Two => |x| {
965 try expect(x == 13);
966 },
967 else => unreachable,
968 }
969}
970
971test "@tagName" {
972 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
973 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
974 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
975 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
976 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
977
978 try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
979 comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
980}
981
982fn testEnumTagNameBare(n: anytype) []const u8 {
983 return @tagName(n);
984}
985
986const BareNumber = enum { One, Two, Three };
987
988test "@tagName non-exhaustive enum" {
989 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
990 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
991 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
992 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
993 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
994
995 try expect(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
996 comptime assert(mem.eql(u8, testEnumTagNameBare(NonExhaustive.B), "B"));
997}
998const NonExhaustive = enum(u8) { A, B, _ };
999
1000test "@tagName is null-terminated" {
1001 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1002 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1003 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1004 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1005 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1006
1007 const S = struct {
1008 fn doTheTest(n: BareNumber) !void {
1009 try expect(@tagName(n)[3] == 0);
1010 }
1011 };
1012 try S.doTheTest(.Two);
1013 try comptime S.doTheTest(.Two);
1014}
1015
1016test "tag name with assigned enum values" {
1017 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1018 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1019 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1020 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1021 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1022
1023 const LocalFoo = enum(u8) {
1024 A = 1,
1025 B = 0,
1026 };
1027 var b = LocalFoo.B;
1028 _ = &b;
1029 try expect(mem.eql(u8, @tagName(b), "B"));
1030}
1031
1032test "@tagName on enum literals" {
1033 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1034 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1035
1036 try expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
1037 comptime assert(mem.eql(u8, @tagName(.FooBar), "FooBar"));
1038}
1039
1040test "tag name with signed enum values" {
1041 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1042 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1043 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1044 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1045 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1046
1047 const LocalFoo = enum(isize) {
1048 alfa = 62,
1049 bravo = 63,
1050 charlie = 64,
1051 delta = 65,
1052 };
1053 var b = LocalFoo.bravo;
1054 _ = &b;
1055 try expect(mem.eql(u8, @tagName(b), "bravo"));
1056}
1057
1058test "tag name with large enum values" {
1059 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1060 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1061 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1062
1063 const Kdf = enum(u128) {
1064 aes_kdf = 0xea4f8ac1080d74bf60448a629af3d9c9,
1065 argon2d = 0x0c0ae303a4a9f7914b44298cdf6d63ef,
1066 argon2id = 0xe6a1f0c63efc3db27347db56198b299e,
1067 };
1068 var kdf: Kdf = .aes_kdf;
1069 try expect(mem.eql(u8, @tagName(kdf), "aes_kdf"));
1070 var argon2d_value: u128 = undefined;
1071 argon2d_value = @backingInt(Kdf.argon2d);
1072 kdf = @fromBackingInt(@intCast(argon2d_value));
1073 try expect(mem.eql(u8, @tagName(kdf), "argon2d"));
1074 kdf = .argon2id;
1075 try expect(mem.eql(u8, @tagName(kdf), "argon2id"));
1076}
1077
1078test "@tagName with exotic integer enum types" {
1079 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1080 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1081 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1082
1083 const S = struct {
1084 fn testEnumSigned(comptime T: type) !void {
1085 {
1086 const E1 = enum(T) {
1087 a = -125,
1088 b = 125,
1089 c = std.math.minInt(T),
1090 d = std.math.maxInt(T),
1091 };
1092
1093 var e: E1 = .a;
1094 try expect(mem.eql(u8, @tagName(e), "a"));
1095 e = .b;
1096 try expect(mem.eql(u8, @tagName(e), "b"));
1097 e = .c;
1098 try expect(mem.eql(u8, @tagName(e), "c"));
1099 e = .d;
1100 try expect(mem.eql(u8, @tagName(e), "d"));
1101 }
1102 {
1103 const E2 = enum(T) {
1104 a = -125,
1105 b = 125,
1106 c = std.math.minInt(T),
1107 d = std.math.maxInt(T),
1108 _,
1109 };
1110
1111 var e: E2 = .a;
1112 try expect(mem.eql(u8, @tagName(e), "a"));
1113 e = .b;
1114 try expect(mem.eql(u8, @tagName(e), "b"));
1115 e = .c;
1116 try expect(mem.eql(u8, @tagName(e), "c"));
1117 e = .d;
1118 try expect(mem.eql(u8, @tagName(e), "d"));
1119 }
1120 }
1121
1122 fn testEnumUnsigned(comptime T: type) !void {
1123 {
1124 const E1 = enum(T) {
1125 a = std.math.maxInt(T) - 125,
1126 b = 125,
1127 c = std.math.minInt(T),
1128 d = std.math.maxInt(T),
1129 };
1130
1131 var e: E1 = .a;
1132 try expect(mem.eql(u8, @tagName(e), "a"));
1133 e = .b;
1134 try expect(mem.eql(u8, @tagName(e), "b"));
1135 e = .c;
1136 try expect(mem.eql(u8, @tagName(e), "c"));
1137 e = .d;
1138 try expect(mem.eql(u8, @tagName(e), "d"));
1139 }
1140 {
1141 const E2 = enum(T) {
1142 a = std.math.maxInt(T) - 125,
1143 b = 125,
1144 c = std.math.minInt(T),
1145 d = std.math.maxInt(T),
1146 _,
1147 };
1148
1149 var e: E2 = .a;
1150 try expect(mem.eql(u8, @tagName(e), "a"));
1151 e = .b;
1152 try expect(mem.eql(u8, @tagName(e), "b"));
1153 e = .c;
1154 try expect(mem.eql(u8, @tagName(e), "c"));
1155 e = .d;
1156 try expect(mem.eql(u8, @tagName(e), "d"));
1157 }
1158 }
1159
1160 fn doTheTest() !void {
1161 try testEnumSigned(i33);
1162 try testEnumSigned(i95);
1163 try testEnumSigned(i127);
1164 try testEnumSigned(i257);
1165
1166 try testEnumUnsigned(u33);
1167 try testEnumUnsigned(u95);
1168 try testEnumUnsigned(u127);
1169 try testEnumUnsigned(u257);
1170 }
1171 };
1172
1173 try S.doTheTest();
1174 try comptime S.doTheTest();
1175}
1176
1177test "@tagName in callconv(.c) function" {
1178 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1179 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1180 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1181 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1182 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1183
1184 try expect(mem.orderZ(u8, testEnumTagNameCallconvC(), "Two") == .eq);
1185 comptime assert(mem.orderZ(u8, testEnumTagNameCallconvC(), "Two") == .eq);
1186}
1187
1188fn testEnumTagNameCallconvC() callconv(.c) [*:0]const u8 {
1189 var e: BareNumber = .Two;
1190 _ = &e;
1191 return @tagName(e);
1192}
1193
1194test "enum literal casting to optional" {
1195 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1196 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1197
1198 var bar: ?Bar = undefined;
1199 bar = .B;
1200
1201 try expect(bar.? == Bar.B);
1202}
1203
1204const A = enum(u3) { One, Two, Three, Four, One2, Two2, Three2, Four2 };
1205const B = enum(u3) { One3, Two3, Three3, Four3, One23, Two23, Three23, Four23 };
1206const C = enum(u2) { One4, Two4, Three4, Four4 };
1207
1208const BitFieldOfEnums = packed struct {
1209 a: A,
1210 b: B,
1211 c: C,
1212};
1213
1214const bit_field_1 = BitFieldOfEnums{
1215 .a = A.Two,
1216 .b = B.Three3,
1217 .c = C.Four4,
1218};
1219
1220test "bit field access with enum fields" {
1221 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1222 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1223 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1224 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
1225
1226 var data = bit_field_1;
1227 try expect(getA(&data) == A.Two);
1228 try expect(getB(&data) == B.Three3);
1229 try expect(getC(&data) == C.Four4);
1230 comptime assert(@sizeOf(BitFieldOfEnums) == 1);
1231
1232 data.b = B.Four3;
1233 try expect(data.b == B.Four3);
1234
1235 data.a = A.Three;
1236 try expect(data.a == A.Three);
1237 try expect(data.b == B.Four3);
1238}
1239
1240fn getA(data: *const BitFieldOfEnums) A {
1241 return data.a;
1242}
1243
1244fn getB(data: *const BitFieldOfEnums) B {
1245 return data.b;
1246}
1247
1248fn getC(data: *const BitFieldOfEnums) C {
1249 return data.c;
1250}
1251
1252test "enum literal in array literal" {
1253 const Items = enum { one, two };
1254 const array = [_]Items{ .one, .two };
1255
1256 try expect(array[0] == .one);
1257 try expect(array[1] == .two);
1258}
1259
1260test "tag name functions are unique" {
1261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1262 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1263 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1264 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1265 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1266
1267 {
1268 const E = enum { a, b };
1269 var b = E.a;
1270 var a = @tagName(b);
1271 _ = .{ &a, &b };
1272 }
1273 {
1274 const E = enum { a, b, c, d, e, f };
1275 var b = E.a;
1276 var a = @tagName(b);
1277 _ = .{ &a, &b };
1278 }
1279}
1280
1281test "size of enum with only one tag which has explicit integer tag type" {
1282 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1283 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1284
1285 const E = enum(u8) { nope = 10 };
1286 const S0 = struct { e: E };
1287 const S1 = extern struct { e: E };
1288 //const U = union(E) { nope: void };
1289 comptime assert(@sizeOf(E) == 1);
1290 comptime assert(@sizeOf(S0) == 1);
1291 comptime assert(@sizeOf(S1) == 1);
1292 //comptime assert(@sizeOf(U) == 1);
1293
1294 var s1: S1 = undefined;
1295 s1.e = .nope;
1296 try expect(s1.e == .nope);
1297 const ptr = @as(*u8, @ptrCast(&s1));
1298 try expect(ptr.* == 10);
1299
1300 var s0: S0 = undefined;
1301 s0.e = .nope;
1302 try expect(s0.e == .nope);
1303}
1304
1305test "switch on an extern enum with negative value" {
1306 const Foo = enum(c_int) {
1307 Bar = -1,
1308 };
1309
1310 const v = Foo.Bar;
1311
1312 switch (v) {
1313 Foo.Bar => return,
1314 }
1315}
1316
1317test "switch on an enum with small signed tag type" {
1318 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1319
1320 const E = enum(i3) {
1321 y = -2,
1322 z = -1,
1323 a = 0,
1324 b = 1,
1325 c = 2,
1326 };
1327
1328 var runtime: E = .c;
1329 _ = &runtime;
1330 const result: u8 = switch (runtime) {
1331 .y, .z, .a, .b => 0,
1332 .c => 1,
1333 };
1334 try expect(result == 1);
1335}
1336
1337test "Non-exhaustive enum with nonstandard int size behaves correctly" {
1338 const E = enum(u15) { _ };
1339 try expect(@sizeOf(E) == @sizeOf(u15));
1340}
1341
1342test "runtime int to enum with one possible value" {
1343 const E = enum { one };
1344 var runtime: usize = 0;
1345 _ = &runtime;
1346 if (@as(E, @fromBackingInt(@intCast(runtime))) != .one) {
1347 @compileError("test failed");
1348 }
1349}
1350
1351test "enum tag from a local variable" {
1352 const S = struct {
1353 fn Int(comptime Inner: type) type {
1354 return enum(Inner) { _ };
1355 }
1356 };
1357 const i = @as(S.Int(u32), @fromBackingInt(@intCast(0)));
1358 try std.testing.expect(@backingInt(i) == 0);
1359}
1360
1361test "auto-numbered enum with signed tag type" {
1362 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1363
1364 const E = enum(i32) { a, b };
1365
1366 try std.testing.expectEqual(@as(i32, 0), @backingInt(E.a));
1367 try std.testing.expectEqual(@as(i32, 1), @backingInt(E.b));
1368 try std.testing.expectEqual(E.a, @as(E, @fromBackingInt(@intCast(0))));
1369 try std.testing.expectEqual(E.b, @as(E, @fromBackingInt(@intCast(1))));
1370 try std.testing.expectEqual(E.a, @as(E, @fromBackingInt(@intCast(@as(i32, 0)))));
1371 try std.testing.expectEqual(E.b, @as(E, @fromBackingInt(@intCast(@as(i32, 1)))));
1372 try std.testing.expectEqual(E.a, @as(E, @fromBackingInt(@intCast(@as(u32, 0)))));
1373 try std.testing.expectEqual(E.b, @as(E, @fromBackingInt(@intCast(@as(u32, 1)))));
1374 try std.testing.expectEqualStrings("a", @tagName(E.a));
1375 try std.testing.expectEqualStrings("b", @tagName(E.b));
1376}
1377
1378test "lazy initialized field" {
1379 try std.testing.expectEqual(@as(u8, @alignOf(struct {})), getLazyInitialized(.a));
1380}
1381
1382fn getLazyInitialized(param: enum(u8) {
1383 a = @bitCast(packed struct(u8) { a: u8 }{ .a = @alignOf(struct {}) }),
1384}) u8 {
1385 return @backingInt(param);
1386}
1387
1388test "matching captures causes enum equivalence" {
1389 const S = struct {
1390 fn Nonexhaustive(comptime I: type) type {
1391 const UTag = @Int(.unsigned, @typeInfo(I).int.bits);
1392 return enum(UTag) { _ };
1393 }
1394 };
1395
1396 comptime assert(S.Nonexhaustive(u8) == S.Nonexhaustive(i8));
1397 comptime assert(S.Nonexhaustive(u16) == S.Nonexhaustive(i16));
1398 comptime assert(S.Nonexhaustive(u8) != S.Nonexhaustive(u16));
1399
1400 const a: S.Nonexhaustive(u8) = @fromBackingInt(@intCast(123));
1401 const b: S.Nonexhaustive(i8) = @fromBackingInt(@intCast(123));
1402 comptime assert(@TypeOf(a) == @TypeOf(b));
1403 try expect(@backingInt(a) == @backingInt(b));
1404}
1405
1406test "large enum field values" {
1407 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1408
1409 {
1410 const E = enum(u64) { min = std.math.minInt(u64), max = std.math.maxInt(u64) };
1411 var e: E = .min;
1412 try expect(e == .min);
1413 try expect(@backingInt(e) == std.math.minInt(u64));
1414 e = .max;
1415 try expect(e == .max);
1416 try expect(@backingInt(e) == std.math.maxInt(u64));
1417 }
1418 {
1419 const E = enum(i64) { min = std.math.minInt(i64), max = std.math.maxInt(i64) };
1420 var e: E = .min;
1421 try expect(e == .min);
1422 try expect(@backingInt(e) == std.math.minInt(i64));
1423 e = .max;
1424 try expect(e == .max);
1425 try expect(@backingInt(e) == std.math.maxInt(i64));
1426 }
1427 {
1428 const E = enum(u128) { min = std.math.minInt(u128), max = std.math.maxInt(u128) };
1429 var e: E = .min;
1430 try expect(e == .min);
1431 try expect(@backingInt(e) == std.math.minInt(u128));
1432 e = .max;
1433 try expect(e == .max);
1434 try expect(@backingInt(e) == std.math.maxInt(u128));
1435 }
1436 {
1437 const E = enum(i128) { min = std.math.minInt(i128), max = std.math.maxInt(i128) };
1438 var e: E = .min;
1439 try expect(e == .min);
1440 try expect(@backingInt(e) == std.math.minInt(i128));
1441 e = .max;
1442 try expect(e == .max);
1443 try expect(@backingInt(e) == std.math.maxInt(i128));
1444 }
1445}
1446
1447test "comptime @enumFromInt with signed arithmetic" {
1448 const E = enum(i8) { foo = -1, bar = 0 };
1449 const x: E = @fromBackingInt(@intCast(@as(i8, -1) * 0));
1450 comptime assert(x == .bar);
1451 comptime assert(@backingInt(x) == 0);
1452}
1453
1454test "enum int tag type uses declaration inside the enum" {
1455 const static = struct {
1456 const E = enum(E.IntTag) {
1457 const IntTag = u8;
1458 a,
1459 b,
1460 c,
1461 };
1462 };
1463 try expect(@sizeOf(static.E) == @sizeOf(u8));
1464 const val: static.E = .b;
1465 try expect(val == .b);
1466 try expect(@backingInt(val) == 1);
1467}
1468
1469test "convert from/to backing int" {
1470 const E = enum(u33) {
1471 a,
1472 b,
1473 c,
1474 fn doTheTest(s: @This()) !void {
1475 const backing_int = @backingInt(s);
1476 const reconstructed: @This() = @fromBackingInt(backing_int);
1477 try expect(reconstructed == s);
1478 }
1479 };
1480 try E.doTheTest(.b);
1481 try comptime E.doTheTest(.b);
1482}