InternPool: use separate key for slices

This change eliminates some problematic recursive logic in InternPool,
and provides a safer API.
This commit is contained in:
mlugg
2024-02-01 16:58:52 +00:00
committed by Matthew Lugg
parent 5a3ae38f3b
commit 9eda6ccefc
11 changed files with 540 additions and 553 deletions

View File

@@ -326,6 +326,7 @@ pub const Key = union(enum) {
empty_enum_value: Index,
float: Float,
ptr: Ptr,
slice: Slice,
opt: Opt,
/// An instance of a struct, array, or vector.
/// Each element/field stored as an `Index`.
@@ -493,7 +494,7 @@ pub const Key = union(enum) {
start: u32,
len: u32,
pub fn get(slice: Slice, ip: *const InternPool) []RuntimeOrder {
pub fn get(slice: RuntimeOrder.Slice, ip: *const InternPool) []RuntimeOrder {
return @ptrCast(ip.extra.items[slice.start..][0..slice.len]);
}
};
@@ -1197,8 +1198,6 @@ pub const Key = union(enum) {
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) {
const Tag = @typeInfo(Addr).Union.tag_type.?;
@@ -1232,6 +1231,15 @@ pub const Key = union(enum) {
};
};
pub const Slice = struct {
/// This is the slice type, not the element type.
ty: Index,
/// The slice's `ptr` field. Must be a many-ptr with the same properties as `ty`.
ptr: Index,
/// The slice's `len` field. Must be a `usize`.
len: Index,
};
/// `null` is represented by the `val` field being `none`.
pub const Opt = extern struct {
/// This is the optional type; not the payload type.
@@ -1354,12 +1362,14 @@ pub const Key = union(enum) {
return hasher.final();
},
.slice => |slice| Hash.hash(seed, asBytes(&slice.ty) ++ asBytes(&slice.ptr) ++ asBytes(&slice.len)),
.ptr => |ptr| {
// Int-to-ptr pointers are hashed separately than decl-referencing pointers.
// This is sound due to pointer provenance rules.
const addr: @typeInfo(Key.Ptr.Addr).Union.tag_type.? = ptr.addr;
const seed2 = seed + @intFromEnum(addr);
const common = asBytes(&ptr.ty) ++ asBytes(&ptr.len);
const common = asBytes(&ptr.ty);
return switch (ptr.addr) {
.decl => |x| Hash.hash(seed2, common ++ asBytes(&x)),
@@ -1624,9 +1634,17 @@ pub const Key = union(enum) {
return a_ty_info.eql(b_ty_info, ip);
},
.slice => |a_info| {
const b_info = b.slice;
if (a_info.ty != b_info.ty) return false;
if (a_info.ptr != b_info.ptr) return false;
if (a_info.len != b_info.len) return false;
return true;
},
.ptr => |a_info| {
const b_info = b.ptr;
if (a_info.ty != b_info.ty or a_info.len != b_info.len) return false;
if (a_info.ty != b_info.ty) return false;
const AddrTag = @typeInfo(Key.Ptr.Addr).Union.tag_type.?;
if (@as(AddrTag, a_info.addr) != @as(AddrTag, b_info.addr)) return false;
@@ -1829,6 +1847,7 @@ pub const Key = union(enum) {
=> .type_type,
inline .ptr,
.slice,
.int,
.float,
.opt,
@@ -3983,77 +4002,11 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
},
.ptr_slice => {
const info = ip.extraData(PtrSlice, data);
const ptr_item = ip.items.get(@intFromEnum(info.ptr));
return .{
.ptr = .{
.ty = info.ty,
.addr = switch (ptr_item.tag) {
.ptr_decl => .{
.decl = ip.extraData(PtrDecl, ptr_item.data).decl,
},
.ptr_mut_decl => b: {
const sub_info = ip.extraData(PtrMutDecl, ptr_item.data);
break :b .{ .mut_decl = .{
.decl = sub_info.decl,
.runtime_index = sub_info.runtime_index,
} };
},
.ptr_anon_decl => .{
.anon_decl = .{
.val = ip.extraData(PtrAnonDecl, ptr_item.data).val,
.orig_ty = info.ty,
},
},
.ptr_anon_decl_aligned => b: {
const sub_info = ip.extraData(PtrAnonDeclAligned, ptr_item.data);
break :b .{ .anon_decl = .{
.val = sub_info.val,
.orig_ty = sub_info.orig_ty,
} };
},
.ptr_comptime_field => .{
.comptime_field = ip.extraData(PtrComptimeField, ptr_item.data).field_val,
},
.ptr_int => .{
.int = ip.extraData(PtrBase, ptr_item.data).base,
},
.ptr_eu_payload => .{
.eu_payload = ip.extraData(PtrBase, ptr_item.data).base,
},
.ptr_opt_payload => .{
.opt_payload = ip.extraData(PtrBase, ptr_item.data).base,
},
.ptr_elem => b: {
// Avoid `indexToKey` recursion by asserting the tag encoding.
const sub_info = ip.extraData(PtrBaseIndex, ptr_item.data);
const index_item = ip.items.get(@intFromEnum(sub_info.index));
break :b switch (index_item.tag) {
.int_usize => .{ .elem = .{
.base = sub_info.base,
.index = index_item.data,
} },
.int_positive => @panic("TODO"), // implement along with behavior test coverage
else => unreachable,
};
},
.ptr_field => b: {
// Avoid `indexToKey` recursion by asserting the tag encoding.
const sub_info = ip.extraData(PtrBaseIndex, ptr_item.data);
const index_item = ip.items.get(@intFromEnum(sub_info.index));
break :b switch (index_item.tag) {
.int_usize => .{ .field = .{
.base = sub_info.base,
.index = index_item.data,
} },
.int_positive => @panic("TODO"), // implement along with behavior test coverage
else => unreachable,
};
},
else => unreachable,
},
.len = info.len,
},
};
return .{ .slice = .{
.ty = info.ty,
.ptr = info.ptr,
.len = info.len,
} };
},
.int_u8 => .{ .int = .{
.ty = .u8_type,
@@ -4735,153 +4688,139 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
});
},
.slice => |slice| {
assert(ip.indexToKey(slice.ty).ptr_type.flags.size == .Slice);
assert(ip.indexToKey(ip.typeOf(slice.ptr)).ptr_type.flags.size == .Many);
ip.items.appendAssumeCapacity(.{
.tag = .ptr_slice,
.data = try ip.addExtra(gpa, PtrSlice{
.ty = slice.ty,
.ptr = slice.ptr,
.len = slice.len,
}),
});
},
.ptr => |ptr| {
const ptr_type = ip.indexToKey(ptr.ty).ptr_type;
switch (ptr.len) {
.none => {
assert(ptr_type.flags.size != .Slice);
switch (ptr.addr) {
.decl => |decl| ip.items.appendAssumeCapacity(.{
.tag = .ptr_decl,
.data = try ip.addExtra(gpa, PtrDecl{
.ty = ptr.ty,
.decl = decl,
}),
assert(ptr_type.flags.size != .Slice);
switch (ptr.addr) {
.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,
}),
}),
.anon_decl => |anon_decl| ip.items.appendAssumeCapacity(
if (ptrsHaveSameAlignment(ip, ptr.ty, ptr_type, anon_decl.orig_ty)) .{
.tag = .ptr_anon_decl,
.data = try ip.addExtra(gpa, PtrAnonDecl{
.ty = ptr.ty,
.val = anon_decl.val,
}),
.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,
}),
} else .{
.tag = .ptr_anon_decl_aligned,
.data = try ip.addExtra(gpa, PtrAnonDeclAligned{
.ty = ptr.ty,
.val = anon_decl.val,
.orig_ty = anon_decl.orig_ty,
}),
.anon_decl => |anon_decl| ip.items.appendAssumeCapacity(
if (ptrsHaveSameAlignment(ip, ptr.ty, ptr_type, anon_decl.orig_ty)) .{
.tag = .ptr_anon_decl,
.data = try ip.addExtra(gpa, PtrAnonDecl{
.ty = ptr.ty,
.val = anon_decl.val,
}),
} else .{
.tag = .ptr_anon_decl_aligned,
.data = try ip.addExtra(gpa, PtrAnonDeclAligned{
.ty = ptr.ty,
.val = anon_decl.val,
.orig_ty = anon_decl.orig_ty,
}),
},
),
.comptime_field => |field_val| {
assert(field_val != .none);
ip.items.appendAssumeCapacity(.{
.tag = .ptr_comptime_field,
.data = try ip.addExtra(gpa, PtrComptimeField{
.ty = ptr.ty,
.field_val = field_val,
}),
});
},
.int, .eu_payload, .opt_payload => |base| {
switch (ptr.addr) {
.int => assert(ip.typeOf(base) == .usize_type),
.eu_payload => assert(ip.indexToKey(
ip.indexToKey(ip.typeOf(base)).ptr_type.child,
) == .error_union_type),
.opt_payload => assert(ip.indexToKey(
ip.indexToKey(ip.typeOf(base)).ptr_type.child,
) == .opt_type),
else => unreachable,
}
ip.items.appendAssumeCapacity(.{
.tag = switch (ptr.addr) {
.int => .ptr_int,
.eu_payload => .ptr_eu_payload,
.opt_payload => .ptr_opt_payload,
else => unreachable,
},
.data = try ip.addExtra(gpa, PtrBase{
.ty = ptr.ty,
.base = base,
}),
});
},
.elem, .field => |base_index| {
const base_ptr_type = ip.indexToKey(ip.typeOf(base_index.base)).ptr_type;
switch (ptr.addr) {
.elem => assert(base_ptr_type.flags.size == .Many),
.field => {
assert(base_ptr_type.flags.size == .One);
switch (ip.indexToKey(base_ptr_type.child)) {
.anon_struct_type => |anon_struct_type| {
assert(ptr.addr == .field);
assert(base_index.index < anon_struct_type.types.len);
},
.struct_type => |struct_type| {
assert(ptr.addr == .field);
assert(base_index.index < struct_type.field_types.len);
},
.union_type => |union_key| {
const union_type = ip.loadUnionType(union_key);
assert(ptr.addr == .field);
assert(base_index.index < union_type.field_names.len);
},
.ptr_type => |slice_type| {
assert(ptr.addr == .field);
assert(slice_type.flags.size == .Slice);
assert(base_index.index < 2);
},
else => unreachable,
}
},
else => unreachable,
}
_ = ip.map.pop();
const index_index = try ip.get(gpa, .{ .int = .{
.ty = .usize_type,
.storage = .{ .u64 = base_index.index },
} });
assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing);
try ip.items.ensureUnusedCapacity(gpa, 1);
ip.items.appendAssumeCapacity(.{
.tag = switch (ptr.addr) {
.elem => .ptr_elem,
.field => .ptr_field,
else => unreachable,
},
.data = try ip.addExtra(gpa, PtrBaseIndex{
.ty = ptr.ty,
.base = base_index.base,
.index = index_index,
}),
});
},
}
},
),
.comptime_field => |field_val| {
assert(field_val != .none);
ip.items.appendAssumeCapacity(.{
.tag = .ptr_comptime_field,
.data = try ip.addExtra(gpa, PtrComptimeField{
.ty = ptr.ty,
.field_val = field_val,
}),
});
},
else => {
// TODO: change Key.Ptr for slices to reference the manyptr value
// rather than having an addr field directly. Then we can avoid
// these problematic calls to pop(), get(), and getOrPutAdapted().
assert(ptr_type.flags.size == .Slice);
.int, .eu_payload, .opt_payload => |base| {
switch (ptr.addr) {
.int => assert(ip.typeOf(base) == .usize_type),
.eu_payload => assert(ip.indexToKey(
ip.indexToKey(ip.typeOf(base)).ptr_type.child,
) == .error_union_type),
.opt_payload => assert(ip.indexToKey(
ip.indexToKey(ip.typeOf(base)).ptr_type.child,
) == .opt_type),
else => unreachable,
}
ip.items.appendAssumeCapacity(.{
.tag = switch (ptr.addr) {
.int => .ptr_int,
.eu_payload => .ptr_eu_payload,
.opt_payload => .ptr_opt_payload,
else => unreachable,
},
.data = try ip.addExtra(gpa, PtrBase{
.ty = ptr.ty,
.base = base,
}),
});
},
.elem, .field => |base_index| {
const base_ptr_type = ip.indexToKey(ip.typeOf(base_index.base)).ptr_type;
switch (ptr.addr) {
.elem => assert(base_ptr_type.flags.size == .Many),
.field => {
assert(base_ptr_type.flags.size == .One);
switch (ip.indexToKey(base_ptr_type.child)) {
.anon_struct_type => |anon_struct_type| {
assert(ptr.addr == .field);
assert(base_index.index < anon_struct_type.types.len);
},
.struct_type => |struct_type| {
assert(ptr.addr == .field);
assert(base_index.index < struct_type.field_types.len);
},
.union_type => |union_key| {
const union_type = ip.loadUnionType(union_key);
assert(ptr.addr == .field);
assert(base_index.index < union_type.field_names.len);
},
.ptr_type => |slice_type| {
assert(ptr.addr == .field);
assert(slice_type.flags.size == .Slice);
assert(base_index.index < 2);
},
else => unreachable,
}
},
else => unreachable,
}
_ = ip.map.pop();
var new_key = key;
new_key.ptr.ty = ip.slicePtrType(ptr.ty);
new_key.ptr.len = .none;
assert(ip.indexToKey(new_key.ptr.ty).ptr_type.flags.size == .Many);
const ptr_index = try ip.get(gpa, new_key);
const index_index = try ip.get(gpa, .{ .int = .{
.ty = .usize_type,
.storage = .{ .u64 = base_index.index },
} });
assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing);
try ip.items.ensureUnusedCapacity(gpa, 1);
ip.items.appendAssumeCapacity(.{
.tag = .ptr_slice,
.data = try ip.addExtra(gpa, PtrSlice{
.tag = switch (ptr.addr) {
.elem => .ptr_elem,
.field => .ptr_field,
else => unreachable,
},
.data = try ip.addExtra(gpa, PtrBaseIndex{
.ty = ptr.ty,
.ptr = ptr_index,
.len = ptr.len,
.base = base_index.base,
.index = index_index,
}),
});
},
}
assert(ptr.ty == ip.indexToKey(@as(Index, @enumFromInt(ip.items.len - 1))).ptr.ty);
},
.opt => |opt| {
@@ -6844,14 +6783,20 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
.val = .none,
} });
if (ip.isPointerType(new_ty)) return ip.get(gpa, .{ .ptr = .{
.ty = new_ty,
.addr = .{ .int = .zero_usize },
.len = switch (ip.indexToKey(new_ty).ptr_type.flags.size) {
.One, .Many, .C => .none,
.Slice => try ip.get(gpa, .{ .undef = .usize_type }),
},
} });
if (ip.isPointerType(new_ty)) switch (ip.indexToKey(new_ty).ptr_type.flags.size) {
.One, .Many, .C => return ip.get(gpa, .{ .ptr = .{
.ty = new_ty,
.addr = .{ .int = .zero_usize },
} }),
.Slice => return ip.get(gpa, .{ .slice = .{
.ty = new_ty,
.ptr = try ip.get(gpa, .{ .ptr = .{
.ty = ip.slicePtrType(new_ty),
.addr = .{ .int = .zero_usize },
} }),
.len = try ip.get(gpa, .{ .undef = .usize_type }),
} }),
};
},
else => switch (tags[@intFromEnum(val)]) {
.func_decl => return getCoercedFuncDecl(ip, gpa, val, new_ty),
@@ -6929,11 +6874,18 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
},
else => {},
},
.ptr => |ptr| if (ip.isPointerType(new_ty))
.slice => |slice| if (ip.isPointerType(new_ty) and ip.indexToKey(new_ty).ptr_type.flags.size == .Slice)
return ip.get(gpa, .{ .slice = .{
.ty = new_ty,
.ptr = try ip.getCoerced(gpa, slice.ptr, ip.slicePtrType(new_ty)),
.len = slice.len,
} })
else if (ip.isIntegerType(new_ty))
return ip.getCoerced(gpa, slice.ptr, new_ty),
.ptr => |ptr| if (ip.isPointerType(new_ty) and ip.indexToKey(new_ty).ptr_type.flags.size != .Slice)
return ip.get(gpa, .{ .ptr = .{
.ty = new_ty,
.addr = ptr.addr,
.len = ptr.len,
} })
else if (ip.isIntegerType(new_ty))
switch (ptr.addr) {
@@ -6942,14 +6894,20 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
},
.opt => |opt| switch (ip.indexToKey(new_ty)) {
.ptr_type => |ptr_type| return switch (opt.val) {
.none => try ip.get(gpa, .{ .ptr = .{
.ty = new_ty,
.addr = .{ .int = .zero_usize },
.len = switch (ptr_type.flags.size) {
.One, .Many, .C => .none,
.Slice => try ip.get(gpa, .{ .undef = .usize_type }),
},
} }),
.none => switch (ptr_type.flags.size) {
.One, .Many, .C => try ip.get(gpa, .{ .ptr = .{
.ty = new_ty,
.addr = .{ .int = .zero_usize },
} }),
.Slice => try ip.get(gpa, .{ .slice = .{
.ty = new_ty,
.ptr = try ip.get(gpa, .{ .ptr = .{
.ty = ip.slicePtrType(new_ty),
.addr = .{ .int = .zero_usize },
} }),
.len = try ip.get(gpa, .{ .undef = .usize_type }),
} }),
},
else => |payload| try ip.getCoerced(gpa, payload, new_ty),
},
.opt_type => |child_type| return try ip.get(gpa, .{ .opt = .{

View File

@@ -5278,9 +5278,12 @@ pub fn populateTestFunctions(
const test_fn_fields = .{
// name
try mod.intern(.{ .ptr = .{
try mod.intern(.{ .slice = .{
.ty = .slice_const_u8_type,
.addr = .{ .decl = test_name_decl_index },
.ptr = try mod.intern(.{ .ptr = .{
.ty = .manyptr_const_u8_type,
.addr = .{ .decl = test_name_decl_index },
} }),
.len = try mod.intern(.{ .int = .{
.ty = .usize_type,
.storage = .{ .u64 = test_decl_name.len },
@@ -5331,9 +5334,12 @@ pub fn populateTestFunctions(
},
});
const new_val = decl.val;
const new_init = try mod.intern(.{ .ptr = .{
const new_init = try mod.intern(.{ .slice = .{
.ty = new_ty.toIntern(),
.addr = .{ .decl = array_decl_index },
.ptr = try mod.intern(.{ .ptr = .{
.ty = new_ty.slicePtrFieldType(mod).toIntern(),
.addr = .{ .decl = array_decl_index },
} }),
.len = (try mod.intValue(Type.usize, mod.test_functions.count())).toIntern(),
} });
ip.mutateVarInit(decl.val.toIntern(), new_init);
@@ -5423,16 +5429,17 @@ pub fn markReferencedDeclsAlive(mod: *Module, val: Value) Allocator.Error!void {
.err_name => {},
.payload => |payload| try mod.markReferencedDeclsAlive(Value.fromInterned(payload)),
},
.ptr => |ptr| {
switch (ptr.addr) {
.decl => |decl| try mod.markDeclIndexAlive(decl),
.anon_decl => {},
.mut_decl => |mut_decl| try mod.markDeclIndexAlive(mut_decl.decl),
.int, .comptime_field => {},
.eu_payload, .opt_payload => |parent| try mod.markReferencedDeclsAlive(Value.fromInterned(parent)),
.elem, .field => |base_index| try mod.markReferencedDeclsAlive(Value.fromInterned(base_index.base)),
}
if (ptr.len != .none) try mod.markReferencedDeclsAlive(Value.fromInterned(ptr.len));
.slice => |slice| {
try mod.markReferencedDeclsAlive(Value.fromInterned(slice.ptr));
try mod.markReferencedDeclsAlive(Value.fromInterned(slice.len));
},
.ptr => |ptr| switch (ptr.addr) {
.decl => |decl| try mod.markDeclIndexAlive(decl),
.anon_decl => {},
.mut_decl => |mut_decl| try mod.markDeclIndexAlive(mut_decl.decl),
.int, .comptime_field => {},
.eu_payload, .opt_payload => |parent| try mod.markReferencedDeclsAlive(Value.fromInterned(parent)),
.elem, .field => |base_index| try mod.markReferencedDeclsAlive(Value.fromInterned(base_index.base)),
},
.opt => |opt| if (opt.val != .none) try mod.markReferencedDeclsAlive(Value.fromInterned(opt.val)),
.aggregate => |aggregate| for (aggregate.storage.values()) |elem|

View File

@@ -17375,16 +17375,19 @@ fn zirBuiltinSrc(
.sentinel = .zero_u8,
.child = .u8_type,
} });
break :v try ip.get(gpa, .{ .ptr = .{
break :v try ip.get(gpa, .{ .slice = .{
.ty = .slice_const_u8_sentinel_0_type,
.ptr = try ip.get(gpa, .{ .ptr = .{
.ty = .manyptr_const_u8_sentinel_0_type,
.addr = .{ .anon_decl = .{
.orig_ty = .slice_const_u8_sentinel_0_type,
.val = try ip.get(gpa, .{ .aggregate = .{
.ty = array_ty,
.storage = .{ .bytes = bytes },
} }),
} },
} }),
.len = (try mod.intValue(Type.usize, bytes.len)).toIntern(),
.addr = .{ .anon_decl = .{
.orig_ty = .slice_const_u8_sentinel_0_type,
.val = try ip.get(gpa, .{ .aggregate = .{
.ty = array_ty,
.storage = .{ .bytes = bytes },
} }),
} },
} });
};
@@ -17396,16 +17399,19 @@ fn zirBuiltinSrc(
.sentinel = .zero_u8,
.child = .u8_type,
} });
break :v try ip.get(gpa, .{ .ptr = .{
break :v try ip.get(gpa, .{ .slice = .{
.ty = .slice_const_u8_sentinel_0_type,
.ptr = try ip.get(gpa, .{ .ptr = .{
.ty = .manyptr_const_u8_sentinel_0_type,
.addr = .{ .anon_decl = .{
.orig_ty = .slice_const_u8_sentinel_0_type,
.val = try ip.get(gpa, .{ .aggregate = .{
.ty = array_ty,
.storage = .{ .bytes = bytes },
} }),
} },
} }),
.len = (try mod.intValue(Type.usize, bytes.len)).toIntern(),
.addr = .{ .anon_decl = .{
.orig_ty = .slice_const_u8_sentinel_0_type,
.val = try ip.get(gpa, .{ .aggregate = .{
.ty = array_ty,
.storage = .{ .bytes = bytes },
} }),
} },
} });
};
@@ -17517,12 +17523,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.is_const = true,
},
})).toIntern();
break :v try mod.intern(.{ .ptr = .{
break :v try mod.intern(.{ .slice = .{
.ty = ptr_ty,
.addr = .{ .anon_decl = .{
.orig_ty = ptr_ty,
.val = new_decl_val,
} },
.ptr = try mod.intern(.{ .ptr = .{
.ty = Type.fromInterned(ptr_ty).slicePtrFieldType(mod).toIntern(),
.addr = .{ .anon_decl = .{
.orig_ty = ptr_ty,
.val = new_decl_val,
} },
} }),
.len = (try mod.intValue(Type.usize, param_vals.len)).toIntern(),
} });
};
@@ -17796,12 +17805,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.ty = new_decl_ty.toIntern(),
.storage = .{ .bytes = name },
} });
break :v try mod.intern(.{ .ptr = .{
break :v try mod.intern(.{ .slice = .{
.ty = .slice_const_u8_sentinel_0_type,
.addr = .{ .anon_decl = .{
.val = new_decl_val,
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
.ptr = try mod.intern(.{ .ptr = .{
.ty = .manyptr_const_u8_sentinel_0_type,
.addr = .{ .anon_decl = .{
.val = new_decl_val,
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
} }),
.len = (try mod.intValue(Type.usize, name.len)).toIntern(),
} });
};
@@ -17838,12 +17850,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.ty = array_errors_ty.toIntern(),
.storage = .{ .elems = vals },
} });
break :v try mod.intern(.{ .ptr = .{
break :v try mod.intern(.{ .slice = .{
.ty = slice_errors_ty.toIntern(),
.addr = .{ .anon_decl = .{
.orig_ty = slice_errors_ty.toIntern(),
.val = new_decl_val,
} },
.ptr = try mod.intern(.{ .ptr = .{
.ty = slice_errors_ty.slicePtrFieldType(mod).toIntern(),
.addr = .{ .anon_decl = .{
.orig_ty = slice_errors_ty.toIntern(),
.val = new_decl_val,
} },
} }),
.len = (try mod.intValue(Type.usize, vals.len)).toIntern(),
} });
} else .none;
@@ -17925,12 +17940,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.ty = new_decl_ty.toIntern(),
.storage = .{ .bytes = name },
} });
break :v try mod.intern(.{ .ptr = .{
break :v try mod.intern(.{ .slice = .{
.ty = .slice_const_u8_sentinel_0_type,
.addr = .{ .anon_decl = .{
.val = new_decl_val,
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
.ptr = try mod.intern(.{ .ptr = .{
.ty = .manyptr_const_u8_sentinel_0_type,
.addr = .{ .anon_decl = .{
.val = new_decl_val,
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
} }),
.len = (try mod.intValue(Type.usize, name.len)).toIntern(),
} });
};
@@ -17963,12 +17981,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.is_const = true,
},
})).toIntern();
break :v try mod.intern(.{ .ptr = .{
break :v try mod.intern(.{ .slice = .{
.ty = ptr_ty,
.addr = .{ .anon_decl = .{
.val = new_decl_val,
.orig_ty = ptr_ty,
} },
.ptr = try mod.intern(.{ .ptr = .{
.ty = Type.fromInterned(ptr_ty).slicePtrFieldType(mod).toIntern(),
.addr = .{ .anon_decl = .{
.val = new_decl_val,
.orig_ty = ptr_ty,
} },
} }),
.len = (try mod.intValue(Type.usize, enum_field_vals.len)).toIntern(),
} });
};
@@ -18051,12 +18072,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.ty = new_decl_ty.toIntern(),
.storage = .{ .bytes = name },
} });
break :v try mod.intern(.{ .ptr = .{
break :v try mod.intern(.{ .slice = .{
.ty = .slice_const_u8_sentinel_0_type,
.addr = .{ .anon_decl = .{
.val = new_decl_val,
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
.ptr = try mod.intern(.{ .ptr = .{
.ty = .manyptr_const_u8_sentinel_0_type,
.addr = .{ .anon_decl = .{
.val = new_decl_val,
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
} }),
.len = (try mod.intValue(Type.usize, name.len)).toIntern(),
} });
};
@@ -18097,12 +18121,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.is_const = true,
},
})).toIntern();
break :v try mod.intern(.{ .ptr = .{
break :v try mod.intern(.{ .slice = .{
.ty = ptr_ty,
.addr = .{ .anon_decl = .{
.orig_ty = ptr_ty,
.val = new_decl_val,
} },
.ptr = try mod.intern(.{ .ptr = .{
.ty = Type.fromInterned(ptr_ty).slicePtrFieldType(mod).toIntern(),
.addr = .{ .anon_decl = .{
.orig_ty = ptr_ty,
.val = new_decl_val,
} },
} }),
.len = (try mod.intValue(Type.usize, union_field_vals.len)).toIntern(),
} });
};
@@ -18199,12 +18226,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.ty = new_decl_ty.toIntern(),
.storage = .{ .bytes = bytes },
} });
break :v try mod.intern(.{ .ptr = .{
break :v try mod.intern(.{ .slice = .{
.ty = .slice_const_u8_sentinel_0_type,
.addr = .{ .anon_decl = .{
.val = new_decl_val,
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
.ptr = try mod.intern(.{ .ptr = .{
.ty = .manyptr_const_u8_sentinel_0_type,
.addr = .{ .anon_decl = .{
.val = new_decl_val,
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
} }),
.len = (try mod.intValue(Type.usize, bytes.len)).toIntern(),
} });
};
@@ -18259,12 +18289,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.ty = new_decl_ty.toIntern(),
.storage = .{ .bytes = name },
} });
break :v try mod.intern(.{ .ptr = .{
break :v try mod.intern(.{ .slice = .{
.ty = .slice_const_u8_sentinel_0_type,
.addr = .{ .anon_decl = .{
.val = new_decl_val,
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
.ptr = try mod.intern(.{ .ptr = .{
.ty = .manyptr_const_u8_sentinel_0_type,
.addr = .{ .anon_decl = .{
.val = new_decl_val,
.orig_ty = .slice_const_u8_sentinel_0_type,
} },
} }),
.len = (try mod.intValue(Type.usize, name.len)).toIntern(),
} });
};
@@ -18315,12 +18348,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.is_const = true,
},
})).toIntern();
break :v try mod.intern(.{ .ptr = .{
break :v try mod.intern(.{ .slice = .{
.ty = ptr_ty,
.addr = .{ .anon_decl = .{
.orig_ty = ptr_ty,
.val = new_decl_val,
} },
.ptr = try mod.intern(.{ .ptr = .{
.ty = Type.fromInterned(ptr_ty).slicePtrFieldType(mod).toIntern(),
.addr = .{ .anon_decl = .{
.orig_ty = ptr_ty,
.val = new_decl_val,
} },
} }),
.len = (try mod.intValue(Type.usize, struct_field_vals.len)).toIntern(),
} });
};
@@ -18453,12 +18489,15 @@ fn typeInfoDecls(
.is_const = true,
},
})).toIntern();
return try mod.intern(.{ .ptr = .{
return try mod.intern(.{ .slice = .{
.ty = ptr_ty,
.addr = .{ .anon_decl = .{
.orig_ty = ptr_ty,
.val = new_decl_val,
} },
.ptr = try mod.intern(.{ .ptr = .{
.ty = Type.fromInterned(ptr_ty).slicePtrFieldType(mod).toIntern(),
.addr = .{ .anon_decl = .{
.orig_ty = ptr_ty,
.val = new_decl_val,
} },
} }),
.len = (try mod.intValue(Type.usize, decl_vals.items.len)).toIntern(),
} });
}
@@ -18498,12 +18537,15 @@ fn typeInfoNamespaceDecls(
.ty = new_decl_ty.toIntern(),
.storage = .{ .bytes = name },
} });
break :v try mod.intern(.{ .ptr = .{
break :v try mod.intern(.{ .slice = .{
.ty = .slice_const_u8_sentinel_0_type,
.addr = .{ .anon_decl = .{
.orig_ty = .slice_const_u8_sentinel_0_type,
.val = new_decl_val,
} },
.ptr = try mod.intern(.{ .ptr = .{
.ty = .manyptr_const_u8_sentinel_0_type,
.addr = .{ .anon_decl = .{
.orig_ty = .slice_const_u8_sentinel_0_type,
.val = new_decl_val,
} },
} }),
.len = (try mod.intValue(Type.usize, name.len)).toIntern(),
} });
};
@@ -22738,9 +22780,12 @@ fn ptrCastFull(
if (dest_info.flags.size == .Slice and src_info.flags.size != .Slice) {
if (ptr_val.isUndef(mod)) return mod.undefRef(dest_ty);
const arr_len = try mod.intValue(Type.usize, Type.fromInterned(src_info.child).arrayLen(mod));
return Air.internedToRef((try mod.intern(.{ .ptr = .{
return Air.internedToRef((try mod.intern(.{ .slice = .{
.ty = dest_ty.toIntern(),
.addr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr,
.ptr = try mod.intern(.{ .ptr = .{
.ty = dest_ty.slicePtrFieldType(mod).toIntern(),
.addr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr,
} }),
.len = arr_len.toIntern(),
} })));
} else {
@@ -28765,21 +28810,24 @@ fn coerceExtra(
if (inst_child_ty.structFieldCount(mod) == 0) {
// Optional slice is represented with a null pointer so
// we use a dummy pointer value with the required alignment.
return Air.internedToRef((try mod.intern(.{ .ptr = .{
return Air.internedToRef((try mod.intern(.{ .slice = .{
.ty = dest_ty.toIntern(),
.addr = .{ .int = if (dest_info.flags.alignment != .none)
(try mod.intValue(
Type.usize,
dest_info.flags.alignment.toByteUnitsOptional().?,
)).toIntern()
else
try mod.intern_pool.getCoercedInts(
mod.gpa,
mod.intern_pool.indexToKey(
(try Type.fromInterned(dest_info.child).lazyAbiAlignment(mod)).toIntern(),
).int,
.usize_type,
) },
.ptr = try mod.intern(.{ .ptr = .{
.ty = dest_ty.slicePtrFieldType(mod).toIntern(),
.addr = .{ .int = if (dest_info.flags.alignment != .none)
(try mod.intValue(
Type.usize,
dest_info.flags.alignment.toByteUnitsOptional().?,
)).toIntern()
else
try mod.intern_pool.getCoercedInts(
mod.gpa,
mod.intern_pool.indexToKey(
(try Type.fromInterned(dest_info.child).lazyAbiAlignment(mod)).toIntern(),
).int,
.usize_type,
) },
} }),
.len = (try mod.intValue(Type.usize, 0)).toIntern(),
} })));
}
@@ -31276,7 +31324,7 @@ fn beginComptimePtrLoad(
},
Value.slice_len_index => TypedValue{
.ty = Type.usize,
.val = Value.fromInterned(ip.indexToKey(try tv.val.intern(tv.ty, mod)).ptr.len),
.val = Value.fromInterned(ip.indexToKey(try tv.val.intern(tv.ty, mod)).slice.len),
},
else => unreachable,
};
@@ -31445,13 +31493,16 @@ fn coerceArrayPtrToSlice(
if (try sema.resolveValue(inst)) |val| {
const ptr_array_ty = sema.typeOf(inst);
const array_ty = ptr_array_ty.childType(mod);
const slice_val = try mod.intern(.{ .ptr = .{
const slice_val = try mod.intern(.{ .slice = .{
.ty = dest_ty.toIntern(),
.addr = switch (mod.intern_pool.indexToKey(val.toIntern())) {
.undef => .{ .int = try mod.intern(.{ .undef = .usize_type }) },
.ptr => |ptr| ptr.addr,
else => unreachable,
},
.ptr = try mod.intern(.{ .ptr = .{
.ty = dest_ty.slicePtrFieldType(mod).toIntern(),
.addr = switch (mod.intern_pool.indexToKey(val.toIntern())) {
.undef => .{ .int = try mod.intern(.{ .undef = .usize_type }) },
.ptr => |ptr| ptr.addr,
else => unreachable,
},
} }),
.len = (try mod.intValue(Type.usize, array_ty.arrayLen(mod))).toIntern(),
} });
return Air.internedToRef(slice_val);
@@ -35211,51 +35262,43 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
(try val.getUnsignedIntAdvanced(mod, sema)).?,
),
},
.slice => |slice| {
const ptr = try sema.resolveLazyValue(Value.fromInterned(slice.ptr));
const len = try sema.resolveLazyValue(Value.fromInterned(slice.len));
if (ptr.toIntern() == slice.ptr and len.toIntern() == slice.len) return val;
return Value.fromInterned(try mod.intern(.{ .slice = .{
.ty = slice.ty,
.ptr = ptr.toIntern(),
.len = len.toIntern(),
} }));
},
.ptr => |ptr| {
const resolved_len = switch (ptr.len) {
.none => .none,
else => (try sema.resolveLazyValue(Value.fromInterned(ptr.len))).toIntern(),
};
switch (ptr.addr) {
.decl, .mut_decl, .anon_decl => return if (resolved_len == ptr.len)
val
else
Value.fromInterned((try mod.intern(.{ .ptr = .{
.ty = ptr.ty,
.addr = switch (ptr.addr) {
.decl => |decl| .{ .decl = decl },
.mut_decl => |mut_decl| .{ .mut_decl = mut_decl },
.anon_decl => |anon_decl| .{ .anon_decl = anon_decl },
else => unreachable,
},
.len = resolved_len,
} }))),
.decl, .mut_decl, .anon_decl => return val,
.comptime_field => |field_val| {
const resolved_field_val =
(try sema.resolveLazyValue(Value.fromInterned(field_val))).toIntern();
return if (resolved_field_val == field_val and resolved_len == ptr.len)
return if (resolved_field_val == field_val)
val
else
Value.fromInterned((try mod.intern(.{ .ptr = .{
.ty = ptr.ty,
.addr = .{ .comptime_field = resolved_field_val },
.len = resolved_len,
} })));
},
.int => |int| {
const resolved_int = (try sema.resolveLazyValue(Value.fromInterned(int))).toIntern();
return if (resolved_int == int and resolved_len == ptr.len)
return if (resolved_int == int)
val
else
Value.fromInterned((try mod.intern(.{ .ptr = .{
.ty = ptr.ty,
.addr = .{ .int = resolved_int },
.len = resolved_len,
} })));
},
.eu_payload, .opt_payload => |base| {
const resolved_base = (try sema.resolveLazyValue(Value.fromInterned(base))).toIntern();
return if (resolved_base == base and resolved_len == ptr.len)
return if (resolved_base == base)
val
else
Value.fromInterned((try mod.intern(.{ .ptr = .{
@@ -35265,12 +35308,11 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
.opt_payload => .{ .opt_payload = resolved_base },
else => unreachable,
},
.len = ptr.len,
} })));
},
.elem, .field => |base_index| {
const resolved_base = (try sema.resolveLazyValue(Value.fromInterned(base_index.base))).toIntern();
return if (resolved_base == base_index.base and resolved_len == ptr.len)
return if (resolved_base == base_index.base)
val
else
Value.fromInterned((try mod.intern(.{ .ptr = .{
@@ -35286,7 +35328,6 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
} },
else => unreachable,
},
.len = ptr.len,
} })));
},
}

View File

@@ -264,52 +264,56 @@ pub fn print(
.float => |float| switch (float.storage) {
inline else => |x| return writer.print("{d}", .{@as(f64, @floatCast(x))}),
},
.ptr => |ptr| {
if (ptr.addr == .int) {
switch (ip.indexToKey(ptr.addr.int)) {
.int => |i| switch (i.storage) {
inline else => |addr| return writer.print("{x:0>8}", .{addr}),
},
.undef => return writer.writeAll("undefined"),
else => unreachable,
}
.slice => |slice| {
const ptr_ty = switch (ip.indexToKey(slice.ptr)) {
.ptr => |ptr| ty: {
if (ptr.addr == .int) return print(.{
.ty = Type.fromInterned(ptr.ty),
.val = Value.fromInterned(slice.ptr),
}, writer, level - 1, mod);
break :ty ip.indexToKey(ptr.ty).ptr_type;
},
.undef => |ptr_ty| ip.indexToKey(ptr_ty).ptr_type,
else => unreachable,
};
if (level == 0) {
return writer.writeAll(".{ ... }");
}
const elem_ty = Type.fromInterned(ptr_ty.child);
const len = Value.fromInterned(slice.len).toUnsignedInt(mod);
if (elem_ty.eql(Type.u8, mod)) str: {
const max_len = @min(len, max_string_len);
var buf: [max_string_len]u8 = undefined;
for (buf[0..max_len], 0..) |*c, i| {
const maybe_elem = try val.maybeElemValue(mod, i);
const elem = maybe_elem orelse return writer.writeAll(".{ (reinterpreted data) }");
if (elem.isUndef(mod)) break :str;
c.* = @as(u8, @intCast(elem.toUnsignedInt(mod)));
}
const truncated = if (len > max_string_len) " (truncated)" else "";
return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated });
}
try writer.writeAll(".{ ");
const max_len = @min(len, max_aggregate_items);
for (0..max_len) |i| {
if (i != 0) try writer.writeAll(", ");
const maybe_elem = try val.maybeElemValue(mod, i);
const elem = maybe_elem orelse return writer.writeAll("(reinterpreted data) }");
try print(.{
.ty = elem_ty,
.val = elem,
}, writer, level - 1, mod);
}
if (len > max_aggregate_items) {
try writer.writeAll(", ...");
}
return writer.writeAll(" }");
},
.ptr => |ptr| {
if (ptr.addr == .int) {}
const ptr_ty = ip.indexToKey(ty.toIntern()).ptr_type;
if (ptr_ty.flags.size == .Slice) {
if (level == 0) {
return writer.writeAll(".{ ... }");
}
const elem_ty = Type.fromInterned(ptr_ty.child);
const len = Value.fromInterned(ptr.len).toUnsignedInt(mod);
if (elem_ty.eql(Type.u8, mod)) str: {
const max_len = @min(len, max_string_len);
var buf: [max_string_len]u8 = undefined;
for (buf[0..max_len], 0..) |*c, i| {
const maybe_elem = try val.maybeElemValue(mod, i);
const elem = maybe_elem orelse return writer.writeAll(".{ (reinterpreted data) }");
if (elem.isUndef(mod)) break :str;
c.* = @as(u8, @intCast(elem.toUnsignedInt(mod)));
}
const truncated = if (len > max_string_len) " (truncated)" else "";
return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated });
}
try writer.writeAll(".{ ");
const max_len = @min(len, max_aggregate_items);
for (0..max_len) |i| {
if (i != 0) try writer.writeAll(", ");
const maybe_elem = try val.maybeElemValue(mod, i);
const elem = maybe_elem orelse return writer.writeAll("(reinterpreted data) }");
try print(.{
.ty = elem_ty,
.val = elem,
}, writer, level - 1, mod);
}
if (len > max_aggregate_items) {
try writer.writeAll(", ...");
}
return writer.writeAll(" }");
}
if (ptr_ty.flags.size == .Slice) {}
switch (ptr.addr) {
.decl => |decl_index| {

View File

@@ -3179,9 +3179,6 @@ fn lowerAnonDeclRef(
fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: InternPool.DeclIndex, offset: u32) InnerError!WValue {
const mod = func.bin_file.base.comp.module.?;
if (tv.ty.isSlice(mod)) {
return WValue{ .memory = try func.bin_file.lowerUnnamedConst(tv, decl_index) };
}
const decl = mod.declPtr(decl_index);
// check if decl is an alias to a function, in which case we
@@ -3335,6 +3332,18 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
.f64 => |f64_val| return WValue{ .float64 = f64_val },
else => unreachable,
},
.slice => |slice| {
var ptr = ip.indexToKey(slice.ptr).ptr;
const owner_decl = while (true) switch (ptr.addr) {
.decl => |decl| break decl,
.mut_decl => |mut_decl| break mut_decl.decl,
.int, .anon_decl => return func.fail("Wasm TODO: lower slice where ptr is not owned by decl", .{}),
.opt_payload, .eu_payload => |base| ptr = ip.indexToKey(base).ptr,
.elem, .field => |base_index| ptr = ip.indexToKey(base_index.base).ptr,
.comptime_field => unreachable,
};
return .{ .memory = try func.bin_file.lowerUnnamedConst(.{ .ty = ty, .val = val }, owner_decl) };
},
.ptr => |ptr| switch (ptr.addr) {
.decl => |decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl, 0),
.mut_decl => |mut_decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, mut_decl.decl, 0),

View File

@@ -322,24 +322,24 @@ pub fn generateSymbol(
},
.f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(16)),
},
.ptr => |ptr| {
// generate ptr
switch (try lowerParentPtr(bin_file, src_loc, switch (ptr.len) {
.none => typed_value.val,
else => typed_value.val.slicePtr(mod),
}.toIntern(), code, debug_output, reloc_info)) {
.ptr => switch (try lowerParentPtr(bin_file, src_loc, typed_value.val.toIntern(), code, debug_output, reloc_info)) {
.ok => {},
.fail => |em| return .{ .fail = em },
},
.slice => |slice| {
switch (try generateSymbol(bin_file, src_loc, .{
.ty = typed_value.ty.slicePtrFieldType(mod),
.val = Value.fromInterned(slice.ptr),
}, code, debug_output, reloc_info)) {
.ok => {},
.fail => |em| return .{ .fail = em },
}
if (ptr.len != .none) {
// generate len
switch (try generateSymbol(bin_file, src_loc, .{
.ty = Type.usize,
.val = Value.fromInterned(ptr.len),
}, code, debug_output, reloc_info)) {
.ok => {},
.fail => |em| return Result{ .fail = em },
}
switch (try generateSymbol(bin_file, src_loc, .{
.ty = Type.usize,
.val = Value.fromInterned(slice.len),
}, code, debug_output, reloc_info)) {
.ok => {},
.fail => |em| return .{ .fail = em },
}
},
.opt => {
@@ -676,7 +676,6 @@ fn lowerParentPtr(
) CodeGenError!Result {
const mod = bin_file.comp.module.?;
const ptr = mod.intern_pool.indexToKey(parent_ptr).ptr;
assert(ptr.len == .none);
return switch (ptr.addr) {
.decl => |decl| try lowerDeclRef(bin_file, src_loc, decl, code, debug_output, reloc_info),
.mut_decl => |md| try lowerDeclRef(bin_file, src_loc, md.decl, code, debug_output, reloc_info),

View File

@@ -1207,50 +1207,35 @@ pub const DeclGen = struct {
try writer.print("{x}", .{try dg.fmtIntLiteral(repr_ty, repr_val, location)});
if (!empty) try writer.writeByte(')');
},
.ptr => |ptr| {
if (ptr.len != .none) {
if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderType(writer, ty);
try writer.writeByte(')');
}
try writer.writeByte('{');
}
const ptr_location = switch (ptr.len) {
.none => location,
else => initializer_type,
};
const ptr_ty = switch (ptr.len) {
.none => ty,
else => ty.slicePtrFieldType(mod),
};
const ptr_val = switch (ptr.len) {
.none => val,
else => val.slicePtr(mod),
};
switch (ptr.addr) {
.decl => |d| try dg.renderDeclValue(writer, ptr_ty, ptr_val, d, ptr_location),
.mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, ptr_val, md.decl, ptr_location),
.anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val, decl_val, ptr_location),
.int => |int| {
try writer.writeAll("((");
try dg.renderType(writer, ptr_ty);
try writer.print("){x})", .{
try dg.fmtIntLiteral(Type.usize, Value.fromInterned(int), ptr_location),
});
},
.eu_payload,
.opt_payload,
.elem,
.field,
=> try dg.renderParentPtr(writer, ptr_val.ip_index, ptr_location),
.comptime_field => unreachable,
}
if (ptr.len != .none) {
try writer.writeAll(", ");
try dg.renderValue(writer, Type.usize, Value.fromInterned(ptr.len), initializer_type);
try writer.writeByte('}');
.slice => |slice| {
if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderType(writer, ty);
try writer.writeByte(')');
}
try writer.writeByte('{');
try dg.renderValue(writer, ty.slicePtrFieldType(mod), Value.fromInterned(slice.ptr), initializer_type);
try writer.writeAll(", ");
try dg.renderValue(writer, Type.usize, Value.fromInterned(slice.len), initializer_type);
try writer.writeByte('}');
},
.ptr => |ptr| switch (ptr.addr) {
.decl => |d| try dg.renderDeclValue(writer, ty, val, d, location),
.mut_decl => |md| try dg.renderDeclValue(writer, ty, val, md.decl, location),
.anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ty, val, decl_val, location),
.int => |int| {
try writer.writeAll("((");
try dg.renderType(writer, ty);
try writer.print("){x})", .{
try dg.fmtIntLiteral(Type.usize, Value.fromInterned(int), location),
});
},
.eu_payload,
.opt_payload,
.elem,
.field,
=> try dg.renderParentPtr(writer, val.ip_index, location),
.comptime_field => unreachable,
},
.opt => |opt| {
const payload_ty = ty.optionalChild(mod);

View File

@@ -3644,6 +3644,7 @@ pub const Object = struct {
.empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
@@ -3872,30 +3873,22 @@ pub const Object = struct {
128 => try o.builder.fp128Const(val.toFloat(f128, mod)),
else => unreachable,
},
.ptr => |ptr| {
const ptr_ty = switch (ptr.len) {
.none => ty,
else => ty.slicePtrFieldType(mod),
};
const ptr_val = switch (ptr.addr) {
.decl => |decl| try o.lowerDeclRefValue(ptr_ty, decl),
.mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_ty, mut_decl.decl),
.anon_decl => |anon_decl| try o.lowerAnonDeclRef(ptr_ty, anon_decl),
.int => |int| try o.lowerIntAsPtr(int),
.eu_payload,
.opt_payload,
.elem,
.field,
=> try o.lowerParentPtr(val),
.comptime_field => unreachable,
};
switch (ptr.len) {
.none => return ptr_val,
else => return o.builder.structConst(try o.lowerType(ty), &.{
ptr_val, try o.lowerValue(ptr.len),
}),
}
.ptr => |ptr| return switch (ptr.addr) {
.decl => |decl| try o.lowerDeclRefValue(ty, decl),
.mut_decl => |mut_decl| try o.lowerDeclRefValue(ty, mut_decl.decl),
.anon_decl => |anon_decl| try o.lowerAnonDeclRef(ty, anon_decl),
.int => |int| try o.lowerIntAsPtr(int),
.eu_payload,
.opt_payload,
.elem,
.field,
=> try o.lowerParentPtr(val),
.comptime_field => unreachable,
},
.slice => |slice| return o.builder.structConst(try o.lowerType(ty), &.{
try o.lowerValue(slice.ptr),
try o.lowerValue(slice.len),
}),
.opt => |opt| {
comptime assert(optional_layout_version == 3);
const payload_ty = ty.optionalChild(mod);

View File

@@ -855,18 +855,12 @@ const DeclGen = struct {
const int_ty = ty.intTagType(mod);
return try self.constant(int_ty, int_val, repr);
},
.ptr => |ptr| {
const ptr_ty = switch (ptr.len) {
.none => ty,
else => ty.slicePtrFieldType(mod),
};
const ptr_id = try self.constantPtr(ptr_ty, val);
if (ptr.len == .none) {
return ptr_id;
}
const len_id = try self.constant(Type.usize, Value.fromInterned(ptr.len), .indirect);
return try self.constructStruct(
.ptr => return self.constantPtr(ty, val),
.slice => |slice| {
const ptr_ty = ty.slicePtrFieldType(mod);
const ptr_id = try self.constantPtr(ptr_ty, Value.fromInterned(slice.ptr));
const len_id = try self.constant(Type.usize, Value.fromInterned(slice.len), .indirect);
return self.constructStruct(
ty,
&.{ ptr_ty, Type.usize },
&.{ ptr_id, len_id },

View File

@@ -426,6 +426,7 @@ pub const Type = struct {
.empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
@@ -651,6 +652,7 @@ pub const Type = struct {
.empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
@@ -758,6 +760,7 @@ pub const Type = struct {
.empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
@@ -1073,6 +1076,7 @@ pub const Type = struct {
.empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
@@ -1434,6 +1438,7 @@ pub const Type = struct {
.empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
@@ -1660,6 +1665,7 @@ pub const Type = struct {
.empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
@@ -2195,6 +2201,7 @@ pub const Type = struct {
.empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
@@ -2538,6 +2545,7 @@ pub const Type = struct {
.empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,
@@ -2731,6 +2739,7 @@ pub const Type = struct {
.empty_enum_value,
.float,
.ptr,
.slice,
.opt,
.aggregate,
.un,

View File

@@ -194,10 +194,7 @@ pub const Value = struct {
const ip = &mod.intern_pool;
return switch (mod.intern_pool.indexToKey(val.toIntern())) {
.enum_literal => |enum_literal| enum_literal,
.ptr => |ptr| switch (ptr.len) {
.none => unreachable,
else => try arrayToIpString(val, Value.fromInterned(ptr.len).toUnsignedInt(mod), mod),
},
.slice => |slice| try arrayToIpString(val, Value.fromInterned(slice.len).toUnsignedInt(mod), mod),
.aggregate => |aggregate| switch (aggregate.storage) {
.bytes => |bytes| try ip.getOrPutString(mod.gpa, bytes),
.elems => try arrayToIpString(val, ty.arrayLen(mod), mod),
@@ -217,10 +214,7 @@ pub const Value = struct {
pub fn toAllocatedBytes(val: Value, ty: Type, allocator: Allocator, mod: *Module) ![]u8 {
return switch (mod.intern_pool.indexToKey(val.toIntern())) {
.enum_literal => |enum_literal| allocator.dupe(u8, mod.intern_pool.stringToSlice(enum_literal)),
.ptr => |ptr| switch (ptr.len) {
.none => unreachable,
else => try arrayToAllocatedBytes(val, Value.fromInterned(ptr.len).toUnsignedInt(mod), allocator, mod),
},
.slice => |slice| try arrayToAllocatedBytes(val, Value.fromInterned(slice.len).toUnsignedInt(mod), allocator, mod),
.aggregate => |aggregate| switch (aggregate.storage) {
.bytes => |bytes| try allocator.dupe(u8, bytes),
.elems => try arrayToAllocatedBytes(val, ty.arrayLen(mod), allocator, mod),
@@ -286,12 +280,11 @@ pub const Value = struct {
},
.slice => {
const pl = val.castTag(.slice).?.data;
const ptr = try pl.ptr.intern(ty.slicePtrFieldType(mod), mod);
var ptr_key = ip.indexToKey(ptr).ptr;
assert(ptr_key.len == .none);
ptr_key.ty = ty.toIntern();
ptr_key.len = try pl.len.intern(Type.usize, mod);
return mod.intern(.{ .ptr = ptr_key });
return mod.intern(.{ .slice = .{
.ty = ty.toIntern(),
.len = try pl.len.intern(Type.usize, mod),
.ptr = try pl.ptr.intern(ty.slicePtrFieldType(mod), mod),
} });
},
.bytes => {
const pl = val.castTag(.bytes).?.data;
@@ -374,6 +367,7 @@ pub const Value = struct {
.enum_tag,
.empty_enum_value,
.float,
.ptr,
=> val,
.error_union => |error_union| switch (error_union.val) {
@@ -381,13 +375,10 @@ pub const Value = struct {
.payload => |payload| Tag.eu_payload.create(arena, Value.fromInterned(payload)),
},
.ptr => |ptr| switch (ptr.len) {
.none => val,
else => |len| Tag.slice.create(arena, .{
.ptr = val.slicePtr(mod),
.len = Value.fromInterned(len),
}),
},
.slice => |slice| Tag.slice.create(arena, .{
.ptr = Value.fromInterned(slice.ptr),
.len = Value.fromInterned(slice.len),
}),
.opt => |opt| switch (opt.val) {
.none => val,
@@ -1538,6 +1529,7 @@ pub const Value = struct {
pub fn isComptimeMutablePtr(val: Value, mod: *Module) bool {
return switch (mod.intern_pool.indexToKey(val.toIntern())) {
.slice => |slice| return Value.fromInterned(slice.ptr).isComptimeMutablePtr(mod),
.ptr => |ptr| switch (ptr.addr) {
.mut_decl, .comptime_field => true,
.eu_payload, .opt_payload => |base_ptr| Value.fromInterned(base_ptr).isComptimeMutablePtr(mod),
@@ -1600,9 +1592,8 @@ pub const Value = struct {
pub fn sliceLen(val: Value, mod: *Module) u64 {
const ip = &mod.intern_pool;
const ptr = ip.indexToKey(val.toIntern()).ptr;
return switch (ptr.len) {
.none => switch (ip.indexToKey(switch (ptr.addr) {
return switch (ip.indexToKey(val.toIntern())) {
.ptr => |ptr| switch (ip.indexToKey(switch (ptr.addr) {
.decl => |decl| mod.declPtr(decl).ty.toIntern(),
.mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).ty.toIntern(),
.anon_decl => |anon_decl| ip.typeOf(anon_decl.val),
@@ -1612,7 +1603,8 @@ pub const Value = struct {
.array_type => |array_type| array_type.len,
else => 1,
},
else => Value.fromInterned(ptr.len).toUnsignedInt(mod),
.slice => |slice| Value.fromInterned(slice.len).toUnsignedInt(mod),
else => unreachable,
};
}
@@ -1636,6 +1628,7 @@ pub const Value = struct {
.undef => |ty| Value.fromInterned((try mod.intern(.{
.undef = Type.fromInterned(ty).elemType2(mod).toIntern(),
}))),
.slice => |slice| return Value.fromInterned(slice.ptr).maybeElemValue(mod, index),
.ptr => |ptr| switch (ptr.addr) {
.decl => |decl| mod.declPtr(decl).val.maybeElemValue(mod, index),
.anon_decl => |anon_decl| Value.fromInterned(anon_decl.val).maybeElemValue(mod, index),
@@ -1800,25 +1793,23 @@ pub const Value = struct {
) Allocator.Error!Value {
const elem_ty = elem_ptr_ty.childType(mod);
const ptr_val = switch (mod.intern_pool.indexToKey(val.toIntern())) {
.ptr => |ptr| ptr: {
switch (ptr.addr) {
.elem => |elem| if (Type.fromInterned(mod.intern_pool.typeOf(elem.base)).elemType2(mod).eql(elem_ty, mod))
return Value.fromInterned((try mod.intern(.{ .ptr = .{
.ty = elem_ptr_ty.toIntern(),
.addr = .{ .elem = .{
.base = elem.base,
.index = elem.index + index,
} },
} }))),
else => {},
}
break :ptr switch (ptr.len) {
.none => val,
else => val.slicePtr(mod),
};
},
.slice => |slice| Value.fromInterned(slice.ptr),
else => val,
};
switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {
.ptr => |ptr| switch (ptr.addr) {
.elem => |elem| if (Type.fromInterned(mod.intern_pool.typeOf(elem.base)).elemType2(mod).eql(elem_ty, mod))
return Value.fromInterned((try mod.intern(.{ .ptr = .{
.ty = elem_ptr_ty.toIntern(),
.addr = .{ .elem = .{
.base = elem.base,
.index = elem.index + index,
} },
} }))),
else => {},
},
else => {},
}
var ptr_ty_key = mod.intern_pool.indexToKey(elem_ptr_ty.toIntern()).ptr_type;
assert(ptr_ty_key.flags.size != .Slice);
ptr_ty_key.flags.size = .Many;
@@ -1850,12 +1841,9 @@ pub const Value = struct {
else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
.undef => true,
.simple_value => |v| v == .undefined,
.ptr => |ptr| switch (ptr.len) {
.none => false,
else => for (0..@as(usize, @intCast(Value.fromInterned(ptr.len).toUnsignedInt(mod)))) |index| {
if (try (try val.elemValue(mod, index)).anyUndef(mod)) break true;
} else false,
},
.slice => |slice| for (0..@intCast(Value.fromInterned(slice.len).toUnsignedInt(mod))) |idx| {
if (try (try val.elemValue(mod, idx)).anyUndef(mod)) break true;
} else false,
.aggregate => |aggregate| for (0..aggregate.storage.values().len) |i| {
const elem = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.values()[i];
if (try anyUndef(Value.fromInterned(elem), mod)) break true;