Sema: fix in-memory coercion during comptime load

This commit is contained in:
Jacob Young 2023-06-01 21:03:53 -04:00 committed by Andrew Kelley
parent dc18739a73
commit e8bcdca044
2 changed files with 29 additions and 16 deletions

View File

@ -22472,9 +22472,7 @@ fn analyzeMinMax(
if (std.debug.runtime_safety) { if (std.debug.runtime_safety) {
assert(try sema.intFitsInType(val, refined_ty, null)); assert(try sema.intFitsInType(val, refined_ty, null));
} }
cur_minmax = try sema.addConstant(refined_ty, (try sema.resolveMaybeUndefVal( cur_minmax = try sema.coerceInMemory(block, val, orig_ty, refined_ty, src);
try sema.coerceInMemory(block, val, orig_ty, refined_ty, src),
)).?);
} }
break :refined refined_ty; break :refined refined_ty;
@ -26659,16 +26657,16 @@ fn coerceExtra(
return sema.failWithOwnedErrorMsg(msg); return sema.failWithOwnedErrorMsg(msg);
} }
fn coerceInMemory( fn coerceValueInMemory(
sema: *Sema, sema: *Sema,
block: *Block, block: *Block,
val: Value, val: Value,
src_ty: Type, src_ty: Type,
dst_ty: Type, dst_ty: Type,
dst_ty_src: LazySrcLoc, dst_ty_src: LazySrcLoc,
) CompileError!Air.Inst.Ref { ) CompileError!Value {
const mod = sema.mod; const mod = sema.mod;
switch (mod.intern_pool.indexToKey(val.toIntern())) { return switch (mod.intern_pool.indexToKey(val.toIntern())) {
.aggregate => |aggregate| { .aggregate => |aggregate| {
const dst_ty_key = mod.intern_pool.indexToKey(dst_ty.toIntern()); const dst_ty_key = mod.intern_pool.indexToKey(dst_ty.toIntern());
const dest_len = try sema.usizeCast( const dest_len = try sema.usizeCast(
@ -26688,14 +26686,14 @@ fn coerceInMemory(
else => unreachable, else => unreachable,
}; };
if (src_ty_child != dst_ty_child) break :direct; if (src_ty_child != dst_ty_child) break :direct;
return try sema.addConstant(dst_ty, (try mod.intern(.{ .aggregate = .{ return (try mod.intern(.{ .aggregate = .{
.ty = dst_ty.toIntern(), .ty = dst_ty.toIntern(),
.storage = switch (aggregate.storage) { .storage = switch (aggregate.storage) {
.bytes => |bytes| .{ .bytes = bytes[0..dest_len] }, .bytes => |bytes| .{ .bytes = bytes[0..dest_len] },
.elems => |elems| .{ .elems = elems[0..dest_len] }, .elems => |elems| .{ .elems = elems[0..dest_len] },
.repeated_elem => |elem| .{ .repeated_elem = elem }, .repeated_elem => |elem| .{ .repeated_elem = elem },
}, },
} })).toValue()); } })).toValue();
} }
const dest_elems = try sema.arena.alloc(InternPool.Index, dest_len); const dest_elems = try sema.arena.alloc(InternPool.Index, dest_len);
for (dest_elems, 0..) |*dest_elem, i| { for (dest_elems, 0..) |*dest_elem, i| {
@ -26712,17 +26710,28 @@ fn coerceInMemory(
.repeated_elem => |elem| elem, .repeated_elem => |elem| elem,
}, elem_ty); }, elem_ty);
} }
return sema.addConstant(dst_ty, (try mod.intern(.{ .aggregate = .{ return (try mod.intern(.{ .aggregate = .{
.ty = dst_ty.toIntern(), .ty = dst_ty.toIntern(),
.storage = .{ .elems = dest_elems }, .storage = .{ .elems = dest_elems },
} })).toValue()); } })).toValue();
}, },
.float => |float| return sema.addConstant(dst_ty, (try mod.intern(.{ .float = .{ .float => |float| (try mod.intern(.{ .float = .{
.ty = dst_ty.toIntern(), .ty = dst_ty.toIntern(),
.storage = float.storage, .storage = float.storage,
} })).toValue()), } })).toValue(),
else => return sema.addConstant(dst_ty, try mod.getCoerced(val, dst_ty)), else => try mod.getCoerced(val, dst_ty),
};
} }
fn coerceInMemory(
sema: *Sema,
block: *Block,
val: Value,
src_ty: Type,
dst_ty: Type,
dst_ty_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
return sema.addConstant(dst_ty, try sema.coerceValueInMemory(block, val, src_ty, dst_ty, dst_ty_src));
} }
const InMemoryCoercionResult = union(enum) { const InMemoryCoercionResult = union(enum) {
@ -33935,8 +33944,11 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value
if (coerce_in_mem_ok) { if (coerce_in_mem_ok) {
// We have a Value that lines up in virtual memory exactly with what we want to load, // We have a Value that lines up in virtual memory exactly with what we want to load,
// and it is in-memory coercible to load_ty. It may be returned without modifications. // and it is in-memory coercible to load_ty. It may be returned without modifications.
// Move mutable decl values to the InternPool and assert other decls are already in the InternPool. // Move mutable decl values to the InternPool and assert other decls are already in
return .{ .val = (if (deref.is_mutable) try tv.val.intern(tv.ty, mod) else tv.val.toIntern()).toValue() }; // the InternPool.
const uncoerced_val = if (deref.is_mutable) try tv.val.intern(tv.ty, mod) else tv.val.toIntern();
const coerced_val = try sema.coerceValueInMemory(block, uncoerced_val.toValue(), tv.ty, load_ty, src);
return .{ .val = coerced_val };
} }
} }

View File

@ -1842,6 +1842,7 @@ pub const Value = struct {
pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value { pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value {
return switch (val.ip_index) { return switch (val.ip_index) {
.none => switch (val.tag()) { .none => switch (val.tag()) {
.bytes => try mod.intValue(Type.u8, val.castTag(.bytes).?.data[index]),
.repeated => val.castTag(.repeated).?.data, .repeated => val.castTag(.repeated).?.data,
.aggregate => val.castTag(.aggregate).?.data[index], .aggregate => val.castTag(.aggregate).?.data[index],
.slice => val.castTag(.slice).?.data.ptr.elemValue(mod, index), .slice => val.castTag(.slice).?.data.ptr.elemValue(mod, index),