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) {
5555 lib_name: u32,
5656 },
5757 int: Key.Int,
58 ptr: Key.Ptr,
58 ptr: Ptr,
59 opt: Opt,
5960 enum_tag: struct {
6061 ty: Index,
6162 tag: BigIntConst,
......@@ -151,6 +152,13 @@ pub const Key = union(enum) {
151152 };
152153 };
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
154162 pub fn hash32(key: Key) u32 {
155163 return @truncate(u32, key.hash64());
156164 }
......@@ -175,6 +183,7 @@ pub const Key = union(enum) {
175183 .simple_type,
176184 .simple_value,
177185 .extern_func,
186 .opt,
178187 => |info| std.hash.autoHash(hasher, info),
179188
180189 .int => |int| {
......@@ -257,6 +266,10 @@ pub const Key = union(enum) {
257266 const b_info = b.extern_func;
258267 return std.meta.eql(a_info, b_info);
259268 },
269 .opt => |a_info| {
270 const b_info = b.opt;
271 return std.meta.eql(a_info, b_info);
272 },
260273
261274 .ptr => |a_info| {
262275 const b_info = b.ptr;
......@@ -343,6 +356,7 @@ pub const Key = union(enum) {
343356
344357 inline .ptr,
345358 .int,
359 .opt,
346360 .extern_func,
347361 .enum_tag,
348362 => |x| return x.ty,
......@@ -771,7 +785,15 @@ pub const Tag = enum(u8) {
771785 simple_internal,
772786 /// A pointer to an integer value.
773787 /// 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`.
774790 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,
775797 /// Type: u8
776798 /// data is integer value
777799 int_u8,
......@@ -1129,6 +1151,14 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
11291151 .fields_len = 0,
11301152 } },
11311153 },
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 } },
11321162 .ptr_int => {
11331163 const info = ip.extraData(PtrInt, data);
11341164 return .{ .ptr = .{
......@@ -1321,6 +1351,17 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
13211351 },
13221352 },
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
13241365 .int => |int| b: {
13251366 switch (int.ty) {
13261367 .none => unreachable,
......@@ -1342,62 +1383,51 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
13421383 },
13431384 .u16_type => switch (int.storage) {
13441385 .big_int => |big_int| {
1345 if (big_int.to(u32)) |casted| {
1346 ip.items.appendAssumeCapacity(.{
1347 .tag = .int_u16,
1348 .data = casted,
1349 });
1350 break :b;
1351 } else |_| {}
1386 ip.items.appendAssumeCapacity(.{
1387 .tag = .int_u16,
1388 .data = big_int.to(u16) catch unreachable,
1389 });
1390 break :b;
13521391 },
13531392 inline .u64, .i64 => |x| {
1354 if (std.math.cast(u32, x)) |casted| {
1355 ip.items.appendAssumeCapacity(.{
1356 .tag = .int_u16,
1357 .data = casted,
1358 });
1359 break :b;
1360 }
1393 ip.items.appendAssumeCapacity(.{
1394 .tag = .int_u16,
1395 .data = @intCast(u16, x),
1396 });
1397 break :b;
13611398 },
13621399 },
13631400 .u32_type => switch (int.storage) {
13641401 .big_int => |big_int| {
1365 if (big_int.to(u32)) |casted| {
1366 ip.items.appendAssumeCapacity(.{
1367 .tag = .int_u32,
1368 .data = casted,
1369 });
1370 break :b;
1371 } else |_| {}
1402 ip.items.appendAssumeCapacity(.{
1403 .tag = .int_u32,
1404 .data = big_int.to(u32) catch unreachable,
1405 });
1406 break :b;
13721407 },
13731408 inline .u64, .i64 => |x| {
1374 if (std.math.cast(u32, x)) |casted| {
1375 ip.items.appendAssumeCapacity(.{
1376 .tag = .int_u32,
1377 .data = casted,
1378 });
1379 break :b;
1380 }
1409 ip.items.appendAssumeCapacity(.{
1410 .tag = .int_u32,
1411 .data = @intCast(u32, x),
1412 });
1413 break :b;
13811414 },
13821415 },
13831416 .i32_type => switch (int.storage) {
13841417 .big_int => |big_int| {
1385 if (big_int.to(i32)) |casted| {
1386 ip.items.appendAssumeCapacity(.{
1387 .tag = .int_i32,
1388 .data = @bitCast(u32, casted),
1389 });
1390 break :b;
1391 } else |_| {}
1418 const casted = big_int.to(i32) catch unreachable;
1419 ip.items.appendAssumeCapacity(.{
1420 .tag = .int_i32,
1421 .data = @bitCast(u32, casted),
1422 });
1423 break :b;
13921424 },
13931425 inline .u64, .i64 => |x| {
1394 if (std.math.cast(i32, x)) |casted| {
1395 ip.items.appendAssumeCapacity(.{
1396 .tag = .int_i32,
1397 .data = @bitCast(u32, casted),
1398 });
1399 break :b;
1400 }
1426 ip.items.appendAssumeCapacity(.{
1427 .tag = .int_i32,
1428 .data = @bitCast(u32, @intCast(i32, x)),
1429 });
1430 break :b;
14011431 },
14021432 },
14031433 .usize_type => switch (int.storage) {
......@@ -1798,6 +1828,8 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
17981828 .simple_value => 0,
17991829 .simple_internal => 0,
18001830 .ptr_int => @sizeOf(PtrInt),
1831 .opt_null => 0,
1832 .opt_payload => 0,
18011833 .int_u8 => 0,
18021834 .int_u16 => 0,
18031835 .int_u32 => 0,
src/Module.zig+21-1
......@@ -6887,12 +6887,32 @@ pub fn singleConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type {
68876887 return ptrType(mod, .{ .elem_type = child_type.ip_index, .is_const = true });
68886888}
68896889
6890/// Supports optionals in addition to pointers.
68906891pub 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 {
68916911 assert(ty.zigTypeTag(mod) == .Pointer);
68926912 const i = try intern(mod, .{ .ptr = .{
68936913 .ty = ty.ip_index,
68946914 .addr = .{ .int = try intern(mod, .{ .int = .{
6895 .ty = ty.ip_index,
6915 .ty = .usize_type,
68966916 .storage = .{ .u64 = x },
68976917 } }) },
68986918 } });
src/Sema.zig+3
......@@ -31684,6 +31684,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3168431684 .extern_func => unreachable,
3168531685 .int => unreachable,
3168631686 .ptr => unreachable,
31687 .opt => unreachable,
3168731688 .enum_tag => unreachable,
3168831689 },
3168931690 };
......@@ -33207,6 +33208,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3320733208 .extern_func => unreachable,
3320833209 .int => unreachable,
3320933210 .ptr => unreachable,
33211 .opt => unreachable,
3321033212 .enum_tag => unreachable,
3321133213 },
3321233214 }
......@@ -33776,6 +33778,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3377633778 .extern_func => unreachable,
3377733779 .int => unreachable,
3377833780 .ptr => unreachable,
33781 .opt => unreachable,
3377933782 .enum_tag => unreachable,
3378033783 },
3378133784 };
src/type.zig+15-1
......@@ -146,6 +146,7 @@ pub const Type = struct {
146146 .extern_func => unreachable,
147147 .int => unreachable,
148148 .ptr => unreachable,
149 .opt => unreachable,
149150 .enum_tag => unreachable,
150151 .simple_value => unreachable,
151152 },
......@@ -1574,10 +1575,13 @@ pub const Type = struct {
15741575 .simple_type => |s| return writer.writeAll(@tagName(s)),
15751576 .struct_type => @panic("TODO"),
15761577 .union_type => @panic("TODO"),
1578
1579 // values, not types
15771580 .simple_value => unreachable,
15781581 .extern_func => unreachable,
15791582 .int => unreachable,
15801583 .ptr => unreachable,
1584 .opt => unreachable,
15811585 .enum_tag => unreachable,
15821586 },
15831587 }
......@@ -1850,6 +1854,7 @@ pub const Type = struct {
18501854 .extern_func => unreachable,
18511855 .int => unreachable,
18521856 .ptr => unreachable,
1857 .opt => unreachable,
18531858 .enum_tag => unreachable,
18541859 },
18551860 }
......@@ -1961,6 +1966,7 @@ pub const Type = struct {
19611966 .extern_func => unreachable,
19621967 .int => unreachable,
19631968 .ptr => unreachable,
1969 .opt => unreachable,
19641970 .enum_tag => unreachable,
19651971 },
19661972 };
......@@ -2362,6 +2368,7 @@ pub const Type = struct {
23622368 .extern_func => unreachable,
23632369 .int => unreachable,
23642370 .ptr => unreachable,
2371 .opt => unreachable,
23652372 .enum_tag => unreachable,
23662373 },
23672374 }
......@@ -2776,6 +2783,7 @@ pub const Type = struct {
27762783 .extern_func => unreachable,
27772784 .int => unreachable,
27782785 .ptr => unreachable,
2786 .opt => unreachable,
27792787 .enum_tag => unreachable,
27802788 },
27812789 }
......@@ -2946,6 +2954,7 @@ pub const Type = struct {
29462954 .extern_func => unreachable,
29472955 .int => unreachable,
29482956 .ptr => unreachable,
2957 .opt => unreachable,
29492958 .enum_tag => unreachable,
29502959 };
29512960
......@@ -3803,6 +3812,7 @@ pub const Type = struct {
38033812 .extern_func => unreachable,
38043813 .int => unreachable,
38053814 .ptr => unreachable,
3815 .opt => unreachable,
38063816 .enum_tag => unreachable,
38073817 },
38083818 };
......@@ -4178,6 +4188,7 @@ pub const Type = struct {
41784188 .extern_func => unreachable,
41794189 .int => unreachable,
41804190 .ptr => unreachable,
4191 .opt => unreachable,
41814192 .enum_tag => unreachable,
41824193 },
41834194 };
......@@ -4339,11 +4350,14 @@ pub const Type = struct {
43394350 },
43404351 .struct_type => @panic("TODO"),
43414352 .union_type => @panic("TODO"),
4353
4354 // values, not types
43424355 .simple_value => unreachable,
43434356 .extern_func => unreachable,
43444357 .int => unreachable,
43454358 .ptr => unreachable,
4346 .enum_tag => unreachable, // it's a value, not a type
4359 .opt => unreachable,
4360 .enum_tag => unreachable,
43474361 },
43484362 };
43494363 }
src/value.zig+8
......@@ -2336,6 +2336,14 @@ pub const Value = struct {
23362336 // The value is runtime-known and shouldn't affect the hash.
23372337 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
23392347 switch (ty.zigTypeTag(mod)) {
23402348 .Opaque => unreachable, // Cannot hash opaque types
23412349 .Void,