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 {...@@ -86,6 +86,8 @@ pub const Value = extern union {
86 one,86 one,
87 void_value,87 void_value,
88 unreachable_value,88 unreachable_value,
89 /// The only possible value for a particular type, which is stored externally.
90 the_only_possible_value,
89 null_value,91 null_value,
90 bool_true,92 bool_true,
91 bool_false,93 bool_false,
...@@ -226,6 +228,7 @@ pub const Value = extern union {...@@ -226,6 +228,7 @@ pub const Value = extern union {
226 .one,228 .one,
227 .void_value,229 .void_value,
228 .unreachable_value,230 .unreachable_value,
231 .the_only_possible_value,
229 .empty_struct_value,232 .empty_struct_value,
230 .empty_array,233 .empty_array,
231 .null_value,234 .null_value,
...@@ -415,6 +418,7 @@ pub const Value = extern union {...@@ -415,6 +418,7 @@ pub const Value = extern union {
415 .one,418 .one,
416 .void_value,419 .void_value,
417 .unreachable_value,420 .unreachable_value,
421 .the_only_possible_value,
418 .empty_array,422 .empty_array,
419 .null_value,423 .null_value,
420 .bool_true,424 .bool_true,
...@@ -664,6 +668,7 @@ pub const Value = extern union {...@@ -664,6 +668,7 @@ pub const Value = extern union {
664 .one => return out_stream.writeAll("1"),668 .one => return out_stream.writeAll("1"),
665 .void_value => return out_stream.writeAll("{}"),669 .void_value => return out_stream.writeAll("{}"),
666 .unreachable_value => return out_stream.writeAll("unreachable"),670 .unreachable_value => return out_stream.writeAll("unreachable"),
671 .the_only_possible_value => return out_stream.writeAll("(the only possible value)"),
667 .bool_true => return out_stream.writeAll("true"),672 .bool_true => return out_stream.writeAll("true"),
668 .bool_false => return out_stream.writeAll("false"),673 .bool_false => return out_stream.writeAll("false"),
669 .ty => return val.castTag(.ty).?.data.format("", options, out_stream),674 .ty => return val.castTag(.ty).?.data.format("", options, out_stream),
...@@ -755,6 +760,7 @@ pub const Value = extern union {...@@ -755,6 +760,7 @@ pub const Value = extern union {
755 const decl_val = try decl.value();760 const decl_val = try decl.value();
756 return decl_val.toAllocatedBytes(decl.ty, allocator);761 return decl_val.toAllocatedBytes(decl.ty, allocator);
757 },762 },
763 .the_only_possible_value => return &[_]u8{},
758 else => unreachable,764 else => unreachable,
759 }765 }
760 }766 }
...@@ -847,53 +853,63 @@ pub const Value = extern union {...@@ -847,53 +853,63 @@ pub const Value = extern union {
847 // TODO should `@intToEnum` do this `@intCast` for you?853 // TODO should `@intToEnum` do this `@intCast` for you?
848 return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index));854 return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index));
849 },855 },
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 },
850 else => unreachable,861 else => unreachable,
851 }862 }
852 }863 }
853864
854 pub fn enumToInt(val: Value, ty: Type, buffer: *Payload.U64) Value {865 pub fn enumToInt(val: Value, ty: Type, buffer: *Payload.U64) Value {
855 if (val.castTag(.enum_field_index)) |enum_field_payload| {866 const field_index = switch (val.tag()) {
856 const field_index = enum_field_payload.data;867 .enum_field_index => val.castTag(.enum_field_index).?.data,
857 switch (ty.tag()) {868 .the_only_possible_value => blk: {
858 .enum_full, .enum_nonexhaustive => {869 assert(ty.enumFieldCount() == 1);
859 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;870 break :blk 0;
860 if (enum_full.values.count() != 0) {871 },
861 return enum_full.values.keys()[field_index];872 // Assume it is already an integer and return it directly.
862 } else {873 else => return val,
863 // Field index and integer values are the same.874 };
864 buffer.* = .{875
865 .base = .{ .tag = .int_u64 },876 switch (ty.tag()) {
866 .data = field_index,877 .enum_full, .enum_nonexhaustive => {
867 };878 const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
868 return Value.initPayload(&buffer.base);879 if (enum_full.values.count() != 0) {
869 }880 return enum_full.values.keys()[field_index];
870 },881 } else {
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 => {
885 // Field index and integer values are the same.882 // Field index and integer values are the same.
886 buffer.* = .{883 buffer.* = .{
887 .base = .{ .tag = .int_u64 },884 .base = .{ .tag = .int_u64 },
888 .data = field_index,885 .data = field_index,
889 };886 };
890 return Value.initPayload(&buffer.base);887 return Value.initPayload(&buffer.base);
891 },888 }
892 else => unreachable,889 },
893 }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,
894 }912 }
895 // Assume it is already an integer and return it directly.
896 return val;
897 }913 }
898914
899 /// Asserts the value is an integer.915 /// Asserts the value is an integer.
...@@ -901,6 +917,7 @@ pub const Value = extern union {...@@ -901,6 +917,7 @@ pub const Value = extern union {
901 switch (self.tag()) {917 switch (self.tag()) {
902 .zero,918 .zero,
903 .bool_false,919 .bool_false,
920 .the_only_possible_value, // i0, u0
904 => return BigIntMutable.init(&space.limbs, 0).toConst(),921 => return BigIntMutable.init(&space.limbs, 0).toConst(),
905922
906 .one,923 .one,
...@@ -922,6 +939,7 @@ pub const Value = extern union {...@@ -922,6 +939,7 @@ pub const Value = extern union {
922 switch (self.tag()) {939 switch (self.tag()) {
923 .zero,940 .zero,
924 .bool_false,941 .bool_false,
942 .the_only_possible_value, // i0, u0
925 => return 0,943 => return 0,
926944
927 .one,945 .one,
...@@ -943,6 +961,7 @@ pub const Value = extern union {...@@ -943,6 +961,7 @@ pub const Value = extern union {
943 switch (self.tag()) {961 switch (self.tag()) {
944 .zero,962 .zero,
945 .bool_false,963 .bool_false,
964 .the_only_possible_value, // i0, u0
946 => return 0,965 => return 0,
947966
948 .one,967 .one,
...@@ -1124,6 +1143,11 @@ pub const Value = extern union {...@@ -1124,6 +1143,11 @@ pub const Value = extern union {
1124 @panic("TODO implement int_big_negative Value clz");1143 @panic("TODO implement int_big_negative Value clz");
1125 },1144 },
11261145
1146 .the_only_possible_value => {
1147 assert(ty_bits == 0);
1148 return ty_bits;
1149 },
1150
1127 else => unreachable,1151 else => unreachable,
1128 }1152 }
1129 }1153 }
...@@ -1134,6 +1158,7 @@ pub const Value = extern union {...@@ -1134,6 +1158,7 @@ pub const Value = extern union {
1134 switch (self.tag()) {1158 switch (self.tag()) {
1135 .zero,1159 .zero,
1136 .bool_false,1160 .bool_false,
1161 .the_only_possible_value,
1137 => return 0,1162 => return 0,
11381163
1139 .one,1164 .one,
...@@ -1213,6 +1238,11 @@ pub const Value = extern union {...@@ -1213,6 +1238,11 @@ pub const Value = extern union {
1213 else => unreachable,1238 else => unreachable,
1214 },1239 },
12151240
1241 .the_only_possible_value => {
1242 assert(ty.intInfo(target).bits == 0);
1243 return true;
1244 },
1245
1216 else => unreachable,1246 else => unreachable,
1217 }1247 }
1218 }1248 }
...@@ -1251,7 +1281,7 @@ pub const Value = extern union {...@@ -1251,7 +1281,7 @@ pub const Value = extern union {
1251 /// Asserts the value is numeric1281 /// Asserts the value is numeric
1252 pub fn isZero(self: Value) bool {1282 pub fn isZero(self: Value) bool {
1253 return switch (self.tag()) {1283 return switch (self.tag()) {
1254 .zero => true,1284 .zero, .the_only_possible_value => true,
1255 .one => false,1285 .one => false,
12561286
1257 .int_u64 => self.castTag(.int_u64).?.data == 0,1287 .int_u64 => self.castTag(.int_u64).?.data == 0,
...@@ -1272,6 +1302,7 @@ pub const Value = extern union {...@@ -1272,6 +1302,7 @@ pub const Value = extern union {
1272 return switch (lhs.tag()) {1302 return switch (lhs.tag()) {
1273 .zero,1303 .zero,
1274 .bool_false,1304 .bool_false,
1305 .the_only_possible_value,
1275 => .eq,1306 => .eq,
12761307
1277 .one,1308 .one,
...@@ -1354,7 +1385,7 @@ pub const Value = extern union {...@@ -1354,7 +1385,7 @@ pub const Value = extern union {
1354 assert(b_tag != .undef);1385 assert(b_tag != .undef);
1355 if (a_tag == b_tag) {1386 if (a_tag == b_tag) {
1356 switch (a_tag) {1387 switch (a_tag) {
1357 .void_value, .null_value => return true,1388 .void_value, .null_value, .the_only_possible_value => return true,
1358 .enum_literal => {1389 .enum_literal => {
1359 const a_name = a.castTag(.enum_literal).?.data;1390 const a_name = a.castTag(.enum_literal).?.data;
1360 const b_name = b.castTag(.enum_literal).?.data;1391 const b_name = b.castTag(.enum_literal).?.data;
...@@ -1706,6 +1737,9 @@ pub const Value = extern union {...@@ -1706,6 +1737,9 @@ pub const Value = extern union {
1706 .decl_ref => return val.castTag(.decl_ref).?.data.val.elemValueAdvanced(index, arena, buffer),1737 .decl_ref => return val.castTag(.decl_ref).?.data.val.elemValueAdvanced(index, arena, buffer),
1707 .decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.val.elemValueAdvanced(index, arena, buffer),1738 .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
1709 else => unreachable,1743 else => unreachable,
1710 }1744 }
1711 }1745 }
...@@ -1722,6 +1756,8 @@ pub const Value = extern union {...@@ -1722,6 +1756,8 @@ pub const Value = extern union {
1722 // TODO assert the tag is correct1756 // TODO assert the tag is correct
1723 return payload.val;1757 return payload.val;
1724 },1758 },
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
1726 else => unreachable,1762 else => unreachable,
1727 }1763 }
...@@ -1820,6 +1856,7 @@ pub const Value = extern union {...@@ -1820,6 +1856,7 @@ pub const Value = extern union {
1820 pub fn intToFloat(val: Value, allocator: *Allocator, dest_ty: Type, target: Target) !Value {1856 pub fn intToFloat(val: Value, allocator: *Allocator, dest_ty: Type, target: Target) !Value {
1821 switch (val.tag()) {1857 switch (val.tag()) {
1822 .undef, .zero, .one => return val,1858 .undef, .zero, .one => return val,
1859 .the_only_possible_value => return Value.initTag(.zero), // for i0, u0
1823 .int_u64 => {1860 .int_u64 => {
1824 return intToFloatInner(val.castTag(.int_u64).?.data, allocator, dest_ty, target);1861 return intToFloatInner(val.castTag(.int_u64).?.data, allocator, dest_ty, target);
1825 },1862 },