aboutsummaryrefslogtreecommitdiff
path: root/src/value.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/value.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/value.zig')
-rw-r--r--src/value.zig108
1 files changed, 92 insertions, 16 deletions
diff --git a/src/value.zig b/src/value.zig
index db79fa3fe6..ea45f0f906 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -602,6 +602,73 @@ pub const Value = struct {
return result;
}
+ pub fn intern(val: Value, ty: Type, mod: *Module) Allocator.Error!InternPool.Index {
+ if (val.ip_index != .none) return val.ip_index;
+ switch (val.tag()) {
+ .slice => {
+ const pl = val.castTag(.slice).?.data;
+ const ptr = try pl.ptr.intern(ty.slicePtrFieldType(mod), mod);
+ return mod.intern(.{ .ptr = .{
+ .ty = ty.ip_index,
+ .addr = mod.intern_pool.indexToKey(ptr).ptr.addr,
+ .len = try pl.len.intern(Type.usize, mod),
+ } });
+ },
+ .opt_payload => return mod.intern(.{ .opt = .{
+ .ty = ty.ip_index,
+ .val = try val.castTag(.opt_payload).?.data.intern(ty.childType(mod), mod),
+ } }),
+ .aggregate => {
+ const old_elems = val.castTag(.aggregate).?.data;
+ const new_elems = try mod.gpa.alloc(InternPool.Index, old_elems.len);
+ defer mod.gpa.free(new_elems);
+ const ty_key = mod.intern_pool.indexToKey(ty.ip_index);
+ for (new_elems, old_elems, 0..) |*new_elem, old_elem, field_i|
+ new_elem.* = try old_elem.intern(switch (ty_key) {
+ .struct_type => ty.structFieldType(field_i, mod),
+ .anon_struct_type => |info| info.types[field_i].toType(),
+ inline .array_type, .vector_type => |info| info.child.toType(),
+ else => unreachable,
+ }, mod);
+ return mod.intern(.{ .aggregate = .{
+ .ty = ty.ip_index,
+ .storage = .{ .elems = new_elems },
+ } });
+ },
+ .repeated => return mod.intern(.{ .aggregate = .{
+ .ty = ty.ip_index,
+ .storage = .{ .repeated_elem = try val.castTag(.repeated).?.data.intern(
+ ty.structFieldType(0, mod),
+ mod,
+ ) },
+ } }),
+ .@"union" => {
+ const pl = val.castTag(.@"union").?.data;
+ return mod.intern(.{ .un = .{
+ .ty = ty.ip_index,
+ .tag = try pl.tag.intern(ty.unionTagTypeHypothetical(mod), mod),
+ .val = try pl.val.intern(ty.unionFieldType(pl.tag, mod), mod),
+ } });
+ },
+ else => unreachable,
+ }
+ }
+
+ pub fn unintern(val: Value, arena: Allocator, mod: *Module) Allocator.Error!Value {
+ if (val.ip_index == .none) return val;
+ switch (mod.intern_pool.indexToKey(val.ip_index)) {
+ .aggregate => |aggregate| switch (aggregate.storage) {
+ .elems => |old_elems| {
+ const new_elems = try arena.alloc(Value, old_elems.len);
+ for (new_elems, old_elems) |*new_elem, old_elem| new_elem.* = old_elem.toValue();
+ return Tag.aggregate.create(arena, new_elems);
+ },
+ .repeated_elem => |elem| return Tag.repeated.create(arena, elem.toValue()),
+ },
+ else => return val,
+ }
+ }
+
pub fn toIntern(val: Value) InternPool.Index {
assert(val.ip_index != .none);
return val.ip_index;
@@ -2002,11 +2069,11 @@ pub const Value = struct {
const ptr_ty = ty.slicePtrFieldType(mod);
const a_ptr = switch (a_ty.ptrSize(mod)) {
- .Slice => a.slicePtr(),
+ .Slice => a.slicePtr(mod),
.One => a,
else => unreachable,
};
- return try eqlAdvanced(a_ptr, ptr_ty, b.slicePtr(), ptr_ty, mod, opt_sema);
+ return try eqlAdvanced(a_ptr, ptr_ty, b.slicePtr(mod), ptr_ty, mod, opt_sema);
},
.Many, .C, .One => {},
},
@@ -2429,7 +2496,8 @@ pub const Value = struct {
}
}
- pub fn slicePtr(val: Value) Value {
+ pub fn slicePtr(val: Value, mod: *Module) Value {
+ if (val.ip_index != .none) return mod.intern_pool.slicePtr(val.ip_index).toValue();
return switch (val.tag()) {
.slice => val.castTag(.slice).?.data.ptr,
// TODO this should require being a slice tag, and not allow decl_ref, field_ptr, etc.
@@ -2439,6 +2507,7 @@ pub const Value = struct {
}
pub fn sliceLen(val: Value, mod: *Module) u64 {
+ if (val.ip_index != .none) return mod.intern_pool.sliceLen(val.ip_index).toValue().toUnsignedInt(mod);
return switch (val.tag()) {
.slice => val.castTag(.slice).?.data.len.toUnsignedInt(mod),
.decl_ref => {
@@ -2531,7 +2600,19 @@ pub const Value = struct {
else => unreachable,
},
- else => unreachable,
+ else => return switch (mod.intern_pool.indexToKey(val.ip_index)) {
+ .ptr => |ptr| switch (ptr.addr) {
+ .@"var" => unreachable,
+ .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index),
+ .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).val.elemValue(mod, index),
+ .int => unreachable,
+ },
+ .aggregate => |aggregate| switch (aggregate.storage) {
+ .elems => |elems| elems[index].toValue(),
+ .repeated_elem => |elem| elem.toValue(),
+ },
+ else => unreachable,
+ },
}
}
@@ -2675,6 +2756,7 @@ pub const Value = struct {
}
pub fn unionTag(val: Value, mod: *Module) Value {
+ if (val.ip_index == .none) return val.castTag(.@"union").?.data.tag;
return switch (mod.intern_pool.indexToKey(val.ip_index)) {
.undef, .enum_tag => val,
.un => |un| un.tag.toValue(),
@@ -2696,7 +2778,7 @@ pub const Value = struct {
else => val,
};
- if (ptr_val.tag() == .elem_ptr) {
+ if (ptr_val.ip_index == .none and ptr_val.tag() == .elem_ptr) {
const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
if (elem_ptr.elem_ty.eql(elem_ty, mod)) {
return Tag.elem_ptr.create(arena, .{
@@ -4809,10 +4891,12 @@ pub const Value = struct {
pub const base_tag = Tag.@"union";
base: Payload = .{ .tag = base_tag },
- data: struct {
+ data: Data,
+
+ pub const Data = struct {
tag: Value,
val: Value,
- },
+ };
};
};
@@ -4844,15 +4928,7 @@ pub const Value = struct {
return if (x) one else zero;
}
- 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);
- }
- };
+ pub const RuntimeIndex = InternPool.RuntimeIndex;
/// This function is used in the debugger pretty formatters in tools/ to fetch the
/// Tag to Payload mapping to facilitate fancy debug printing for this type.