authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-19 23:19:56+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-20 03:44:02+02:00
log7b97f6792fdc4f2774f109ec016ad19bf341e768
tree391cd7c7df31fd1acf1b2f9a6c21024b63b91c89
parentb65582e834de34f2351fa04a47f20e7f9c16a47c

stage2: add Value.the_only_possible_value


1 files changed, 74 insertions(+), 37 deletions(-)

src/value.zig+74-37
......@@ -86,6 +86,8 @@ pub const Value = extern union {
8686 one,
8787 void_value,
8888 unreachable_value,
89 /// The only possible value for a particular type, which is stored externally.
90 the_only_possible_value,
8991 null_value,
9092 bool_true,
9193 bool_false,
......@@ -226,6 +228,7 @@ pub const Value = extern union {
226228 .one,
227229 .void_value,
228230 .unreachable_value,
231 .the_only_possible_value,
229232 .empty_struct_value,
230233 .empty_array,
231234 .null_value,
......@@ -415,6 +418,7 @@ pub const Value = extern union {
415418 .one,
416419 .void_value,
417420 .unreachable_value,
421 .the_only_possible_value,
418422 .empty_array,
419423 .null_value,
420424 .bool_true,
......@@ -664,6 +668,7 @@ pub const Value = extern union {
664668 .one => return out_stream.writeAll("1"),
665669 .void_value => return out_stream.writeAll("{}"),
666670 .unreachable_value => return out_stream.writeAll("unreachable"),
671 .the_only_possible_value => return out_stream.writeAll("(the only possible value)"),
667672 .bool_true => return out_stream.writeAll("true"),
668673 .bool_false => return out_stream.writeAll("false"),
669674 .ty => return val.castTag(.ty).?.data.format("", options, out_stream),
......@@ -755,6 +760,7 @@ pub const Value = extern union {
755760 const decl_val = try decl.value();
756761 return decl_val.toAllocatedBytes(decl.ty, allocator);
757762 },
763 .the_only_possible_value => return &[_]u8{},
758764 else => unreachable,
759765 }
760766 }
......@@ -847,53 +853,63 @@ pub const Value = extern union {
847853 // TODO should `@intToEnum` do this `@intCast` for you?
848854 return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index));
849855 },
856 .the_only_possible_value => {
857 const fields = std.meta.fields(E);
858 assert(fields.len == 1);
859 return @intToEnum(E, fields[0].value);
860 },
850861 else => unreachable,
851862 }
852863 }
853864
854865 pub fn enumToInt(val: Value, ty: Type, buffer: *Payload.U64) Value {
855 if (val.castTag(.enum_field_index)) |enum_field_payload| {
856 const field_index = enum_field_payload.data;
857 switch (ty.tag()) {
858 .enum_full, .enum_nonexhaustive => {
859 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
860 if (enum_full.values.count() != 0) {
861 return enum_full.values.keys()[field_index];
862 } else {
863 // Field index and integer values are the same.
864 buffer.* = .{
865 .base = .{ .tag = .int_u64 },
866 .data = field_index,
867 };
868 return Value.initPayload(&buffer.base);
869 }
870 },
871 .enum_numbered => {
872 const enum_obj = ty.castTag(.enum_numbered).?.data;
873 if (enum_obj.values.count() != 0) {
874 return enum_obj.values.keys()[field_index];
875 } else {
876 // Field index and integer values are the same.
877 buffer.* = .{
878 .base = .{ .tag = .int_u64 },
879 .data = field_index,
880 };
881 return Value.initPayload(&buffer.base);
882 }
883 },
884 .enum_simple => {
866 const field_index = switch (val.tag()) {
867 .enum_field_index => val.castTag(.enum_field_index).?.data,
868 .the_only_possible_value => blk: {
869 assert(ty.enumFieldCount() == 1);
870 break :blk 0;
871 },
872 // Assume it is already an integer and return it directly.
873 else => return val,
874 };
875
876 switch (ty.tag()) {
877 .enum_full, .enum_nonexhaustive => {
878 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
879 if (enum_full.values.count() != 0) {
880 return enum_full.values.keys()[field_index];
881 } else {
885882 // Field index and integer values are the same.
886883 buffer.* = .{
887884 .base = .{ .tag = .int_u64 },
888885 .data = field_index,
889886 };
890887 return Value.initPayload(&buffer.base);
891 },
892 else => unreachable,
893 }
888 }
889 },
890 .enum_numbered => {
891 const enum_obj = ty.castTag(.enum_numbered).?.data;
892 if (enum_obj.values.count() != 0) {
893 return enum_obj.values.keys()[field_index];
894 } else {
895 // Field index and integer values are the same.
896 buffer.* = .{
897 .base = .{ .tag = .int_u64 },
898 .data = field_index,
899 };
900 return Value.initPayload(&buffer.base);
901 }
902 },
903 .enum_simple => {
904 // Field index and integer values are the same.
905 buffer.* = .{
906 .base = .{ .tag = .int_u64 },
907 .data = field_index,
908 };
909 return Value.initPayload(&buffer.base);
910 },
911 else => unreachable,
894912 }
895 // Assume it is already an integer and return it directly.
896 return val;
897913 }
898914
899915 /// Asserts the value is an integer.
......@@ -901,6 +917,7 @@ pub const Value = extern union {
901917 switch (self.tag()) {
902918 .zero,
903919 .bool_false,
920 .the_only_possible_value, // i0, u0
904921 => return BigIntMutable.init(&space.limbs, 0).toConst(),
905922
906923 .one,
......@@ -922,6 +939,7 @@ pub const Value = extern union {
922939 switch (self.tag()) {
923940 .zero,
924941 .bool_false,
942 .the_only_possible_value, // i0, u0
925943 => return 0,
926944
927945 .one,
......@@ -943,6 +961,7 @@ pub const Value = extern union {
943961 switch (self.tag()) {
944962 .zero,
945963 .bool_false,
964 .the_only_possible_value, // i0, u0
946965 => return 0,
947966
948967 .one,
......@@ -1124,6 +1143,11 @@ pub const Value = extern union {
11241143 @panic("TODO implement int_big_negative Value clz");
11251144 },
11261145
1146 .the_only_possible_value => {
1147 assert(ty_bits == 0);
1148 return ty_bits;
1149 },
1150
11271151 else => unreachable,
11281152 }
11291153 }
......@@ -1134,6 +1158,7 @@ pub const Value = extern union {
11341158 switch (self.tag()) {
11351159 .zero,
11361160 .bool_false,
1161 .the_only_possible_value,
11371162 => return 0,
11381163
11391164 .one,
......@@ -1213,6 +1238,11 @@ pub const Value = extern union {
12131238 else => unreachable,
12141239 },
12151240
1241 .the_only_possible_value => {
1242 assert(ty.intInfo(target).bits == 0);
1243 return true;
1244 },
1245
12161246 else => unreachable,
12171247 }
12181248 }
......@@ -1251,7 +1281,7 @@ pub const Value = extern union {
12511281 /// Asserts the value is numeric
12521282 pub fn isZero(self: Value) bool {
12531283 return switch (self.tag()) {
1254 .zero => true,
1284 .zero, .the_only_possible_value => true,
12551285 .one => false,
12561286
12571287 .int_u64 => self.castTag(.int_u64).?.data == 0,
......@@ -1272,6 +1302,7 @@ pub const Value = extern union {
12721302 return switch (lhs.tag()) {
12731303 .zero,
12741304 .bool_false,
1305 .the_only_possible_value,
12751306 => .eq,
12761307
12771308 .one,
......@@ -1354,7 +1385,7 @@ pub const Value = extern union {
13541385 assert(b_tag != .undef);
13551386 if (a_tag == b_tag) {
13561387 switch (a_tag) {
1357 .void_value, .null_value => return true,
1388 .void_value, .null_value, .the_only_possible_value => return true,
13581389 .enum_literal => {
13591390 const a_name = a.castTag(.enum_literal).?.data;
13601391 const b_name = b.castTag(.enum_literal).?.data;
......@@ -1706,6 +1737,9 @@ pub const Value = extern union {
17061737 .decl_ref => return val.castTag(.decl_ref).?.data.val.elemValueAdvanced(index, arena, buffer),
17071738 .decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.val.elemValueAdvanced(index, arena, buffer),
17081739
1740 // The child type of arrays which have only one possible value need to have only one possible value itself.
1741 .the_only_possible_value => return val,
1742
17091743 else => unreachable,
17101744 }
17111745 }
......@@ -1722,6 +1756,8 @@ pub const Value = extern union {
17221756 // TODO assert the tag is correct
17231757 return payload.val;
17241758 },
1759 // Structs which have only one possible value need to consist of members which have only one possible value.
1760 .the_only_possible_value => return val,
17251761
17261762 else => unreachable,
17271763 }
......@@ -1820,6 +1856,7 @@ pub const Value = extern union {
18201856 pub fn intToFloat(val: Value, allocator: *Allocator, dest_ty: Type, target: Target) !Value {
18211857 switch (val.tag()) {
18221858 .undef, .zero, .one => return val,
1859 .the_only_possible_value => return Value.initTag(.zero), // for i0, u0
18231860 .int_u64 => {
18241861 return intToFloatInner(val.castTag(.int_u64).?.data, allocator, dest_ty, target);
18251862 },