aboutsummaryrefslogtreecommitdiff
path: root/src/InternPool.zig
diff options
context:
space:
mode:
authorJacob Young <jacobly0@users.noreply.github.com>2023-05-20 09:35:11 -0400
committerAndrew Kelley <andrew@ziglang.org>2023-06-10 20:47:53 -0700
commit115c08956278b79c848e04c2f4eefca40e6cd8a3 (patch)
tree8dfdced9bc1ba7499f7660e986bd82d0ae772347 /src/InternPool.zig
parentbe78a12d7d5ac0a711fdf7237d7ccefba42be83c (diff)
downloadzig-115c08956278b79c848e04c2f4eefca40e6cd8a3.tar.gz
zig-115c08956278b79c848e04c2f4eefca40e6cd8a3.zip
Value: add `intern` and `unintern` to facilitate code conversion
This allows some code (like struct initializers) to use interned types while other code (such as comptime mutation) continues to use legacy types. With these changes, an `zig build-obj empty.zig` gets to a crash on missing interned error union types.
Diffstat (limited to 'src/InternPool.zig')
-rw-r--r--src/InternPool.zig222
1 files changed, 205 insertions, 17 deletions
diff --git a/src/InternPool.zig b/src/InternPool.zig
index 04ec10fe72..8b826458a8 100644
--- a/src/InternPool.zig
+++ b/src/InternPool.zig
@@ -100,6 +100,16 @@ pub const MapIndex = enum(u32) {
}
};
+pub const RuntimeIndex = enum(u32) {
+ zero = 0,
+ comptime_field_ptr = std.math.maxInt(u32),
+ _,
+
+ pub fn increment(ri: *RuntimeIndex) void {
+ ri.* = @intToEnum(RuntimeIndex, @enumToInt(ri.*) + 1);
+ }
+};
+
/// An index into `string_bytes`.
pub const NullTerminatedString = enum(u32) {
_,
@@ -478,11 +488,27 @@ pub const Key = union(enum) {
};
pub const Ptr = struct {
+ /// This is the pointer type, not the element type.
ty: Index,
+ /// The value of the address that the pointer points to.
addr: Addr,
+ /// This could be `none` if size is not a slice.
+ len: Index = .none,
pub const Addr = union(enum) {
+ @"var": struct {
+ init: Index,
+ owner_decl: Module.Decl.Index,
+ lib_name: OptionalNullTerminatedString,
+ is_const: bool,
+ is_threadlocal: bool,
+ is_weak_linkage: bool,
+ },
decl: Module.Decl.Index,
+ mut_decl: struct {
+ decl: Module.Decl.Index,
+ runtime_index: RuntimeIndex,
+ },
int: Index,
};
};
@@ -577,7 +603,9 @@ pub const Key = union(enum) {
// This is sound due to pointer provenance rules.
std.hash.autoHash(hasher, @as(@typeInfo(Key.Ptr.Addr).Union.tag_type.?, ptr.addr));
switch (ptr.addr) {
+ .@"var" => |@"var"| std.hash.autoHash(hasher, @"var".owner_decl),
.decl => |decl| std.hash.autoHash(hasher, decl),
+ .mut_decl => |mut_decl| std.hash.autoHash(hasher, mut_decl),
.int => |int| std.hash.autoHash(hasher, int),
}
},
@@ -697,7 +725,9 @@ pub const Key = union(enum) {
if (@as(AddrTag, a_info.addr) != @as(AddrTag, b_info.addr)) return false;
return switch (a_info.addr) {
+ .@"var" => |a_var| a_var.owner_decl == b_info.addr.@"var".owner_decl,
.decl => |a_decl| a_decl == b_info.addr.decl,
+ .mut_decl => |a_mut_decl| std.meta.eql(a_mut_decl, b_info.addr.mut_decl),
.int => |a_int| a_int == b_info.addr.int,
};
},
@@ -1330,6 +1360,12 @@ pub const Tag = enum(u8) {
/// A value that can be represented with only an enum tag.
/// data is SimpleValue enum value.
simple_value,
+ /// A pointer to a var.
+ /// data is extra index of PtrVal, which contains the type and address.
+ ptr_var,
+ /// A pointer to a decl that can be mutated at comptime.
+ /// data is extra index of PtrMutDecl, which contains the type and address.
+ ptr_mut_decl,
/// A pointer to a decl.
/// data is extra index of PtrDecl, which contains the type and address.
ptr_decl,
@@ -1338,6 +1374,11 @@ pub const Tag = enum(u8) {
/// Only pointer types are allowed to have this encoding. Optional types must use
/// `opt_payload` or `opt_null`.
ptr_int,
+ /// A slice.
+ /// data is extra index of PtrSlice, which contains the ptr and len values
+ /// In order to use this encoding, one must ensure that the `InternPool`
+ /// already contains the slice type corresponding to this payload.
+ ptr_slice,
/// An optional value that is non-null.
/// data is Index of the payload value.
/// In order to use this encoding, one must ensure that the `InternPool`
@@ -1672,16 +1713,45 @@ pub const PackedU64 = packed struct(u64) {
}
};
+pub const PtrVar = struct {
+ ty: Index,
+ /// If flags.is_extern == true this is `none`.
+ init: Index,
+ owner_decl: Module.Decl.Index,
+ /// Library name if specified.
+ /// For example `extern "c" var stderrp = ...` would have 'c' as library name.
+ lib_name: OptionalNullTerminatedString,
+ flags: Flags,
+
+ pub const Flags = packed struct(u32) {
+ is_const: bool,
+ is_threadlocal: bool,
+ is_weak_linkage: bool,
+ unused: u29 = undefined,
+ };
+};
+
pub const PtrDecl = struct {
ty: Index,
decl: Module.Decl.Index,
};
+pub const PtrMutDecl = struct {
+ ty: Index,
+ decl: Module.Decl.Index,
+ runtime_index: RuntimeIndex,
+};
+
pub const PtrInt = struct {
ty: Index,
addr: Index,
};
+pub const PtrSlice = struct {
+ ptr: Index,
+ len: Index,
+};
+
/// Trailing: Limb for every limbs_len
pub const Int = struct {
ty: Index,
@@ -1994,6 +2064,30 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
.val = payload_val,
} };
},
+ .ptr_var => {
+ const info = ip.extraData(PtrVar, data);
+ return .{ .ptr = .{
+ .ty = info.ty,
+ .addr = .{ .@"var" = .{
+ .init = info.init,
+ .owner_decl = info.owner_decl,
+ .lib_name = info.lib_name,
+ .is_const = info.flags.is_const,
+ .is_threadlocal = info.flags.is_threadlocal,
+ .is_weak_linkage = info.flags.is_weak_linkage,
+ } },
+ } };
+ },
+ .ptr_mut_decl => {
+ const info = ip.extraData(PtrMutDecl, data);
+ return .{ .ptr = .{
+ .ty = info.ty,
+ .addr = .{ .mut_decl = .{
+ .decl = info.decl,
+ .runtime_index = info.runtime_index,
+ } },
+ } };
+ },
.ptr_decl => {
const info = ip.extraData(PtrDecl, data);
return .{ .ptr = .{
@@ -2008,6 +2102,18 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
.addr = .{ .int = info.addr },
} };
},
+ .ptr_slice => {
+ const info = ip.extraData(PtrSlice, data);
+ const ptr = ip.indexToKey(info.ptr).ptr;
+ var ptr_ty = ip.indexToKey(ptr.ty);
+ assert(ptr_ty.ptr_type.size == .Many);
+ ptr_ty.ptr_type.size = .Slice;
+ return .{ .ptr = .{
+ .ty = ip.getAssumeExists(ptr_ty),
+ .addr = ptr.addr,
+ .len = info.len,
+ } };
+ },
.int_u8 => .{ .int = .{
.ty = .u8_type,
.storage = .{ .u64 = data },
@@ -2472,31 +2578,67 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.extern_func => @panic("TODO"),
- .ptr => |ptr| switch (ptr.addr) {
- .decl => |decl| {
- assert(ptr.ty != .none);
- ip.items.appendAssumeCapacity(.{
- .tag = .ptr_decl,
- .data = try ip.addExtra(gpa, PtrDecl{
- .ty = ptr.ty,
- .decl = decl,
+ .ptr => |ptr| switch (ip.items.items(.tag)[@enumToInt(ptr.ty)]) {
+ .type_pointer => {
+ assert(ptr.len == .none);
+ switch (ptr.addr) {
+ .@"var" => |@"var"| ip.items.appendAssumeCapacity(.{
+ .tag = .ptr_var,
+ .data = try ip.addExtra(gpa, PtrVar{
+ .ty = ptr.ty,
+ .init = @"var".init,
+ .owner_decl = @"var".owner_decl,
+ .lib_name = @"var".lib_name,
+ .flags = .{
+ .is_const = @"var".is_const,
+ .is_threadlocal = @"var".is_threadlocal,
+ .is_weak_linkage = @"var".is_weak_linkage,
+ },
+ }),
}),
- });
+ .decl => |decl| ip.items.appendAssumeCapacity(.{
+ .tag = .ptr_decl,
+ .data = try ip.addExtra(gpa, PtrDecl{
+ .ty = ptr.ty,
+ .decl = decl,
+ }),
+ }),
+ .mut_decl => |mut_decl| ip.items.appendAssumeCapacity(.{
+ .tag = .ptr_mut_decl,
+ .data = try ip.addExtra(gpa, PtrMutDecl{
+ .ty = ptr.ty,
+ .decl = mut_decl.decl,
+ .runtime_index = mut_decl.runtime_index,
+ }),
+ }),
+ .int => |int| ip.items.appendAssumeCapacity(.{
+ .tag = .ptr_int,
+ .data = try ip.addExtra(gpa, PtrInt{
+ .ty = ptr.ty,
+ .addr = int,
+ }),
+ }),
+ }
},
- .int => |int| {
- assert(ptr.ty != .none);
+ .type_slice => {
+ assert(ptr.len != .none);
+ var new_key = key;
+ new_key.ptr.ty = @intToEnum(Index, ip.items.items(.data)[@enumToInt(ptr.ty)]);
+ new_key.ptr.len = .none;
+ const ptr_index = try get(ip, gpa, new_key);
+ try ip.items.ensureUnusedCapacity(gpa, 1);
ip.items.appendAssumeCapacity(.{
- .tag = .ptr_int,
- .data = try ip.addExtra(gpa, PtrInt{
- .ty = ptr.ty,
- .addr = int,
+ .tag = .ptr_slice,
+ .data = try ip.addExtra(gpa, PtrSlice{
+ .ptr = ptr_index,
+ .len = ptr.len,
}),
});
},
+ else => unreachable,
},
.opt => |opt| {
- assert(opt.ty != .none);
assert(ip.isOptionalType(opt.ty));
ip.items.appendAssumeCapacity(if (opt.val == .none) .{
.tag = .opt_null,
@@ -3087,11 +3229,15 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
Module.Namespace.OptionalIndex => @enumToInt(@field(extra, field.name)),
MapIndex => @enumToInt(@field(extra, field.name)),
OptionalMapIndex => @enumToInt(@field(extra, field.name)),
+ RuntimeIndex => @enumToInt(@field(extra, field.name)),
+ NullTerminatedString => @enumToInt(@field(extra, field.name)),
+ OptionalNullTerminatedString => @enumToInt(@field(extra, field.name)),
i32 => @bitCast(u32, @field(extra, field.name)),
Pointer.Flags => @bitCast(u32, @field(extra, field.name)),
TypeFunction.Flags => @bitCast(u32, @field(extra, field.name)),
Pointer.PackedOffset => @bitCast(u32, @field(extra, field.name)),
Pointer.VectorIndex => @enumToInt(@field(extra, field.name)),
+ PtrVar.Flags => @bitCast(u32, @field(extra, field.name)),
else => @compileError("bad field type: " ++ @typeName(field.type)),
});
}
@@ -3149,11 +3295,15 @@ fn extraDataTrail(ip: InternPool, comptime T: type, index: usize) struct { data:
Module.Namespace.OptionalIndex => @intToEnum(Module.Namespace.OptionalIndex, int32),
MapIndex => @intToEnum(MapIndex, int32),
OptionalMapIndex => @intToEnum(OptionalMapIndex, int32),
+ RuntimeIndex => @intToEnum(RuntimeIndex, int32),
+ NullTerminatedString => @intToEnum(NullTerminatedString, int32),
+ OptionalNullTerminatedString => @intToEnum(OptionalNullTerminatedString, int32),
i32 => @bitCast(i32, int32),
Pointer.Flags => @bitCast(Pointer.Flags, int32),
TypeFunction.Flags => @bitCast(TypeFunction.Flags, int32),
Pointer.PackedOffset => @bitCast(Pointer.PackedOffset, int32),
Pointer.VectorIndex => @intToEnum(Pointer.VectorIndex, int32),
+ PtrVar.Flags => @bitCast(PtrVar.Flags, int32),
else => @compileError("bad field type: " ++ @typeName(field.type)),
};
}
@@ -3274,7 +3424,7 @@ pub fn childType(ip: InternPool, i: Index) Index {
};
}
-/// Given a slice type, returns the type of the pointer field.
+/// Given a slice type, returns the type of the ptr field.
pub fn slicePtrType(ip: InternPool, i: Index) Index {
switch (i) {
.const_slice_u8_type => return .manyptr_const_u8_type,
@@ -3288,10 +3438,29 @@ pub fn slicePtrType(ip: InternPool, i: Index) Index {
}
}
+/// Given a slice value, returns the value of the ptr field.
+pub fn slicePtr(ip: InternPool, i: Index) Index {
+ const item = ip.items.get(@enumToInt(i));
+ switch (item.tag) {
+ .ptr_slice => return ip.extraData(PtrSlice, item.data).ptr,
+ else => unreachable, // not a slice value
+ }
+}
+
+/// Given a slice value, returns the value of the len field.
+pub fn sliceLen(ip: InternPool, i: Index) Index {
+ const item = ip.items.get(@enumToInt(i));
+ switch (item.tag) {
+ .ptr_slice => return ip.extraData(PtrSlice, item.data).len,
+ else => unreachable, // not a slice value
+ }
+}
+
/// Given an existing value, returns the same value but with the supplied type.
/// Only some combinations are allowed:
/// * int <=> int
/// * int <=> enum
+/// * ptr <=> ptr
pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
switch (ip.indexToKey(val)) {
.int => |int| switch (ip.indexToKey(new_ty)) {
@@ -3305,6 +3474,13 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
// Assume new_ty is an integer type.
return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty);
},
+ .ptr => |ptr| switch (ip.indexToKey(new_ty)) {
+ .ptr_type => return ip.get(gpa, .{ .ptr = .{
+ .ty = new_ty,
+ .addr = ptr.addr,
+ } }),
+ else => unreachable,
+ },
else => unreachable,
}
}
@@ -3380,6 +3556,15 @@ pub fn indexToInferredErrorSetType(ip: InternPool, val: Index) Module.Fn.Inferre
return @intToEnum(Module.Fn.InferredErrorSet.Index, datas[@enumToInt(val)]).toOptional();
}
+pub fn isPointerType(ip: InternPool, ty: Index) bool {
+ const tags = ip.items.items(.tag);
+ if (ty == .none) return false;
+ return switch (tags[@enumToInt(ty)]) {
+ .type_pointer, .type_slice => true,
+ else => false,
+ };
+}
+
pub fn isOptionalType(ip: InternPool, ty: Index) bool {
const tags = ip.items.items(.tag);
if (ty == .none) return false;
@@ -3485,8 +3670,11 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
.undef => 0,
.simple_type => 0,
.simple_value => 0,
+ .ptr_var => @sizeOf(PtrVar),
.ptr_decl => @sizeOf(PtrDecl),
+ .ptr_mut_decl => @sizeOf(PtrMutDecl),
.ptr_int => @sizeOf(PtrInt),
+ .ptr_slice => @sizeOf(PtrSlice),
.opt_null => 0,
.opt_payload => 0,
.int_u8 => 0,