authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-08 13:00:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:42:30-07:00
loge94a81c951905a6b5bcf2a6028589ac1e33d1edd
treecc31783591b1b07257831563f46dfb83802b8489
parent68b95a39b1fe734b938ec02fa2b16bbb63170f87

InternPool: add optional values


5 files changed, 122 insertions(+), 45 deletions(-)

src/InternPool.zig+75-43
...@@ -55,7 +55,8 @@ pub const Key = union(enum) {...@@ -55,7 +55,8 @@ pub const Key = union(enum) {
55 lib_name: u32,55 lib_name: u32,
56 },56 },
57 int: Key.Int,57 int: Key.Int,
58 ptr: Key.Ptr,58 ptr: Ptr,
59 opt: Opt,
59 enum_tag: struct {60 enum_tag: struct {
60 ty: Index,61 ty: Index,
61 tag: BigIntConst,62 tag: BigIntConst,
...@@ -151,6 +152,13 @@ pub const Key = union(enum) {...@@ -151,6 +152,13 @@ pub const Key = union(enum) {
151 };152 };
152 };153 };
153154
155 /// `null` is represented by the `val` field being `none`.
156 pub const Opt = struct {
157 ty: Index,
158 /// This could be `none`, indicating the optional is `null`.
159 val: Index,
160 };
161
154 pub fn hash32(key: Key) u32 {162 pub fn hash32(key: Key) u32 {
155 return @truncate(u32, key.hash64());163 return @truncate(u32, key.hash64());
156 }164 }
...@@ -175,6 +183,7 @@ pub const Key = union(enum) {...@@ -175,6 +183,7 @@ pub const Key = union(enum) {
175 .simple_type,183 .simple_type,
176 .simple_value,184 .simple_value,
177 .extern_func,185 .extern_func,
186 .opt,
178 => |info| std.hash.autoHash(hasher, info),187 => |info| std.hash.autoHash(hasher, info),
179188
180 .int => |int| {189 .int => |int| {
...@@ -257,6 +266,10 @@ pub const Key = union(enum) {...@@ -257,6 +266,10 @@ pub const Key = union(enum) {
257 const b_info = b.extern_func;266 const b_info = b.extern_func;
258 return std.meta.eql(a_info, b_info);267 return std.meta.eql(a_info, b_info);
259 },268 },
269 .opt => |a_info| {
270 const b_info = b.opt;
271 return std.meta.eql(a_info, b_info);
272 },
260273
261 .ptr => |a_info| {274 .ptr => |a_info| {
262 const b_info = b.ptr;275 const b_info = b.ptr;
...@@ -343,6 +356,7 @@ pub const Key = union(enum) {...@@ -343,6 +356,7 @@ pub const Key = union(enum) {
343356
344 inline .ptr,357 inline .ptr,
345 .int,358 .int,
359 .opt,
346 .extern_func,360 .extern_func,
347 .enum_tag,361 .enum_tag,
348 => |x| return x.ty,362 => |x| return x.ty,
...@@ -771,7 +785,15 @@ pub const Tag = enum(u8) {...@@ -771,7 +785,15 @@ pub const Tag = enum(u8) {
771 simple_internal,785 simple_internal,
772 /// A pointer to an integer value.786 /// A pointer to an integer value.
773 /// data is extra index of PtrInt, which contains the type and address.787 /// data is extra index of PtrInt, which contains the type and address.
788 /// Only pointer types are allowed to have this encoding. Optional types must use
789 /// `opt_payload` or `opt_null`.
774 ptr_int,790 ptr_int,
791 /// An optional value that is non-null.
792 /// data is Index of the payload value.
793 opt_payload,
794 /// An optional value that is null.
795 /// data is Index of the payload type.
796 opt_null,
775 /// Type: u8797 /// Type: u8
776 /// data is integer value798 /// data is integer value
777 int_u8,799 int_u8,
...@@ -1129,6 +1151,14 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {...@@ -1129,6 +1151,14 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
1129 .fields_len = 0,1151 .fields_len = 0,
1130 } },1152 } },
1131 },1153 },
1154 .opt_null => .{ .opt = .{
1155 .ty = @intToEnum(Index, data),
1156 .val = .none,
1157 } },
1158 .opt_payload => .{ .opt = .{
1159 .ty = indexToKey(ip, @intToEnum(Index, data)).typeOf(),
1160 .val = @intToEnum(Index, data),
1161 } },
1132 .ptr_int => {1162 .ptr_int => {
1133 const info = ip.extraData(PtrInt, data);1163 const info = ip.extraData(PtrInt, data);
1134 return .{ .ptr = .{1164 return .{ .ptr = .{
...@@ -1321,6 +1351,17 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -1321,6 +1351,17 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
1321 },1351 },
1322 },1352 },
13231353
1354 .opt => |opt| {
1355 assert(opt.ty != .none);
1356 ip.items.appendAssumeCapacity(if (opt.val == .none) .{
1357 .tag = .opt_null,
1358 .data = @enumToInt(opt.ty),
1359 } else .{
1360 .tag = .opt_payload,
1361 .data = @enumToInt(opt.val),
1362 });
1363 },
1364
1324 .int => |int| b: {1365 .int => |int| b: {
1325 switch (int.ty) {1366 switch (int.ty) {
1326 .none => unreachable,1367 .none => unreachable,
...@@ -1342,62 +1383,51 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -1342,62 +1383,51 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
1342 },1383 },
1343 .u16_type => switch (int.storage) {1384 .u16_type => switch (int.storage) {
1344 .big_int => |big_int| {1385 .big_int => |big_int| {
1345 if (big_int.to(u32)) |casted| {1386 ip.items.appendAssumeCapacity(.{
1346 ip.items.appendAssumeCapacity(.{1387 .tag = .int_u16,
1347 .tag = .int_u16,1388 .data = big_int.to(u16) catch unreachable,
1348 .data = casted,1389 });
1349 });1390 break :b;
1350 break :b;
1351 } else |_| {}
1352 },1391 },
1353 inline .u64, .i64 => |x| {1392 inline .u64, .i64 => |x| {
1354 if (std.math.cast(u32, x)) |casted| {1393 ip.items.appendAssumeCapacity(.{
1355 ip.items.appendAssumeCapacity(.{1394 .tag = .int_u16,
1356 .tag = .int_u16,1395 .data = @intCast(u16, x),
1357 .data = casted,1396 });
1358 });1397 break :b;
1359 break :b;
1360 }
1361 },1398 },
1362 },1399 },
1363 .u32_type => switch (int.storage) {1400 .u32_type => switch (int.storage) {
1364 .big_int => |big_int| {1401 .big_int => |big_int| {
1365 if (big_int.to(u32)) |casted| {1402 ip.items.appendAssumeCapacity(.{
1366 ip.items.appendAssumeCapacity(.{1403 .tag = .int_u32,
1367 .tag = .int_u32,1404 .data = big_int.to(u32) catch unreachable,
1368 .data = casted,1405 });
1369 });1406 break :b;
1370 break :b;
1371 } else |_| {}
1372 },1407 },
1373 inline .u64, .i64 => |x| {1408 inline .u64, .i64 => |x| {
1374 if (std.math.cast(u32, x)) |casted| {1409 ip.items.appendAssumeCapacity(.{
1375 ip.items.appendAssumeCapacity(.{1410 .tag = .int_u32,
1376 .tag = .int_u32,1411 .data = @intCast(u32, x),
1377 .data = casted,1412 });
1378 });1413 break :b;
1379 break :b;
1380 }
1381 },1414 },
1382 },1415 },
1383 .i32_type => switch (int.storage) {1416 .i32_type => switch (int.storage) {
1384 .big_int => |big_int| {1417 .big_int => |big_int| {
1385 if (big_int.to(i32)) |casted| {1418 const casted = big_int.to(i32) catch unreachable;
1386 ip.items.appendAssumeCapacity(.{1419 ip.items.appendAssumeCapacity(.{
1387 .tag = .int_i32,1420 .tag = .int_i32,
1388 .data = @bitCast(u32, casted),1421 .data = @bitCast(u32, casted),
1389 });1422 });
1390 break :b;1423 break :b;
1391 } else |_| {}
1392 },1424 },
1393 inline .u64, .i64 => |x| {1425 inline .u64, .i64 => |x| {
1394 if (std.math.cast(i32, x)) |casted| {1426 ip.items.appendAssumeCapacity(.{
1395 ip.items.appendAssumeCapacity(.{1427 .tag = .int_i32,
1396 .tag = .int_i32,1428 .data = @bitCast(u32, @intCast(i32, x)),
1397 .data = @bitCast(u32, casted),1429 });
1398 });1430 break :b;
1399 break :b;
1400 }
1401 },1431 },
1402 },1432 },
1403 .usize_type => switch (int.storage) {1433 .usize_type => switch (int.storage) {
...@@ -1798,6 +1828,8 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {...@@ -1798,6 +1828,8 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
1798 .simple_value => 0,1828 .simple_value => 0,
1799 .simple_internal => 0,1829 .simple_internal => 0,
1800 .ptr_int => @sizeOf(PtrInt),1830 .ptr_int => @sizeOf(PtrInt),
1831 .opt_null => 0,
1832 .opt_payload => 0,
1801 .int_u8 => 0,1833 .int_u8 => 0,
1802 .int_u16 => 0,1834 .int_u16 => 0,
1803 .int_u32 => 0,1835 .int_u32 => 0,
src/Module.zig+21-1
...@@ -6887,12 +6887,32 @@ pub fn singleConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type {...@@ -6887,12 +6887,32 @@ pub fn singleConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type {
6887 return ptrType(mod, .{ .elem_type = child_type.ip_index, .is_const = true });6887 return ptrType(mod, .{ .elem_type = child_type.ip_index, .is_const = true });
6888}6888}
68896889
6890/// Supports optionals in addition to pointers.
6890pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {6891pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
6892 if (ty.isPtrLikeOptional(mod)) {
6893 const i = try intern(mod, .{ .opt = .{
6894 .ty = ty.ip_index,
6895 .val = try intern(mod, .{ .ptr = .{
6896 .ty = ty.childType(mod).ip_index,
6897 .addr = .{ .int = try intern(mod, .{ .int = .{
6898 .ty = .usize_type,
6899 .storage = .{ .u64 = x },
6900 } }) },
6901 } }),
6902 } });
6903 return i.toValue();
6904 } else {
6905 return ptrIntValue_ptronly(mod, ty, x);
6906 }
6907}
6908
6909/// Supports only pointers. See `ptrIntValue` for pointer-like optional support.
6910pub fn ptrIntValue_ptronly(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
6891 assert(ty.zigTypeTag(mod) == .Pointer);6911 assert(ty.zigTypeTag(mod) == .Pointer);
6892 const i = try intern(mod, .{ .ptr = .{6912 const i = try intern(mod, .{ .ptr = .{
6893 .ty = ty.ip_index,6913 .ty = ty.ip_index,
6894 .addr = .{ .int = try intern(mod, .{ .int = .{6914 .addr = .{ .int = try intern(mod, .{ .int = .{
6895 .ty = ty.ip_index,6915 .ty = .usize_type,
6896 .storage = .{ .u64 = x },6916 .storage = .{ .u64 = x },
6897 } }) },6917 } }) },
6898 } });6918 } });
src/Sema.zig+3
...@@ -31684,6 +31684,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -31684,6 +31684,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
31684 .extern_func => unreachable,31684 .extern_func => unreachable,
31685 .int => unreachable,31685 .int => unreachable,
31686 .ptr => unreachable,31686 .ptr => unreachable,
31687 .opt => unreachable,
31687 .enum_tag => unreachable,31688 .enum_tag => unreachable,
31688 },31689 },
31689 };31690 };
...@@ -33207,6 +33208,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -33207,6 +33208,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
33207 .extern_func => unreachable,33208 .extern_func => unreachable,
33208 .int => unreachable,33209 .int => unreachable,
33209 .ptr => unreachable,33210 .ptr => unreachable,
33211 .opt => unreachable,
33210 .enum_tag => unreachable,33212 .enum_tag => unreachable,
33211 },33213 },
33212 }33214 }
...@@ -33776,6 +33778,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {...@@ -33776,6 +33778,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
33776 .extern_func => unreachable,33778 .extern_func => unreachable,
33777 .int => unreachable,33779 .int => unreachable,
33778 .ptr => unreachable,33780 .ptr => unreachable,
33781 .opt => unreachable,
33779 .enum_tag => unreachable,33782 .enum_tag => unreachable,
33780 },33783 },
33781 };33784 };
src/type.zig+15-1
...@@ -146,6 +146,7 @@ pub const Type = struct {...@@ -146,6 +146,7 @@ pub const Type = struct {
146 .extern_func => unreachable,146 .extern_func => unreachable,
147 .int => unreachable,147 .int => unreachable,
148 .ptr => unreachable,148 .ptr => unreachable,
149 .opt => unreachable,
149 .enum_tag => unreachable,150 .enum_tag => unreachable,
150 .simple_value => unreachable,151 .simple_value => unreachable,
151 },152 },
...@@ -1574,10 +1575,13 @@ pub const Type = struct {...@@ -1574,10 +1575,13 @@ pub const Type = struct {
1574 .simple_type => |s| return writer.writeAll(@tagName(s)),1575 .simple_type => |s| return writer.writeAll(@tagName(s)),
1575 .struct_type => @panic("TODO"),1576 .struct_type => @panic("TODO"),
1576 .union_type => @panic("TODO"),1577 .union_type => @panic("TODO"),
1578
1579 // values, not types
1577 .simple_value => unreachable,1580 .simple_value => unreachable,
1578 .extern_func => unreachable,1581 .extern_func => unreachable,
1579 .int => unreachable,1582 .int => unreachable,
1580 .ptr => unreachable,1583 .ptr => unreachable,
1584 .opt => unreachable,
1581 .enum_tag => unreachable,1585 .enum_tag => unreachable,
1582 },1586 },
1583 }1587 }
...@@ -1850,6 +1854,7 @@ pub const Type = struct {...@@ -1850,6 +1854,7 @@ pub const Type = struct {
1850 .extern_func => unreachable,1854 .extern_func => unreachable,
1851 .int => unreachable,1855 .int => unreachable,
1852 .ptr => unreachable,1856 .ptr => unreachable,
1857 .opt => unreachable,
1853 .enum_tag => unreachable,1858 .enum_tag => unreachable,
1854 },1859 },
1855 }1860 }
...@@ -1961,6 +1966,7 @@ pub const Type = struct {...@@ -1961,6 +1966,7 @@ pub const Type = struct {
1961 .extern_func => unreachable,1966 .extern_func => unreachable,
1962 .int => unreachable,1967 .int => unreachable,
1963 .ptr => unreachable,1968 .ptr => unreachable,
1969 .opt => unreachable,
1964 .enum_tag => unreachable,1970 .enum_tag => unreachable,
1965 },1971 },
1966 };1972 };
...@@ -2362,6 +2368,7 @@ pub const Type = struct {...@@ -2362,6 +2368,7 @@ pub const Type = struct {
2362 .extern_func => unreachable,2368 .extern_func => unreachable,
2363 .int => unreachable,2369 .int => unreachable,
2364 .ptr => unreachable,2370 .ptr => unreachable,
2371 .opt => unreachable,
2365 .enum_tag => unreachable,2372 .enum_tag => unreachable,
2366 },2373 },
2367 }2374 }
...@@ -2776,6 +2783,7 @@ pub const Type = struct {...@@ -2776,6 +2783,7 @@ pub const Type = struct {
2776 .extern_func => unreachable,2783 .extern_func => unreachable,
2777 .int => unreachable,2784 .int => unreachable,
2778 .ptr => unreachable,2785 .ptr => unreachable,
2786 .opt => unreachable,
2779 .enum_tag => unreachable,2787 .enum_tag => unreachable,
2780 },2788 },
2781 }2789 }
...@@ -2946,6 +2954,7 @@ pub const Type = struct {...@@ -2946,6 +2954,7 @@ pub const Type = struct {
2946 .extern_func => unreachable,2954 .extern_func => unreachable,
2947 .int => unreachable,2955 .int => unreachable,
2948 .ptr => unreachable,2956 .ptr => unreachable,
2957 .opt => unreachable,
2949 .enum_tag => unreachable,2958 .enum_tag => unreachable,
2950 };2959 };
29512960
...@@ -3803,6 +3812,7 @@ pub const Type = struct {...@@ -3803,6 +3812,7 @@ pub const Type = struct {
3803 .extern_func => unreachable,3812 .extern_func => unreachable,
3804 .int => unreachable,3813 .int => unreachable,
3805 .ptr => unreachable,3814 .ptr => unreachable,
3815 .opt => unreachable,
3806 .enum_tag => unreachable,3816 .enum_tag => unreachable,
3807 },3817 },
3808 };3818 };
...@@ -4178,6 +4188,7 @@ pub const Type = struct {...@@ -4178,6 +4188,7 @@ pub const Type = struct {
4178 .extern_func => unreachable,4188 .extern_func => unreachable,
4179 .int => unreachable,4189 .int => unreachable,
4180 .ptr => unreachable,4190 .ptr => unreachable,
4191 .opt => unreachable,
4181 .enum_tag => unreachable,4192 .enum_tag => unreachable,
4182 },4193 },
4183 };4194 };
...@@ -4339,11 +4350,14 @@ pub const Type = struct {...@@ -4339,11 +4350,14 @@ pub const Type = struct {
4339 },4350 },
4340 .struct_type => @panic("TODO"),4351 .struct_type => @panic("TODO"),
4341 .union_type => @panic("TODO"),4352 .union_type => @panic("TODO"),
4353
4354 // values, not types
4342 .simple_value => unreachable,4355 .simple_value => unreachable,
4343 .extern_func => unreachable,4356 .extern_func => unreachable,
4344 .int => unreachable,4357 .int => unreachable,
4345 .ptr => unreachable,4358 .ptr => unreachable,
4346 .enum_tag => unreachable, // it's a value, not a type4359 .opt => unreachable,
4360 .enum_tag => unreachable,
4347 },4361 },
4348 };4362 };
4349 }4363 }
src/value.zig+8
...@@ -2336,6 +2336,14 @@ pub const Value = struct {...@@ -2336,6 +2336,14 @@ pub const Value = struct {
2336 // The value is runtime-known and shouldn't affect the hash.2336 // The value is runtime-known and shouldn't affect the hash.
2337 if (val.isRuntimeValue()) return;2337 if (val.isRuntimeValue()) return;
23382338
2339 if (val.ip_index != .none) {
2340 // The InternPool data structure hashes based on Key to make interned objects
2341 // unique. An Index can be treated simply as u32 value for the
2342 // purpose of Type/Value hashing and equality.
2343 std.hash.autoHash(hasher, val.ip_index);
2344 return;
2345 }
2346
2339 switch (ty.zigTypeTag(mod)) {2347 switch (ty.zigTypeTag(mod)) {
2340 .Opaque => unreachable, // Cannot hash opaque types2348 .Opaque => unreachable, // Cannot hash opaque types
2341 .Void,2349 .Void,