| ... | @@ -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 | } |
| 853 | | 864 | |
| 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 | } |
| 898 | | 914 | |
| 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(), |
| 905 | | 922 | |
| 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, |
| 926 | | 944 | |
| 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, |
| 947 | | 966 | |
| 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 | }, |
| 1126 | | 1145 | |
| | 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, |
| 1138 | | 1163 | |
| 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 | }, |
| 1215 | | 1240 | |
| | 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 numeric | 1281 | /// 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, |
| 1256 | | 1286 | |
| 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, |
| 1276 | | 1307 | |
| 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), |
| 1708 | | 1739 | |
| | 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 correct | 1756 | // 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, |
| 1725 | | 1761 | |
| 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 | }, |