mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 12:27:41 +00:00
stage2: bug fixes related to Type/Value/InternPool
This commit is contained in:
parent
8699cdc3df
commit
a5fb169594
68
src/Sema.zig
68
src/Sema.zig
@ -1746,8 +1746,9 @@ pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
|
||||
if (i < InternPool.static_len) return @intToEnum(Air.Inst.Ref, i);
|
||||
// The last section of indexes refers to the map of ZIR => AIR.
|
||||
const inst = sema.inst_map.get(i - InternPool.static_len).?;
|
||||
if (inst == .generic_poison) return error.GenericPoison;
|
||||
const ty = sema.typeOf(inst);
|
||||
if (ty.isGenericPoison()) return error.GenericPoison;
|
||||
assert(!ty.isGenericPoison());
|
||||
return inst;
|
||||
}
|
||||
|
||||
@ -2000,7 +2001,7 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime(
|
||||
.constant => {
|
||||
const ty_pl = air_datas[i].ty_pl;
|
||||
const val = sema.air_values.items[ty_pl.payload];
|
||||
if (val.tag() == .runtime_value) make_runtime.* = true;
|
||||
if (val.isRuntimeValue()) make_runtime.* = true;
|
||||
if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true;
|
||||
return val;
|
||||
},
|
||||
@ -9688,7 +9689,7 @@ fn intCast(
|
||||
// range shrinkage
|
||||
// requirement: int value fits into target type
|
||||
if (wanted_value_bits < actual_value_bits) {
|
||||
const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod);
|
||||
const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod, operand_ty);
|
||||
const dest_max_val = if (is_vector)
|
||||
try Value.Tag.repeated.create(sema.arena, dest_max_val_scalar)
|
||||
else
|
||||
@ -10831,7 +10832,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
defer arena.deinit();
|
||||
|
||||
const min_int = try operand_ty.minInt(arena.allocator(), mod);
|
||||
const max_int = try operand_ty.maxIntScalar(mod);
|
||||
const max_int = try operand_ty.maxIntScalar(mod, Type.comptime_int);
|
||||
if (try range_set.spans(min_int, max_int, operand_ty)) {
|
||||
if (special_prong == .@"else") {
|
||||
return sema.fail(
|
||||
@ -11683,7 +11684,7 @@ const RangeSetUnhandledIterator = struct {
|
||||
fn init(sema: *Sema, ty: Type, range_set: RangeSet) !RangeSetUnhandledIterator {
|
||||
const mod = sema.mod;
|
||||
const min = try ty.minInt(sema.arena, mod);
|
||||
const max = try ty.maxIntScalar(mod);
|
||||
const max = try ty.maxIntScalar(mod, Type.comptime_int);
|
||||
|
||||
return RangeSetUnhandledIterator{
|
||||
.sema = sema,
|
||||
@ -12294,7 +12295,7 @@ fn zirShl(
|
||||
{
|
||||
const max_int = try sema.addConstant(
|
||||
lhs_ty,
|
||||
try lhs_ty.maxInt(sema.arena, mod),
|
||||
try lhs_ty.maxInt(sema.arena, mod, lhs_ty),
|
||||
);
|
||||
const rhs_limited = try sema.analyzeMinMax(block, rhs_src, .min, &.{ rhs, max_int }, &.{ rhs_src, rhs_src });
|
||||
break :rhs try sema.intCast(block, src, lhs_ty, rhs_src, rhs_limited, rhs_src, false);
|
||||
@ -16503,7 +16504,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
else
|
||||
try std.fmt.allocPrintZ(anon_decl.arena(), "{d}", .{i});
|
||||
const new_decl = try anon_decl.finish(
|
||||
try Type.array(anon_decl.arena(), bytes.len, try mod.intValue(Type.u8, 0), Type.u8, mod),
|
||||
try Type.array(anon_decl.arena(), bytes.len, Value.zero_u8, Type.u8, mod),
|
||||
try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
|
||||
0, // default alignment
|
||||
);
|
||||
@ -22202,8 +22203,8 @@ fn analyzeMinMax(
|
||||
else => unreachable,
|
||||
};
|
||||
const max_val = switch (air_tag) {
|
||||
.min => try comptime_elem_ty.maxInt(sema.arena, mod), // @min(ct, rt) <= ct
|
||||
.max => try unrefined_elem_ty.maxInt(sema.arena, mod),
|
||||
.min => try comptime_elem_ty.maxInt(sema.arena, mod, Type.comptime_int), // @min(ct, rt) <= ct
|
||||
.max => try unrefined_elem_ty.maxInt(sema.arena, mod, Type.comptime_int),
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
@ -27931,33 +27932,32 @@ fn beginComptimePtrMutation(
|
||||
switch (parent.pointee) {
|
||||
.direct => |val_ptr| {
|
||||
const payload_ty = parent.ty.errorUnionPayload();
|
||||
switch (val_ptr.tag()) {
|
||||
else => {
|
||||
// An error union has been initialized to undefined at comptime and now we
|
||||
// are for the first time setting the payload. We must change the
|
||||
// representation of the error union from `undef` to `opt_payload`.
|
||||
const arena = parent.beginArena(sema.mod);
|
||||
defer parent.finishArena(sema.mod);
|
||||
|
||||
const payload = try arena.create(Value.Payload.SubValue);
|
||||
payload.* = .{
|
||||
.base = .{ .tag = .eu_payload },
|
||||
.data = Value.undef,
|
||||
};
|
||||
|
||||
val_ptr.* = Value.initPayload(&payload.base);
|
||||
|
||||
return ComptimePtrMutationKit{
|
||||
.decl_ref_mut = parent.decl_ref_mut,
|
||||
.pointee = .{ .direct = &payload.data },
|
||||
.ty = payload_ty,
|
||||
};
|
||||
},
|
||||
.eu_payload => return ComptimePtrMutationKit{
|
||||
if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) {
|
||||
return ComptimePtrMutationKit{
|
||||
.decl_ref_mut = parent.decl_ref_mut,
|
||||
.pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data },
|
||||
.ty = payload_ty,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// An error union has been initialized to undefined at comptime and now we
|
||||
// are for the first time setting the payload. We must change the
|
||||
// representation of the error union from `undef` to `opt_payload`.
|
||||
const arena = parent.beginArena(sema.mod);
|
||||
defer parent.finishArena(sema.mod);
|
||||
|
||||
const payload = try arena.create(Value.Payload.SubValue);
|
||||
payload.* = .{
|
||||
.base = .{ .tag = .eu_payload },
|
||||
.data = Value.undef,
|
||||
};
|
||||
|
||||
val_ptr.* = Value.initPayload(&payload.base);
|
||||
|
||||
return ComptimePtrMutationKit{
|
||||
.decl_ref_mut = parent.decl_ref_mut,
|
||||
.pointee = .{ .direct = &payload.data },
|
||||
.ty = payload_ty,
|
||||
};
|
||||
}
|
||||
},
|
||||
.bad_decl_ty, .bad_ptr_ty => return parent,
|
||||
@ -33225,7 +33225,7 @@ fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {
|
||||
|
||||
pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref {
|
||||
const gpa = sema.gpa;
|
||||
if (val.ip_index != .none) {
|
||||
if (val.ip_index != .none and val.ip_index != .null_value) {
|
||||
if (@enumToInt(val.ip_index) < Air.ref_start_index)
|
||||
return @intToEnum(Air.Inst.Ref, @enumToInt(val.ip_index));
|
||||
try sema.air_instructions.append(gpa, .{
|
||||
|
||||
@ -4915,7 +4915,7 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void {
|
||||
|
||||
const sign_val = switch (tag) {
|
||||
.neg => try vec_ty.minInt(stack.get(), mod),
|
||||
.fabs => try vec_ty.maxInt(stack.get(), mod),
|
||||
.fabs => try vec_ty.maxInt(stack.get(), mod, vec_ty),
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
|
||||
@ -3542,7 +3542,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
try v.elem(f, writer);
|
||||
} else switch (dest_int_info.signedness) {
|
||||
.unsigned => {
|
||||
const mask_val = try inst_scalar_ty.maxIntScalar(mod);
|
||||
const mask_val = try inst_scalar_ty.maxIntScalar(mod, scalar_ty);
|
||||
try writer.writeAll("zig_and_");
|
||||
try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty);
|
||||
try writer.writeByte('(');
|
||||
@ -6681,13 +6681,13 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
.And => switch (scalar_ty.zigTypeTag(mod)) {
|
||||
.Bool => try mod.intValue(Type.comptime_int, 1),
|
||||
else => switch (scalar_ty.intInfo(mod).signedness) {
|
||||
.unsigned => try scalar_ty.maxIntScalar(mod),
|
||||
.unsigned => try scalar_ty.maxIntScalar(mod, scalar_ty),
|
||||
.signed => try mod.intValue(scalar_ty, -1),
|
||||
},
|
||||
},
|
||||
.Min => switch (scalar_ty.zigTypeTag(mod)) {
|
||||
.Bool => try mod.intValue(Type.comptime_int, 1),
|
||||
.Int => try scalar_ty.maxIntScalar(mod),
|
||||
.Bool => Value.one_comptime_int,
|
||||
.Int => try scalar_ty.maxIntScalar(mod, scalar_ty),
|
||||
.Float => try Value.floatToValue(std.math.nan(f128), stack.get(), scalar_ty, target),
|
||||
else => unreachable,
|
||||
},
|
||||
|
||||
@ -3570,15 +3570,21 @@ pub const DeclGen = struct {
|
||||
},
|
||||
.ErrorSet => {
|
||||
const llvm_ty = try dg.lowerType(Type.anyerror);
|
||||
switch (tv.val.tag()) {
|
||||
.@"error" => {
|
||||
const err_name = tv.val.castTag(.@"error").?.data.name;
|
||||
const kv = try dg.module.getErrorValue(err_name);
|
||||
return llvm_ty.constInt(kv.value, .False);
|
||||
switch (tv.val.ip_index) {
|
||||
.none => switch (tv.val.tag()) {
|
||||
.@"error" => {
|
||||
const err_name = tv.val.castTag(.@"error").?.data.name;
|
||||
const kv = try dg.module.getErrorValue(err_name);
|
||||
return llvm_ty.constInt(kv.value, .False);
|
||||
},
|
||||
else => {
|
||||
// In this case we are rendering an error union which has a 0 bits payload.
|
||||
return llvm_ty.constNull();
|
||||
},
|
||||
},
|
||||
else => {
|
||||
// In this case we are rendering an error union which has a 0 bits payload.
|
||||
return llvm_ty.constNull();
|
||||
else => switch (mod.intern_pool.indexToKey(tv.val.ip_index)) {
|
||||
.int => |int| return llvm_ty.constInt(int.storage.u64, .False),
|
||||
else => unreachable,
|
||||
},
|
||||
}
|
||||
},
|
||||
@ -3588,7 +3594,7 @@ pub const DeclGen = struct {
|
||||
|
||||
if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) {
|
||||
// We use the error type directly as the type.
|
||||
const err_val = if (!is_pl) tv.val else try mod.intValue(Type.anyerror, 0);
|
||||
const err_val = if (!is_pl) tv.val else try mod.intValue(Type.err_int, 0);
|
||||
return dg.lowerValue(.{ .ty = Type.anyerror, .val = err_val });
|
||||
}
|
||||
|
||||
@ -3596,7 +3602,7 @@ pub const DeclGen = struct {
|
||||
const error_align = Type.anyerror.abiAlignment(mod);
|
||||
const llvm_error_value = try dg.lowerValue(.{
|
||||
.ty = Type.anyerror,
|
||||
.val = if (is_pl) try mod.intValue(Type.anyerror, 0) else tv.val,
|
||||
.val = if (is_pl) try mod.intValue(Type.err_int, 0) else tv.val,
|
||||
});
|
||||
const llvm_payload_value = try dg.lowerValue(.{
|
||||
.ty = payload_type,
|
||||
@ -6873,7 +6879,7 @@ pub const FuncGen = struct {
|
||||
const err_union_ty = self.typeOf(ty_op.operand).childType(mod);
|
||||
|
||||
const payload_ty = err_union_ty.errorUnionPayload();
|
||||
const non_error_val = try self.dg.lowerValue(.{ .ty = Type.anyerror, .val = try mod.intValue(Type.anyerror, 0) });
|
||||
const non_error_val = try self.dg.lowerValue(.{ .ty = Type.anyerror, .val = try mod.intValue(Type.err_int, 0) });
|
||||
if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
|
||||
_ = self.builder.buildStore(non_error_val, operand);
|
||||
return operand;
|
||||
|
||||
48
src/type.zig
48
src/type.zig
@ -4382,8 +4382,9 @@ pub const Type = struct {
|
||||
}
|
||||
|
||||
// Works for vectors and vectors of integers.
|
||||
pub fn maxInt(ty: Type, arena: Allocator, mod: *Module) !Value {
|
||||
const scalar = try maxIntScalar(ty.scalarType(mod), mod);
|
||||
/// The returned Value will have type dest_ty.
|
||||
pub fn maxInt(ty: Type, arena: Allocator, mod: *Module, dest_ty: Type) !Value {
|
||||
const scalar = try maxIntScalar(ty.scalarType(mod), mod, dest_ty);
|
||||
if (ty.zigTypeTag(mod) == .Vector and scalar.tag() != .the_only_possible_value) {
|
||||
return Value.Tag.repeated.create(arena, scalar);
|
||||
} else {
|
||||
@ -4391,18 +4392,18 @@ pub const Type = struct {
|
||||
}
|
||||
}
|
||||
|
||||
/// Asserts that the type is an integer.
|
||||
pub fn maxIntScalar(ty: Type, mod: *Module) !Value {
|
||||
/// The returned Value will have type dest_ty.
|
||||
pub fn maxIntScalar(ty: Type, mod: *Module, dest_ty: Type) !Value {
|
||||
const info = ty.intInfo(mod);
|
||||
|
||||
switch (info.bits) {
|
||||
0 => return switch (info.signedness) {
|
||||
.signed => mod.intValue(ty, -1),
|
||||
.unsigned => mod.intValue(ty, 0),
|
||||
.signed => try mod.intValue(dest_ty, -1),
|
||||
.unsigned => try mod.intValue(dest_ty, 0),
|
||||
},
|
||||
1 => return switch (info.signedness) {
|
||||
.signed => mod.intValue(ty, 0),
|
||||
.unsigned => mod.intValue(ty, 0),
|
||||
.signed => try mod.intValue(dest_ty, 0),
|
||||
.unsigned => try mod.intValue(dest_ty, 1),
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@ -4410,11 +4411,11 @@ pub const Type = struct {
|
||||
if (std.math.cast(u6, info.bits - 1)) |shift| switch (info.signedness) {
|
||||
.signed => {
|
||||
const n = @as(i64, std.math.maxInt(i64)) >> (63 - shift);
|
||||
return mod.intValue(Type.comptime_int, n);
|
||||
return mod.intValue(dest_ty, n);
|
||||
},
|
||||
.unsigned => {
|
||||
const n = @as(u64, std.math.maxInt(u64)) >> (63 - shift);
|
||||
return mod.intValue(Type.comptime_int, n);
|
||||
return mod.intValue(dest_ty, n);
|
||||
},
|
||||
};
|
||||
|
||||
@ -4423,7 +4424,7 @@ pub const Type = struct {
|
||||
|
||||
try res.setTwosCompIntLimit(.max, info.signedness, info.bits);
|
||||
|
||||
return mod.intValue_big(Type.comptime_int, res.toConst());
|
||||
return mod.intValue_big(dest_ty, res.toConst());
|
||||
}
|
||||
|
||||
/// Asserts the type is an enum or a union.
|
||||
@ -5068,6 +5069,7 @@ pub const Type = struct {
|
||||
|
||||
pub fn isSimpleTuple(ty: Type) bool {
|
||||
return switch (ty.ip_index) {
|
||||
.empty_struct => true,
|
||||
.none => switch (ty.tag()) {
|
||||
.tuple, .empty_struct_literal => true,
|
||||
else => false,
|
||||
@ -5077,21 +5079,29 @@ pub const Type = struct {
|
||||
}
|
||||
|
||||
pub fn isSimpleTupleOrAnonStruct(ty: Type) bool {
|
||||
return switch (ty.tag()) {
|
||||
.tuple, .empty_struct_literal, .anon_struct => true,
|
||||
return switch (ty.ip_index) {
|
||||
.empty_struct => true,
|
||||
.none => switch (ty.tag()) {
|
||||
.tuple, .empty_struct_literal, .anon_struct => true,
|
||||
else => false,
|
||||
},
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
// Only allowed for simple tuple types
|
||||
pub fn tupleFields(ty: Type) Payload.Tuple.Data {
|
||||
return switch (ty.tag()) {
|
||||
.tuple => ty.castTag(.tuple).?.data,
|
||||
.anon_struct => .{
|
||||
.types = ty.castTag(.anon_struct).?.data.types,
|
||||
.values = ty.castTag(.anon_struct).?.data.values,
|
||||
return switch (ty.ip_index) {
|
||||
.empty_struct => .{ .types = &.{}, .values = &.{} },
|
||||
.none => switch (ty.tag()) {
|
||||
.tuple => ty.castTag(.tuple).?.data,
|
||||
.anon_struct => .{
|
||||
.types = ty.castTag(.anon_struct).?.data.types,
|
||||
.values = ty.castTag(.anon_struct).?.data.values,
|
||||
},
|
||||
.empty_struct_literal => .{ .types = &.{}, .values = &.{} },
|
||||
else => unreachable,
|
||||
},
|
||||
.empty_struct_literal => .{ .types = &.{}, .values = &.{} },
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
@ -2625,6 +2625,10 @@ pub const Value = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn isRuntimeValue(val: Value) bool {
|
||||
return val.ip_index == .none and val.tag() == .runtime_value;
|
||||
}
|
||||
|
||||
pub fn tagIsVariable(val: Value) bool {
|
||||
return val.ip_index == .none and val.tag() == .variable;
|
||||
}
|
||||
@ -3402,7 +3406,7 @@ pub const Value = struct {
|
||||
if (lhs.isUndef() or rhs.isUndef()) return Value.undef;
|
||||
|
||||
const anded = try bitwiseAnd(lhs, rhs, ty, arena, mod);
|
||||
const all_ones = if (ty.isSignedInt(mod)) try mod.intValue(ty, -1) else try ty.maxIntScalar(mod);
|
||||
const all_ones = if (ty.isSignedInt(mod)) try mod.intValue(ty, -1) else try ty.maxIntScalar(mod, ty);
|
||||
return bitwiseXor(anded, all_ones, ty, arena, mod);
|
||||
}
|
||||
|
||||
@ -5152,6 +5156,10 @@ pub const Value = struct {
|
||||
pub const BigIntSpace = InternPool.Key.Int.Storage.BigIntSpace;
|
||||
|
||||
pub const zero_usize: Value = .{ .ip_index = .zero_usize, .legacy = undefined };
|
||||
pub const zero_u8: Value = .{ .ip_index = .zero_u8, .legacy = undefined };
|
||||
pub const zero_comptime_int: Value = .{ .ip_index = .zero, .legacy = undefined };
|
||||
pub const one_comptime_int: Value = .{ .ip_index = .one, .legacy = undefined };
|
||||
pub const negative_one_comptime_int: Value = .{ .ip_index = .negative_one, .legacy = undefined };
|
||||
pub const undef: Value = .{ .ip_index = .undef, .legacy = undefined };
|
||||
pub const float_zero: Value = .{ .ip_index = .zero, .legacy = undefined }; // TODO: replace this!
|
||||
pub const @"void": Value = .{ .ip_index = .void_value, .legacy = undefined };
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user