| ... | ... | @@ -86,6 +86,8 @@ pub const Value = extern union { |
| 86 | 86 | one, |
| 87 | 87 | void_value, |
| 88 | 88 | unreachable_value, |
| 89 | /// The only possible value for a particular type, which is stored externally. |
| 90 | the_only_possible_value, |
| 89 | 91 | null_value, |
| 90 | 92 | bool_true, |
| 91 | 93 | bool_false, |
| ... | ... | @@ -226,6 +228,7 @@ pub const Value = extern union { |
| 226 | 228 | .one, |
| 227 | 229 | .void_value, |
| 228 | 230 | .unreachable_value, |
| 231 | .the_only_possible_value, |
| 229 | 232 | .empty_struct_value, |
| 230 | 233 | .empty_array, |
| 231 | 234 | .null_value, |
| ... | ... | @@ -415,6 +418,7 @@ pub const Value = extern union { |
| 415 | 418 | .one, |
| 416 | 419 | .void_value, |
| 417 | 420 | .unreachable_value, |
| 421 | .the_only_possible_value, |
| 418 | 422 | .empty_array, |
| 419 | 423 | .null_value, |
| 420 | 424 | .bool_true, |
| ... | ... | @@ -664,6 +668,7 @@ pub const Value = extern union { |
| 664 | 668 | .one => return out_stream.writeAll("1"), |
| 665 | 669 | .void_value => return out_stream.writeAll("{}"), |
| 666 | 670 | .unreachable_value => return out_stream.writeAll("unreachable"), |
| 671 | .the_only_possible_value => return out_stream.writeAll("(the only possible value)"), |
| 667 | 672 | .bool_true => return out_stream.writeAll("true"), |
| 668 | 673 | .bool_false => return out_stream.writeAll("false"), |
| 669 | 674 | .ty => return val.castTag(.ty).?.data.format("", options, out_stream), |
| ... | ... | @@ -755,6 +760,7 @@ pub const Value = extern union { |
| 755 | 760 | const decl_val = try decl.value(); |
| 756 | 761 | return decl_val.toAllocatedBytes(decl.ty, allocator); |
| 757 | 762 | }, |
| 763 | .the_only_possible_value => return &[_]u8{}, |
| 758 | 764 | else => unreachable, |
| 759 | 765 | } |
| 760 | 766 | } |
| ... | ... | @@ -847,53 +853,63 @@ pub const Value = extern union { |
| 847 | 853 | // TODO should `@intToEnum` do this `@intCast` for you? |
| 848 | 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 | 861 | else => unreachable, |
| 851 | 862 | } |
| 852 | 863 | } |
| 853 | 864 | |
| 854 | 865 | 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 { |
| 885 | 882 | // Field index and integer values are the same. |
| 886 | 883 | buffer.* = .{ |
| 887 | 884 | .base = .{ .tag = .int_u64 }, |
| 888 | 885 | .data = field_index, |
| 889 | 886 | }; |
| 890 | 887 | 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, |
| 894 | 912 | } |
| 895 | | // Assume it is already an integer and return it directly. |
| 896 | | return val; |
| 897 | 913 | } |
| 898 | 914 | |
| 899 | 915 | /// Asserts the value is an integer. |
| ... | ... | @@ -901,6 +917,7 @@ pub const Value = extern union { |
| 901 | 917 | switch (self.tag()) { |
| 902 | 918 | .zero, |
| 903 | 919 | .bool_false, |
| 920 | .the_only_possible_value, // i0, u0 |
| 904 | 921 | => return BigIntMutable.init(&space.limbs, 0).toConst(), |
| 905 | 922 | |
| 906 | 923 | .one, |
| ... | ... | @@ -922,6 +939,7 @@ pub const Value = extern union { |
| 922 | 939 | switch (self.tag()) { |
| 923 | 940 | .zero, |
| 924 | 941 | .bool_false, |
| 942 | .the_only_possible_value, // i0, u0 |
| 925 | 943 | => return 0, |
| 926 | 944 | |
| 927 | 945 | .one, |
| ... | ... | @@ -943,6 +961,7 @@ pub const Value = extern union { |
| 943 | 961 | switch (self.tag()) { |
| 944 | 962 | .zero, |
| 945 | 963 | .bool_false, |
| 964 | .the_only_possible_value, // i0, u0 |
| 946 | 965 | => return 0, |
| 947 | 966 | |
| 948 | 967 | .one, |
| ... | ... | @@ -1124,6 +1143,11 @@ pub const Value = extern union { |
| 1124 | 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 | 1151 | else => unreachable, |
| 1128 | 1152 | } |
| 1129 | 1153 | } |
| ... | ... | @@ -1134,6 +1158,7 @@ pub const Value = extern union { |
| 1134 | 1158 | switch (self.tag()) { |
| 1135 | 1159 | .zero, |
| 1136 | 1160 | .bool_false, |
| 1161 | .the_only_possible_value, |
| 1137 | 1162 | => return 0, |
| 1138 | 1163 | |
| 1139 | 1164 | .one, |
| ... | ... | @@ -1213,6 +1238,11 @@ pub const Value = extern union { |
| 1213 | 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 | 1246 | else => unreachable, |
| 1217 | 1247 | } |
| 1218 | 1248 | } |
| ... | ... | @@ -1251,7 +1281,7 @@ pub const Value = extern union { |
| 1251 | 1281 | /// Asserts the value is numeric |
| 1252 | 1282 | pub fn isZero(self: Value) bool { |
| 1253 | 1283 | return switch (self.tag()) { |
| 1254 | | .zero => true, |
| 1284 | .zero, .the_only_possible_value => true, |
| 1255 | 1285 | .one => false, |
| 1256 | 1286 | |
| 1257 | 1287 | .int_u64 => self.castTag(.int_u64).?.data == 0, |
| ... | ... | @@ -1272,6 +1302,7 @@ pub const Value = extern union { |
| 1272 | 1302 | return switch (lhs.tag()) { |
| 1273 | 1303 | .zero, |
| 1274 | 1304 | .bool_false, |
| 1305 | .the_only_possible_value, |
| 1275 | 1306 | => .eq, |
| 1276 | 1307 | |
| 1277 | 1308 | .one, |
| ... | ... | @@ -1354,7 +1385,7 @@ pub const Value = extern union { |
| 1354 | 1385 | assert(b_tag != .undef); |
| 1355 | 1386 | if (a_tag == b_tag) { |
| 1356 | 1387 | switch (a_tag) { |
| 1357 | | .void_value, .null_value => return true, |
| 1388 | .void_value, .null_value, .the_only_possible_value => return true, |
| 1358 | 1389 | .enum_literal => { |
| 1359 | 1390 | const a_name = a.castTag(.enum_literal).?.data; |
| 1360 | 1391 | const b_name = b.castTag(.enum_literal).?.data; |
| ... | ... | @@ -1706,6 +1737,9 @@ pub const Value = extern union { |
| 1706 | 1737 | .decl_ref => return val.castTag(.decl_ref).?.data.val.elemValueAdvanced(index, arena, buffer), |
| 1707 | 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 | 1743 | else => unreachable, |
| 1710 | 1744 | } |
| 1711 | 1745 | } |
| ... | ... | @@ -1722,6 +1756,8 @@ pub const Value = extern union { |
| 1722 | 1756 | // TODO assert the tag is correct |
| 1723 | 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 | 1762 | else => unreachable, |
| 1727 | 1763 | } |
| ... | ... | @@ -1820,6 +1856,7 @@ pub const Value = extern union { |
| 1820 | 1856 | pub fn intToFloat(val: Value, allocator: *Allocator, dest_ty: Type, target: Target) !Value { |
| 1821 | 1857 | switch (val.tag()) { |
| 1822 | 1858 | .undef, .zero, .one => return val, |
| 1859 | .the_only_possible_value => return Value.initTag(.zero), // for i0, u0 |
| 1823 | 1860 | .int_u64 => { |
| 1824 | 1861 | return intToFloatInner(val.castTag(.int_u64).?.data, allocator, dest_ty, target); |
| 1825 | 1862 | }, |