InternPool: fix more crashes

This commit is contained in:
Jacob Young 2023-05-26 03:41:35 -04:00 committed by Andrew Kelley
parent 66c4396854
commit f2c716187c
8 changed files with 502 additions and 448 deletions

View file

@ -650,8 +650,14 @@ pub const Key = union(enum) {
.enum_type => |enum_type| std.hash.autoHash(hasher, enum_type.decl),
.variable => |variable| std.hash.autoHash(hasher, variable.decl),
.extern_func => |extern_func| std.hash.autoHash(hasher, extern_func.decl),
.func => |func| std.hash.autoHash(hasher, func.index),
.extern_func => |extern_func| {
std.hash.autoHash(hasher, extern_func.ty);
std.hash.autoHash(hasher, extern_func.decl);
},
.func => |func| {
std.hash.autoHash(hasher, func.ty);
std.hash.autoHash(hasher, func.index);
},
.int => |int| {
// Canonicalize all integers by converting them to BigIntConst.
@ -854,11 +860,11 @@ pub const Key = union(enum) {
},
.extern_func => |a_info| {
const b_info = b.extern_func;
return a_info.decl == b_info.decl;
return a_info.ty == b_info.ty and a_info.decl == b_info.decl;
},
.func => |a_info| {
const b_info = b.func;
return a_info.index == b_info.index;
return a_info.ty == b_info.ty and a_info.index == b_info.index;
},
.ptr => |a_info| {
@ -1340,8 +1346,8 @@ pub const Index = enum(u32) {
float_c_longdouble_f128: struct { data: *Float128 },
float_comptime_float: struct { data: *Float128 },
variable: struct { data: *Variable },
extern_func: struct { data: void },
func: struct { data: void },
extern_func: struct { data: *Key.ExternFunc },
func: struct { data: *Key.Func },
only_possible_value: DataIsIndex,
union_value: struct { data: *Key.Union },
bytes: struct { data: *Bytes },
@ -3216,6 +3222,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.opt => |opt| {
assert(ip.isOptionalType(opt.ty));
assert(opt.val == .none or ip.indexToKey(opt.ty).opt_type == ip.typeOf(opt.val));
ip.items.appendAssumeCapacity(if (opt.val == .none) .{
.tag = .opt_null,
.data = @enumToInt(opt.ty),
@ -3226,23 +3233,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
},
.int => |int| b: {
switch (int.ty) {
.usize_type,
.isize_type,
.c_char_type,
.c_short_type,
.c_ushort_type,
.c_int_type,
.c_uint_type,
.c_long_type,
.c_ulong_type,
.c_longlong_type,
.c_ulonglong_type,
.c_longdouble_type,
.comptime_int_type,
=> {},
else => assert(ip.indexToKey(int.ty) == .int_type),
}
assert(ip.isIntegerType(int.ty));
switch (int.storage) {
.u64, .i64, .big_int => {},
.lazy_align, .lazy_size => |lazy_ty| {
@ -3425,13 +3416,16 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
}
},
.err => |err| ip.items.appendAssumeCapacity(.{
.tag = .error_set_error,
.data = try ip.addExtra(gpa, err),
}),
.err => |err| {
assert(ip.isErrorSetType(err.ty));
ip.items.appendAssumeCapacity(.{
.tag = .error_set_error,
.data = try ip.addExtra(gpa, err),
});
},
.error_union => |error_union| {
assert(ip.indexToKey(error_union.ty) == .error_union_type);
assert(ip.isErrorUnionType(error_union.ty));
ip.items.appendAssumeCapacity(switch (error_union.val) {
.err_name => |err_name| .{
.tag = .error_union_error,
@ -3456,9 +3450,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
}),
.enum_tag => |enum_tag| {
assert(enum_tag.ty != .none);
assert(enum_tag.int != .none);
assert(ip.isEnumType(enum_tag.ty));
assert(ip.indexToKey(enum_tag.int) == .int);
ip.items.appendAssumeCapacity(.{
.tag = .enum_tag,
.data = try ip.addExtra(gpa, enum_tag),
@ -4191,69 +4184,93 @@ pub fn sliceLen(ip: InternPool, i: Index) Index {
/// * identity coercion
/// * int <=> int
/// * int <=> enum
/// * enum_literal => enum
/// * ptr <=> ptr
/// * null_value => opt
/// * payload => opt
/// * error set <=> error set
/// * error union <=> error union
/// * error set => error union
/// * payload => error union
/// * fn <=> fn
pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
const old_ty = ip.typeOf(val);
if (old_ty == new_ty) return val;
switch (ip.indexToKey(val)) {
.int => |int| switch (ip.indexToKey(new_ty)) {
.simple_type => |simple_type| switch (simple_type) {
.usize,
.isize,
.c_char,
.c_short,
.c_ushort,
.c_int,
.c_uint,
.c_long,
.c_ulong,
.c_longlong,
.c_ulonglong,
.comptime_int,
=> return getCoercedInts(ip, gpa, int, new_ty),
else => {},
},
.int_type => return getCoercedInts(ip, gpa, int, new_ty),
.enum_type => return ip.get(gpa, .{ .enum_tag = .{
.extern_func => |extern_func| if (ip.isFunctionType(new_ty))
return ip.get(gpa, .{ .extern_func = .{
.ty = new_ty,
.decl = extern_func.decl,
.lib_name = extern_func.lib_name,
} }),
.func => |func| if (ip.isFunctionType(new_ty))
return ip.get(gpa, .{ .func = .{
.ty = new_ty,
.index = func.index,
} }),
.int => |int| if (ip.isIntegerType(new_ty))
return getCoercedInts(ip, gpa, int, new_ty)
else if (ip.isEnumType(new_ty))
return ip.get(gpa, .{ .enum_tag = .{
.ty = new_ty,
.int = val,
} }),
.enum_tag => |enum_tag| if (ip.isIntegerType(new_ty))
return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty),
.enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) {
.enum_type => |enum_type| {
const index = enum_type.nameIndex(ip, enum_literal).?;
return ip.get(gpa, .{ .enum_tag = .{
.ty = new_ty,
.int = if (enum_type.values.len != 0)
enum_type.values[index]
else
try ip.get(gpa, .{ .int = .{
.ty = enum_type.tag_ty,
.storage = .{ .u64 = index },
} }),
} });
},
else => {},
},
.enum_tag => |enum_tag| {
// 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 = .{
.ptr => |ptr| if (ip.isPointerType(new_ty))
return ip.get(gpa, .{ .ptr = .{
.ty = new_ty,
.addr = ptr.addr,
.len = ptr.len,
} }),
else => {},
},
.err => |err| switch (ip.indexToKey(new_ty)) {
.error_set_type, .inferred_error_set_type => return ip.get(gpa, .{ .err = .{
.err => |err| if (ip.isErrorSetType(new_ty))
return ip.get(gpa, .{ .err = .{
.ty = new_ty,
.name = err.name,
} })
else if (ip.isErrorUnionType(new_ty))
return ip.get(gpa, .{ .error_union = .{
.ty = new_ty,
.val = .{ .err_name = err.name },
} }),
.error_union => |error_union| if (ip.isErrorUnionType(new_ty))
return ip.get(gpa, .{ .error_union = .{
.ty = new_ty,
.val = error_union.val,
} }),
else => {},
},
else => {},
}
switch (ip.indexToKey(new_ty)) {
.opt_type => |child_ty| switch (val) {
.opt_type => |child_type| switch (val) {
.null_value => return ip.get(gpa, .{ .opt = .{
.ty = new_ty,
.val = .none,
} }),
else => return ip.get(gpa, .{ .opt = .{
.ty = new_ty,
.val = try ip.getCoerced(gpa, val, child_ty),
.val = try ip.getCoerced(gpa, val, child_type),
} }),
},
.error_union_type => |error_union_type| return ip.get(gpa, .{ .error_union = .{
.ty = new_ty,
.val = .{ .payload = try ip.getCoerced(gpa, val, error_union_type.payload_type) },
} }),
else => {},
}
if (std.debug.runtime_safety) {
@ -4271,33 +4288,24 @@ pub fn getCoercedInts(ip: *InternPool, gpa: Allocator, int: Key.Int, new_ty: Ind
// big_int storage, the limbs would be invalidated before they are read.
// Here we pre-reserve the limbs to ensure that the logic in `addInt` will
// not use an invalidated limbs pointer.
switch (int.storage) {
.u64 => |x| return ip.get(gpa, .{ .int = .{
.ty = new_ty,
.storage = .{ .u64 = x },
} }),
.i64 => |x| return ip.get(gpa, .{ .int = .{
.ty = new_ty,
.storage = .{ .i64 = x },
} }),
.big_int => |big_int| {
const new_storage: Key.Int.Storage = switch (int.storage) {
.u64, .i64, .lazy_align, .lazy_size => int.storage,
.big_int => |big_int| storage: {
const positive = big_int.positive;
const limbs = ip.limbsSliceToIndex(big_int.limbs);
// This line invalidates the limbs slice, but the indexes computed in the
// previous line are still correct.
try reserveLimbs(ip, gpa, @typeInfo(Int).Struct.fields.len + big_int.limbs.len);
return ip.get(gpa, .{ .int = .{
.ty = new_ty,
.storage = .{ .big_int = .{
.limbs = ip.limbsIndexToSlice(limbs),
.positive = positive,
} },
} });
break :storage .{ .big_int = .{
.limbs = ip.limbsIndexToSlice(limbs),
.positive = positive,
} };
},
.lazy_align, .lazy_size => unreachable,
}
};
return ip.get(gpa, .{ .int = .{
.ty = new_ty,
.storage = new_storage,
} });
}
pub fn indexToStructType(ip: InternPool, val: Index) Module.Struct.OptionalIndex {
@ -4345,25 +4353,68 @@ pub fn indexToInferredErrorSetType(ip: InternPool, val: Index) Module.Fn.Inferre
return @intToEnum(Module.Fn.InferredErrorSet.Index, datas[@enumToInt(val)]).toOptional();
}
/// includes .comptime_int_type
pub fn isIntegerType(ip: InternPool, ty: Index) bool {
return switch (ty) {
.usize_type,
.isize_type,
.c_char_type,
.c_short_type,
.c_ushort_type,
.c_int_type,
.c_uint_type,
.c_long_type,
.c_ulong_type,
.c_longlong_type,
.c_ulonglong_type,
.c_longdouble_type,
.comptime_int_type,
=> true,
else => ip.indexToKey(ty) == .int_type,
};
}
/// does not include .enum_literal_type
pub fn isEnumType(ip: InternPool, ty: Index) bool {
return switch (ty) {
.atomic_order_type,
.atomic_rmw_op_type,
.calling_convention_type,
.address_space_type,
.float_mode_type,
.reduce_op_type,
.call_modifier_type,
=> true,
else => ip.indexToKey(ty) == .enum_type,
};
}
pub fn isFunctionType(ip: InternPool, ty: Index) bool {
return ip.indexToKey(ty) == .func_type;
}
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,
return ip.indexToKey(ty) == .ptr_type;
}
pub fn isOptionalType(ip: InternPool, ty: Index) bool {
return ip.indexToKey(ty) == .opt_type;
}
/// includes .inferred_error_set_type
pub fn isErrorSetType(ip: InternPool, ty: Index) bool {
return ty == .anyerror_type or switch (ip.indexToKey(ty)) {
.error_set_type, .inferred_error_set_type => true,
else => false,
};
}
pub fn isOptionalType(ip: InternPool, ty: Index) bool {
const tags = ip.items.items(.tag);
if (ty == .none) return false;
return tags[@enumToInt(ty)] == .type_optional;
pub fn isInferredErrorSetType(ip: InternPool, ty: Index) bool {
return ip.indexToKey(ty) == .inferred_error_set_type;
}
pub fn isInferredErrorSetType(ip: InternPool, ty: Index) bool {
const tags = ip.items.items(.tag);
assert(ty != .none);
return tags[@enumToInt(ty)] == .type_inferred_error_set;
pub fn isErrorUnionType(ip: InternPool, ty: Index) bool {
return ip.indexToKey(ty) == .error_union_type;
}
/// The is only legal because the initializer is not part of the hash.

View file

@ -6699,6 +6699,11 @@ pub fn intern(mod: *Module, key: InternPool.Key) Allocator.Error!InternPool.Inde
return mod.intern_pool.get(mod.gpa, key);
}
/// Shortcut for calling `intern_pool.getCoerced`.
pub fn getCoerced(mod: *Module, val: Value, new_ty: Type) Allocator.Error!Value {
return (try mod.intern_pool.getCoerced(mod.gpa, val.toIntern(), new_ty.toIntern())).toValue();
}
pub fn intType(mod: *Module, signedness: std.builtin.Signedness, bits: u16) Allocator.Error!Type {
const i = try intern(mod, .{ .int_type = .{
.signedness = signedness,

View file

@ -7821,7 +7821,6 @@ fn resolveGenericInstantiationType(
const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst);
const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst, undefined) catch unreachable;
const new_func = new_func_val.getFunctionIndex(mod).unwrap().?;
errdefer mod.destroyFunc(new_func);
assert(new_func == new_module_func);
arg_i = 0;
@ -10793,7 +10792,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
check_range: {
if (operand_ty.zigTypeTag(mod) == .Int) {
const min_int = try operand_ty.minInt(mod);
const max_int = try operand_ty.maxIntScalar(mod, Type.comptime_int);
const max_int = try operand_ty.maxInt(mod, operand_ty);
if (try range_set.spans(min_int, max_int, operand_ty)) {
if (special_prong == .@"else") {
return sema.fail(
@ -11649,7 +11648,7 @@ const RangeSetUnhandledIterator = struct {
fn init(sema: *Sema, ty: Type, range_set: RangeSet) !RangeSetUnhandledIterator {
const mod = sema.mod;
const min = try ty.minInt(mod);
const max = try ty.maxIntScalar(mod, Type.comptime_int);
const max = try ty.maxInt(mod, ty);
return RangeSetUnhandledIterator{
.sema = sema,
@ -15964,25 +15963,24 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}
const args_val = v: {
const args_slice_ty = try mod.ptrType(.{
.elem_type = param_info_ty.toIntern(),
.size = .Slice,
.is_const = true,
const new_decl_ty = try mod.arrayType(.{
.len = param_vals.len,
.child = param_info_ty.toIntern(),
});
const new_decl = try params_anon_decl.finish(
try mod.arrayType(.{
.len = param_vals.len,
.child = param_info_ty.toIntern(),
.sentinel = .none,
}),
new_decl_ty,
(try mod.intern(.{ .aggregate = .{
.ty = args_slice_ty.toIntern(),
.ty = new_decl_ty.toIntern(),
.storage = .{ .elems = param_vals },
} })).toValue(),
0, // default alignment
);
break :v try mod.intern(.{ .ptr = .{
.ty = args_slice_ty.toIntern(),
.ty = (try mod.ptrType(.{
.elem_type = param_info_ty.toIntern(),
.size = .Slice,
.is_const = true,
})).toIntern(),
.addr = .{ .decl = new_decl },
.len = (try mod.intValue(Type.usize, param_vals.len)).toIntern(),
} });
@ -16214,7 +16212,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
};
return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
.ty = type_info_ty.toIntern(),
.tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Vector))).toIntern(),
.tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Optional))).toIntern(),
.val = try mod.intern(.{ .aggregate = .{
.ty = optional_field_ty.toIntern(),
.storage = .{ .elems = &field_values },
@ -16258,7 +16256,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const new_decl_ty = try mod.arrayType(.{
.len = name.len,
.child = .u8_type,
.sentinel = .zero_u8,
});
const new_decl = try anon_decl.finish(
new_decl_ty,
@ -16269,8 +16266,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
0, // default alignment
);
break :v try mod.intern(.{ .ptr = .{
.ty = .slice_const_u8_sentinel_0_type,
.ty = .slice_const_u8_type,
.addr = .{ .decl = new_decl },
.len = (try mod.intValue(Type.usize, name.len)).toIntern(),
} });
};
@ -16386,7 +16384,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const new_decl_ty = try mod.arrayType(.{
.len = name.len,
.child = .u8_type,
.sentinel = .zero_u8,
});
const new_decl = try anon_decl.finish(
new_decl_ty,
@ -16397,8 +16394,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
0, // default alignment
);
break :v try mod.intern(.{ .ptr = .{
.ty = .slice_const_u8_sentinel_0_type,
.ty = .slice_const_u8_type,
.addr = .{ .decl = new_decl },
.len = (try mod.intValue(Type.usize, name.len)).toIntern(),
} });
};
@ -16521,7 +16519,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const new_decl_ty = try mod.arrayType(.{
.len = name.len,
.child = .u8_type,
.sentinel = .zero_u8,
});
const new_decl = try anon_decl.finish(
new_decl_ty,
@ -16532,8 +16529,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
0, // default alignment
);
break :v try mod.intern(.{ .ptr = .{
.ty = .slice_const_u8_sentinel_0_type,
.ty = .slice_const_u8_type,
.addr = .{ .decl = new_decl },
.len = (try mod.intValue(Type.usize, name.len)).toIntern(),
} });
};
@ -16663,12 +16661,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const struct_type = switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) {
.anon_struct_type => |tuple| {
struct_field_vals = try gpa.alloc(InternPool.Index, tuple.types.len);
for (
tuple.types,
tuple.values,
struct_field_vals,
0..,
) |field_ty, field_val, *struct_field_val, i| {
for (struct_field_vals, 0..) |*struct_field_val, i| {
const anon_struct_type = mod.intern_pool.indexToKey(struct_ty.toIntern()).anon_struct_type;
const field_ty = anon_struct_type.types[i];
const field_val = anon_struct_type.values[i];
const name_val = v: {
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
@ -16735,7 +16731,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const new_decl_ty = try mod.arrayType(.{
.len = name.len,
.child = .u8_type,
.sentinel = .zero_u8,
});
const new_decl = try anon_decl.finish(
new_decl_ty,
@ -16746,7 +16741,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
0, // default alignment
);
break :v try mod.intern(.{ .ptr = .{
.ty = .slice_const_u8_sentinel_0_type,
.ty = .slice_const_u8_type,
.addr = .{ .decl = new_decl },
.len = (try mod.intValue(Type.usize, name.len)).toIntern(),
} });
@ -16975,7 +16970,6 @@ fn typeInfoNamespaceDecls(
const new_decl_ty = try mod.arrayType(.{
.len = name.len,
.child = .u8_type,
.sentinel = .zero_u8,
});
const new_decl = try anon_decl.finish(
new_decl_ty,
@ -16986,7 +16980,7 @@ fn typeInfoNamespaceDecls(
0, // default alignment
);
break :v try mod.intern(.{ .ptr = .{
.ty = .slice_const_u8_sentinel_0_type,
.ty = .slice_const_u8_type,
.addr = .{ .decl = new_decl },
.len = (try mod.intValue(Type.usize, name.len)).toIntern(),
} });
@ -20404,7 +20398,7 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
.val = operand_val.toIntern(),
} })).toValue());
}
return sema.addConstant(aligned_dest_ty, operand_val);
return sema.addConstant(aligned_dest_ty, try mod.getCoerced(operand_val, aligned_dest_ty));
}
try sema.requireRuntimeBlock(block, src, null);
@ -22401,7 +22395,7 @@ fn analyzeMinMax(
if (std.debug.runtime_safety) {
assert(try sema.intFitsInType(val, refined_ty, null));
}
cur_minmax = try sema.addConstant(refined_ty, val);
cur_minmax = try sema.addConstant(refined_ty, try mod.getCoerced(val, refined_ty));
}
break :refined refined_ty;
@ -22459,8 +22453,8 @@ fn analyzeMinMax(
else => unreachable,
};
const max_val = switch (air_tag) {
.min => try comptime_elem_ty.maxInt(mod, Type.comptime_int), // @min(ct, rt) <= ct
.max => try unrefined_elem_ty.maxInt(mod, Type.comptime_int),
.min => try comptime_elem_ty.maxInt(mod, comptime_elem_ty), // @min(ct, rt) <= ct
.max => try unrefined_elem_ty.maxInt(mod, unrefined_elem_ty),
else => unreachable,
};
@ -23356,11 +23350,14 @@ fn zirBuiltinExtern(
try mod.declareDeclDependency(sema.owner_decl_index, new_decl_index);
try sema.ensureDeclAnalyzed(new_decl_index);
const ref = try mod.intern(.{ .ptr = .{
.ty = (try mod.singleConstPtrType(ty)).toIntern(),
return sema.addConstant(ty, try mod.getCoerced((try mod.intern(.{ .ptr = .{
.ty = switch (mod.intern_pool.indexToKey(ty.toIntern())) {
.ptr_type => ty.toIntern(),
.opt_type => |child_type| child_type,
else => unreachable,
},
.addr = .{ .decl = new_decl_index },
} });
return sema.addConstant(ty, ref.toValue());
} })).toValue(), ty));
}
fn zirWorkItem(
@ -25887,13 +25884,7 @@ fn coerceExtra(
var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
if (in_memory_result == .ok) {
if (maybe_inst_val) |val| {
if (val.ip_index == .none) {
// Keep the comptime Value representation; take the new type.
return sema.addConstant(dest_ty, val);
} else {
const new_val = try mod.intern_pool.getCoerced(sema.gpa, val.toIntern(), dest_ty.toIntern());
return sema.addConstant(dest_ty, new_val.toValue());
}
return sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty));
}
try sema.requireRuntimeBlock(block, inst_src, null);
return block.addBitCast(dest_ty, inst);
@ -26269,8 +26260,7 @@ fn coerceExtra(
if (!opts.report_err) return error.NotCoercible;
return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
}
const new_val = try mod.intern_pool.getCoerced(sema.gpa, val.toIntern(), dest_ty.toIntern());
return try sema.addConstant(dest_ty, new_val.toValue());
return try sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty));
}
if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
if (!opts.report_err) return error.NotCoercible;
@ -27222,68 +27212,84 @@ fn coerceInMemoryAllowedFns(
src_src: LazySrcLoc,
) !InMemoryCoercionResult {
const mod = sema.mod;
const dest_info = mod.typeToFunc(dest_ty).?;
const src_info = mod.typeToFunc(src_ty).?;
if (dest_info.is_var_args != src_info.is_var_args) {
return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args };
}
{
const dest_info = mod.typeToFunc(dest_ty).?;
const src_info = mod.typeToFunc(src_ty).?;
if (dest_info.is_generic != src_info.is_generic) {
return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };
}
if (dest_info.is_var_args != src_info.is_var_args) {
return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args };
}
if (dest_info.cc != src_info.cc) {
return InMemoryCoercionResult{ .fn_cc = .{
.actual = src_info.cc,
.wanted = dest_info.cc,
} };
}
if (dest_info.is_generic != src_info.is_generic) {
return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };
}
if (src_info.return_type != .noreturn_type) {
const rt = try sema.coerceInMemoryAllowed(block, dest_info.return_type.toType(), src_info.return_type.toType(), false, target, dest_src, src_src);
if (rt != .ok) {
return InMemoryCoercionResult{ .fn_return_type = .{
.child = try rt.dupe(sema.arena),
.actual = src_info.return_type.toType(),
.wanted = dest_info.return_type.toType(),
if (dest_info.cc != src_info.cc) {
return InMemoryCoercionResult{ .fn_cc = .{
.actual = src_info.cc,
.wanted = dest_info.cc,
} };
}
if (src_info.return_type != .noreturn_type) {
const dest_return_type = dest_info.return_type.toType();
const src_return_type = src_info.return_type.toType();
const rt = try sema.coerceInMemoryAllowed(block, dest_return_type, src_return_type, false, target, dest_src, src_src);
if (rt != .ok) {
return InMemoryCoercionResult{ .fn_return_type = .{
.child = try rt.dupe(sema.arena),
.actual = dest_return_type,
.wanted = src_return_type,
} };
}
}
}
if (dest_info.param_types.len != src_info.param_types.len) {
return InMemoryCoercionResult{ .fn_param_count = .{
.actual = src_info.param_types.len,
.wanted = dest_info.param_types.len,
} };
}
const params_len = params_len: {
const dest_info = mod.typeToFunc(dest_ty).?;
const src_info = mod.typeToFunc(src_ty).?;
if (dest_info.noalias_bits != src_info.noalias_bits) {
return InMemoryCoercionResult{ .fn_param_noalias = .{
.actual = src_info.noalias_bits,
.wanted = dest_info.noalias_bits,
} };
}
if (dest_info.param_types.len != src_info.param_types.len) {
return InMemoryCoercionResult{ .fn_param_count = .{
.actual = src_info.param_types.len,
.wanted = dest_info.param_types.len,
} };
}
for (dest_info.param_types, 0..) |dest_param_ty, i| {
const src_param_ty = src_info.param_types[i].toType();
if (dest_info.noalias_bits != src_info.noalias_bits) {
return InMemoryCoercionResult{ .fn_param_noalias = .{
.actual = src_info.noalias_bits,
.wanted = dest_info.noalias_bits,
} };
}
const i_small = @intCast(u5, i);
if (dest_info.paramIsComptime(i_small) != src_info.paramIsComptime(i_small)) {
break :params_len dest_info.param_types.len;
};
for (0..params_len) |param_i| {
const dest_info = mod.typeToFunc(dest_ty).?;
const src_info = mod.typeToFunc(src_ty).?;
const dest_param_ty = dest_info.param_types[param_i].toType();
const src_param_ty = src_info.param_types[param_i].toType();
const param_i_small = @intCast(u5, param_i);
if (dest_info.paramIsComptime(param_i_small) != src_info.paramIsComptime(param_i_small)) {
return InMemoryCoercionResult{ .fn_param_comptime = .{
.index = i,
.wanted = dest_info.paramIsComptime(i_small),
.index = param_i,
.wanted = dest_info.paramIsComptime(param_i_small),
} };
}
// Note: Cast direction is reversed here.
const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty.toType(), false, target, dest_src, src_src);
const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src);
if (param != .ok) {
return InMemoryCoercionResult{ .fn_param = .{
.child = try param.dupe(sema.arena),
.actual = src_param_ty,
.wanted = dest_param_ty.toType(),
.index = i,
.wanted = dest_param_ty,
.index = param_i,
} };
}
}
@ -28385,7 +28391,7 @@ fn beginComptimePtrLoad(
};
},
.elem => |elem_ptr| blk: {
const elem_ty = ptr.ty.toType().childType(mod);
const elem_ty = ptr.ty.toType().elemType2(mod);
var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.base.toValue(), null);
// This code assumes that elem_ptrs have been "flattened" in order for direct dereference
@ -28678,11 +28684,10 @@ fn coerceCompatiblePtrs(
return sema.fail(block, inst_src, "null pointer casted to type '{}'", .{dest_ty.fmt(sema.mod)});
}
// The comptime Value representation is compatible with both types.
return sema.addConstant(dest_ty, (try mod.intern_pool.getCoerced(
sema.gpa,
try val.intern(inst_ty, mod),
dest_ty.toIntern(),
)).toValue());
return sema.addConstant(
dest_ty,
try mod.getCoerced((try val.intern(inst_ty, mod)).toValue(), dest_ty),
);
}
try sema.requireRuntimeBlock(block, inst_src, null);
const inst_allows_zero = inst_ty.zigTypeTag(mod) != .Pointer or inst_ty.ptrAllowsZero(mod);
@ -29390,9 +29395,13 @@ fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value {
fn optRefValue(sema: *Sema, block: *Block, ty: Type, opt_val: ?Value) !Value {
const mod = sema.mod;
const ptr_anyopaque_ty = try mod.singleConstPtrType(Type.anyopaque);
return (try mod.intern(.{ .opt = .{
.ty = (try mod.optionalType((try mod.singleConstPtrType(Type.anyopaque)).toIntern())).toIntern(),
.val = if (opt_val) |val| (try sema.refValue(block, ty, val)).toIntern() else .none,
.ty = (try mod.optionalType(ptr_anyopaque_ty.toIntern())).toIntern(),
.val = if (opt_val) |val| (try mod.getCoerced(
try sema.refValue(block, ty, val),
ptr_anyopaque_ty,
)).toIntern() else .none,
} })).toValue();
}
@ -30051,11 +30060,10 @@ fn analyzeSlice(
};
if (!new_ptr_val.isUndef(mod)) {
return sema.addConstant(return_ty, (try mod.intern_pool.getCoerced(
sema.gpa,
try new_ptr_val.intern(new_ptr_ty, mod),
return_ty.toIntern(),
)).toValue());
return sema.addConstant(return_ty, try mod.getCoerced(
(try new_ptr_val.intern(new_ptr_ty, mod)).toValue(),
return_ty,
));
}
// Special case: @as([]i32, undefined)[x..x]
@ -34237,9 +34245,9 @@ fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {
// The `tagValueIndex` function call below relies on the type being the integer tag type.
// `getCoerced` assumes the value will fit the new type.
if (!(try sema.intFitsInType(int, enum_type.tag_ty.toType(), null))) return false;
const int_coerced = try mod.intern_pool.getCoerced(sema.gpa, int.toIntern(), enum_type.tag_ty);
const int_coerced = try mod.getCoerced(int, enum_type.tag_ty.toType());
return enum_type.tagValueIndex(&mod.intern_pool, int_coerced) != null;
return enum_type.tagValueIndex(&mod.intern_pool, int_coerced.toIntern()) != null;
}
fn intAddWithOverflow(

View file

@ -185,7 +185,7 @@ pub fn generateSymbol(
const mod = bin_file.options.module.?;
var typed_value = arg_tv;
switch (mod.intern_pool.indexToKey(typed_value.val.ip_index)) {
switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) {
.runtime_value => |rt| typed_value.val = rt.val.toValue(),
else => {},
}
@ -204,7 +204,7 @@ pub fn generateSymbol(
return .ok;
}
switch (mod.intern_pool.indexToKey(typed_value.val.ip_index)) {
switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) {
.int_type,
.ptr_type,
.array_type,
@ -282,7 +282,7 @@ pub fn generateSymbol(
switch (try generateSymbol(bin_file, src_loc, .{
.ty = payload_ty,
.val = switch (error_union.val) {
.err_name => try mod.intern(.{ .undef = payload_ty.ip_index }),
.err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }),
.payload => |payload| payload,
}.toValue(),
}, code, debug_output, reloc_info)) {
@ -315,7 +315,7 @@ pub fn generateSymbol(
const int_tag_ty = try typed_value.ty.intTagType(mod);
switch (try generateSymbol(bin_file, src_loc, .{
.ty = int_tag_ty,
.val = (try mod.intern_pool.getCoerced(mod.gpa, enum_tag.int, int_tag_ty.ip_index)).toValue(),
.val = try mod.getCoerced(enum_tag.int.toValue(), int_tag_ty),
}, code, debug_output, reloc_info)) {
.ok => {},
.fail => |em| return .{ .fail = em },
@ -337,7 +337,7 @@ pub fn generateSymbol(
switch (try lowerParentPtr(bin_file, src_loc, switch (ptr.len) {
.none => typed_value.val,
else => typed_value.val.slicePtr(mod),
}.ip_index, code, debug_output, reloc_info)) {
}.toIntern(), code, debug_output, reloc_info)) {
.ok => {},
.fail => |em| return .{ .fail = em },
}
@ -372,7 +372,7 @@ pub fn generateSymbol(
} else {
const padding = abi_size - (math.cast(usize, payload_type.abiSize(mod)) orelse return error.Overflow) - 1;
if (payload_type.hasRuntimeBits(mod)) {
const value = payload_val orelse (try mod.intern(.{ .undef = payload_type.ip_index })).toValue();
const value = payload_val orelse (try mod.intern(.{ .undef = payload_type.toIntern() })).toValue();
switch (try generateSymbol(bin_file, src_loc, .{
.ty = payload_type,
.val = value,
@ -385,7 +385,7 @@ pub fn generateSymbol(
try code.writer().writeByteNTimes(0, padding);
}
},
.aggregate => |aggregate| switch (mod.intern_pool.indexToKey(typed_value.ty.ip_index)) {
.aggregate => |aggregate| switch (mod.intern_pool.indexToKey(typed_value.ty.toIntern())) {
.array_type => |array_type| {
var index: u64 = 0;
while (index < array_type.len) : (index += 1) {
@ -850,7 +850,7 @@ pub fn genTypedValue(
) CodeGenError!GenResult {
const mod = bin_file.options.module.?;
var typed_value = arg_tv;
switch (mod.intern_pool.indexToKey(typed_value.val.ip_index)) {
switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) {
.runtime_value => |rt| typed_value.val = rt.val.toValue(),
else => {},
}
@ -866,7 +866,7 @@ pub fn genTypedValue(
const target = bin_file.options.target;
const ptr_bits = target.ptrBitWidth();
if (!typed_value.ty.isSlice(mod)) switch (mod.intern_pool.indexToKey(typed_value.val.ip_index)) {
if (!typed_value.ty.isSlice(mod)) switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) {
.ptr => |ptr| switch (ptr.addr) {
.decl => |decl| return genDeclRef(bin_file, src_loc, typed_value, decl),
.mut_decl => |mut_decl| return genDeclRef(bin_file, src_loc, typed_value, mut_decl.decl),
@ -879,12 +879,12 @@ pub fn genTypedValue(
.Void => return GenResult.mcv(.none),
.Pointer => switch (typed_value.ty.ptrSize(mod)) {
.Slice => {},
else => switch (typed_value.val.ip_index) {
else => switch (typed_value.val.toIntern()) {
.null_value => {
return GenResult.mcv(.{ .immediate = 0 });
},
.none => {},
else => switch (mod.intern_pool.indexToKey(typed_value.val.ip_index)) {
else => switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) {
.int => {
return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(mod) });
},
@ -916,7 +916,7 @@ pub fn genTypedValue(
}
},
.Enum => {
const enum_tag = mod.intern_pool.indexToKey(typed_value.val.ip_index).enum_tag;
const enum_tag = mod.intern_pool.indexToKey(typed_value.val.toIntern()).enum_tag;
const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int);
return genTypedValue(bin_file, src_loc, .{
.ty = int_tag_ty.toType(),
@ -924,7 +924,9 @@ pub fn genTypedValue(
}, owner_decl_index);
},
.ErrorSet => {
const err_name = mod.intern_pool.stringToSlice(mod.intern_pool.indexToKey(typed_value.val.ip_index).err.name);
const err_name = mod.intern_pool.stringToSlice(
mod.intern_pool.indexToKey(typed_value.val.toIntern()).err.name,
);
const global_error_set = mod.global_error_set;
const error_index = global_error_set.get(err_name).?;
return GenResult.mcv(.{ .immediate = error_index });

View file

@ -2329,7 +2329,7 @@ pub const Object = struct {
try param_di_types.append(try o.lowerDebugType(ptr_ty, .full));
}
for (fn_info.param_types) |param_ty| {
for (mod.typeToFunc(ty).?.param_types) |param_ty| {
if (!param_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
if (isByRef(param_ty.toType(), mod)) {

File diff suppressed because it is too large Load diff

View file

@ -345,7 +345,7 @@ pub const Value = struct {
}
pub fn intern(val: Value, ty: Type, mod: *Module) Allocator.Error!InternPool.Index {
if (val.ip_index != .none) return mod.intern_pool.getCoerced(mod.gpa, val.toIntern(), ty.toIntern());
if (val.ip_index != .none) return (try mod.getCoerced(val, ty)).toIntern();
switch (val.tag()) {
.eu_payload => {
const pl = val.castTag(.eu_payload).?.data;
@ -506,11 +506,7 @@ pub const Value = struct {
else => unreachable,
};
},
.enum_type => |enum_type| (try ip.getCoerced(
mod.gpa,
val.toIntern(),
enum_type.tag_ty,
)).toValue(),
.enum_type => |enum_type| try mod.getCoerced(val, enum_type.tag_ty.toType()),
else => unreachable,
};
}
@ -872,10 +868,15 @@ pub const Value = struct {
.Packed => {
var bits: u16 = 0;
const fields = ty.structFields(mod).values();
const field_vals = val.castTag(.aggregate).?.data;
const storage = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage;
for (fields, 0..) |field, i| {
const field_bits = @intCast(u16, field.ty.bitSize(mod));
try field_vals[i].writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits);
const field_val = switch (storage) {
.bytes => unreachable,
.elems => |elems| elems[i],
.repeated_elem => |elem| elem,
};
try field_val.toValue().writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits);
bits += field_bits;
}
},
@ -2006,23 +2007,30 @@ pub const Value = struct {
}
pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool {
return val.ip_index != .none and switch (mod.intern_pool.indexToKey(val.toIntern())) {
.variable => false,
else => val.isPtrToThreadLocalInner(mod),
};
}
pub fn isPtrToThreadLocalInner(val: Value, mod: *Module) bool {
return val.ip_index != .none and switch (mod.intern_pool.indexToKey(val.toIntern())) {
.variable => |variable| variable.is_threadlocal,
.ptr => |ptr| switch (ptr.addr) {
.decl => |decl_index| {
const decl = mod.declPtr(decl_index);
assert(decl.has_tv);
return decl.val.isPtrToThreadLocal(mod);
return decl.val.isPtrToThreadLocalInner(mod);
},
.mut_decl => |mut_decl| {
const decl = mod.declPtr(mut_decl.decl);
assert(decl.has_tv);
return decl.val.isPtrToThreadLocal(mod);
return decl.val.isPtrToThreadLocalInner(mod);
},
.int => false,
.eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isPtrToThreadLocal(mod),
.comptime_field => |comptime_field| comptime_field.toValue().isPtrToThreadLocal(mod),
.elem, .field => |base_index| base_index.base.toValue().isPtrToThreadLocal(mod),
.eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isPtrToThreadLocalInner(mod),
.comptime_field => |comptime_field| comptime_field.toValue().isPtrToThreadLocalInner(mod),
.elem, .field => |base_index| base_index.base.toValue().isPtrToThreadLocalInner(mod),
},
else => false,
};
@ -2045,7 +2053,18 @@ pub const Value = struct {
else => unreachable,
},
.aggregate => |aggregate| (try mod.intern(.{ .aggregate = .{
.ty = mod.intern_pool.typeOf(val.toIntern()),
.ty = switch (mod.intern_pool.indexToKey(mod.intern_pool.typeOf(val.toIntern()))) {
.array_type => |array_type| try mod.arrayType(.{
.len = @intCast(u32, end - start),
.child = array_type.child,
.sentinel = if (end == array_type.len) array_type.sentinel else .none,
}),
.vector_type => |vector_type| try mod.vectorType(.{
.len = @intCast(u32, end - start),
.child = vector_type.child,
}),
else => unreachable,
}.toIntern(),
.storage = switch (aggregate.storage) {
.bytes => |bytes| .{ .bytes = bytes[start..end] },
.elems => |elems| .{ .elems = elems[start..end] },

View file

@ -347,9 +347,15 @@ class TagAndPayload_SynthProvider:
except: return -1
def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index in range(2) else None
def Inst_Ref_SummaryProvider(value, _=None):
def Zir_Inst__Zir_Inst_Ref_SummaryProvider(value, _=None):
members = value.type.enum_members
return value if any(value.unsigned == member.unsigned for member in members) else 'instructions[%d]' % (value.unsigned - len(members))
# ignore .var_args_param_type and .none
return value if any(value.unsigned == member.unsigned for member in members) else 'instructions[%d]' % (value.unsigned + 2 - len(members))
def Air_Inst__Air_Inst_Ref_SummaryProvider(value, _=None):
members = value.type.enum_members
# ignore .none
return value if any(value.unsigned == member.unsigned for member in members) else 'instructions[%d]' % (value.unsigned + 1 - len(members))
class Module_Decl__Module_Decl_Index_SynthProvider:
def __init__(self, value, _=None): self.value = value
@ -676,8 +682,9 @@ def __lldb_init_module(debugger, _=None):
add(debugger, category='zig.stage2', type='Zir.Inst', identifier='TagAndPayload', synth=True, inline_children=True, summary=True)
add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Zir\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True)
add(debugger, category='zig.stage2', regex=True, type='^Zir\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True)
add(debugger, category='zig.stage2', type='Zir.Inst::Zir.Inst.Ref', identifier='Inst_Ref', summary=True)
add(debugger, category='zig.stage2', type='Zir.Inst::Zir.Inst.Ref', summary=True)
add(debugger, category='zig.stage2', type='Air.Inst', identifier='TagAndPayload', synth=True, inline_children=True, summary=True)
add(debugger, category='zig.stage2', type='Air.Inst::Air.Inst.Ref', summary=True)
add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Air\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True)
add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True)
add(debugger, category='zig.stage2', type='Module.Decl::Module.Decl.Index', synth=True)