mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Sema: cleanup coerceExtra
* remove unreachable code * remove already handled cases * avoid `InternPool.getCoerced` * add some undef checks * error when converting undef int to float Closes #16987
This commit is contained in:
parent
49075d2055
commit
e2ff486de5
@ -6360,7 +6360,7 @@ pub fn errorSetFromUnsortedNames(
|
||||
|
||||
/// Supports only pointers, not pointer-like optionals.
|
||||
pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
|
||||
assert(ty.zigTypeTag(mod) == .Pointer);
|
||||
assert(ty.zigTypeTag(mod) == .Pointer and !ty.isSlice(mod));
|
||||
const i = try intern(mod, .{ .ptr = .{
|
||||
.ty = ty.toIntern(),
|
||||
.addr = .{ .int = (try mod.intValue_u64(Type.usize, x)).toIntern() },
|
||||
|
||||
183
src/Sema.zig
183
src/Sema.zig
@ -17282,12 +17282,13 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
for (enum_field_vals, 0..) |*field_val, i| {
|
||||
const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
|
||||
const value_val = if (enum_type.values.len > 0)
|
||||
try mod.intern_pool.getCoerced(gpa, enum_type.values.get(ip)[i], .comptime_int_type)
|
||||
try mod.intern_pool.getCoercedInts(
|
||||
mod.gpa,
|
||||
mod.intern_pool.indexToKey(enum_type.values.get(ip)[i]).int,
|
||||
.comptime_int_type,
|
||||
)
|
||||
else
|
||||
try mod.intern(.{ .int = .{
|
||||
.ty = .comptime_int_type,
|
||||
.storage = .{ .u64 = @intCast(i) },
|
||||
} });
|
||||
(try mod.intValue(Type.comptime_int, i)).toIntern();
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
||||
const name = try sema.arena.dupe(u8, ip.stringToSlice(enum_type.names.get(ip)[i]));
|
||||
const name_val = v: {
|
||||
@ -21259,7 +21260,7 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
|
||||
try sema.checkFloatType(block, operand_src, operand_scalar_ty);
|
||||
|
||||
if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
|
||||
const result_val = try sema.intFromFloat(block, operand_src, operand_val, operand_ty, dest_ty);
|
||||
const result_val = try sema.intFromFloat(block, operand_src, operand_val, operand_ty, dest_ty, .truncate);
|
||||
return Air.internedToRef(result_val.toIntern());
|
||||
} else if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
|
||||
return sema.failWithNeededComptime(block, operand_src, .{
|
||||
@ -27575,21 +27576,21 @@ fn coerceExtra(
|
||||
return block.addBitCast(dest_ty, inst);
|
||||
}
|
||||
|
||||
const is_undef = inst_ty.zigTypeTag(mod) == .Undefined;
|
||||
|
||||
switch (dest_ty.zigTypeTag(mod)) {
|
||||
.Optional => optional: {
|
||||
// undefined sets the optional bit also to undefined.
|
||||
if (is_undef) {
|
||||
return mod.undefRef(dest_ty);
|
||||
}
|
||||
if (maybe_inst_val) |val| {
|
||||
// undefined sets the optional bit also to undefined.
|
||||
if (val.toIntern() == .undef) {
|
||||
return mod.undefRef(dest_ty);
|
||||
}
|
||||
|
||||
// null to ?T
|
||||
if (inst_ty.zigTypeTag(mod) == .Null) {
|
||||
return Air.internedToRef((try mod.intern(.{ .opt = .{
|
||||
.ty = dest_ty.toIntern(),
|
||||
.val = .none,
|
||||
} })));
|
||||
// null to ?T
|
||||
if (val.toIntern() == .null_value) {
|
||||
return Air.internedToRef((try mod.intern(.{ .opt = .{
|
||||
.ty = dest_ty.toIntern(),
|
||||
.val = .none,
|
||||
} })));
|
||||
}
|
||||
}
|
||||
|
||||
// cast from ?*T and ?[*]T to ?*anyopaque
|
||||
@ -27681,7 +27682,9 @@ fn coerceExtra(
|
||||
|
||||
if (dest_info.sentinel != .none) {
|
||||
if (array_ty.sentinel(mod)) |inst_sent| {
|
||||
if (dest_info.sentinel != (try mod.getCoerced(inst_sent, dst_elem_type)).toIntern()) {
|
||||
if (Air.internedToRef(dest_info.sentinel) !=
|
||||
try sema.coerceInMemory(inst_sent, dst_elem_type))
|
||||
{
|
||||
in_memory_result = .{ .ptr_sentinel = .{
|
||||
.actual = inst_sent,
|
||||
.wanted = dest_info.sentinel.toValue(),
|
||||
@ -27758,9 +27761,10 @@ fn coerceExtra(
|
||||
switch (dest_info.flags.size) {
|
||||
// coercion to C pointer
|
||||
.C => switch (inst_ty.zigTypeTag(mod)) {
|
||||
.Null => {
|
||||
return Air.internedToRef((try mod.getCoerced(Value.null, dest_ty)).toIntern());
|
||||
},
|
||||
.Null => return Air.internedToRef(try mod.intern(.{ .ptr = .{
|
||||
.ty = dest_ty.toIntern(),
|
||||
.addr = .{ .int = .zero_usize },
|
||||
} })),
|
||||
.ComptimeInt => {
|
||||
const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
|
||||
error.NotCoercible => break :pointer,
|
||||
@ -27865,10 +27869,19 @@ fn coerceExtra(
|
||||
// we use a dummy pointer value with the required alignment.
|
||||
return Air.internedToRef((try mod.intern(.{ .ptr = .{
|
||||
.ty = dest_ty.toIntern(),
|
||||
.addr = .{ .int = (if (dest_info.flags.alignment != .none)
|
||||
try mod.intValue(Type.usize, dest_info.flags.alignment.toByteUnitsOptional().?)
|
||||
.addr = .{ .int = if (dest_info.flags.alignment != .none)
|
||||
(try mod.intValue(
|
||||
Type.usize,
|
||||
dest_info.flags.alignment.toByteUnitsOptional().?,
|
||||
)).toIntern()
|
||||
else
|
||||
try mod.getCoerced(try dest_info.child.toType().lazyAbiAlignment(mod), Type.usize)).toIntern() },
|
||||
try mod.intern_pool.getCoercedInts(
|
||||
mod.gpa,
|
||||
mod.intern_pool.indexToKey(
|
||||
(try dest_info.child.toType().lazyAbiAlignment(mod)).toIntern(),
|
||||
).int,
|
||||
.usize_type,
|
||||
) },
|
||||
.len = (try mod.intValue(Type.usize, 0)).toIntern(),
|
||||
} })));
|
||||
}
|
||||
@ -27904,8 +27917,8 @@ fn coerceExtra(
|
||||
}
|
||||
|
||||
if (dest_info.sentinel == .none or inst_info.sentinel == .none or
|
||||
dest_info.sentinel !=
|
||||
try mod.intern_pool.getCoerced(sema.gpa, inst_info.sentinel, dest_info.child))
|
||||
Air.internedToRef(dest_info.sentinel) !=
|
||||
try sema.coerceInMemory(inst_info.sentinel.toValue(), dest_info.child.toType()))
|
||||
break :p;
|
||||
|
||||
const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty);
|
||||
@ -27915,10 +27928,7 @@ fn coerceExtra(
|
||||
},
|
||||
.Int, .ComptimeInt => switch (inst_ty.zigTypeTag(mod)) {
|
||||
.Float, .ComptimeFloat => float: {
|
||||
if (is_undef) {
|
||||
return mod.undefRef(dest_ty);
|
||||
}
|
||||
const val = (try sema.resolveMaybeUndefVal(inst)) orelse {
|
||||
const val = maybe_inst_val orelse {
|
||||
if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
|
||||
if (!opts.report_err) return error.NotCoercible;
|
||||
return sema.failWithNeededComptime(block, inst_src, .{
|
||||
@ -27927,29 +27937,23 @@ fn coerceExtra(
|
||||
}
|
||||
break :float;
|
||||
};
|
||||
|
||||
if (val.floatHasFraction(mod)) {
|
||||
return sema.fail(
|
||||
block,
|
||||
inst_src,
|
||||
"fractional component prevents float value '{}' from coercion to type '{}'",
|
||||
.{ val.fmtValue(inst_ty, mod), dest_ty.fmt(mod) },
|
||||
);
|
||||
}
|
||||
const result_val = try sema.intFromFloat(block, inst_src, val, inst_ty, dest_ty);
|
||||
const result_val = try sema.intFromFloat(block, inst_src, val, inst_ty, dest_ty, .exact);
|
||||
return Air.internedToRef(result_val.toIntern());
|
||||
},
|
||||
.Int, .ComptimeInt => {
|
||||
if (is_undef) {
|
||||
return mod.undefRef(dest_ty);
|
||||
}
|
||||
if (try sema.resolveMaybeUndefVal(inst)) |val| {
|
||||
if (maybe_inst_val) |val| {
|
||||
// comptime-known integer to other number
|
||||
if (!(try sema.intFitsInType(val, dest_ty, null))) {
|
||||
if (!opts.report_err) return error.NotCoercible;
|
||||
return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) });
|
||||
}
|
||||
return Air.internedToRef((try mod.getCoerced(val, dest_ty)).toIntern());
|
||||
return switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
.undef => try mod.undefRef(dest_ty),
|
||||
.int => |int| Air.internedToRef(
|
||||
try mod.intern_pool.getCoercedInts(mod.gpa, int, dest_ty.toIntern()),
|
||||
),
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
|
||||
if (!opts.report_err) return error.NotCoercible;
|
||||
@ -27970,9 +27974,6 @@ fn coerceExtra(
|
||||
return block.addTyOp(.intcast, dest_ty, inst);
|
||||
}
|
||||
},
|
||||
.Undefined => {
|
||||
return mod.undefRef(dest_ty);
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(mod)) {
|
||||
@ -27982,10 +27983,7 @@ fn coerceExtra(
|
||||
return Air.internedToRef(result_val.toIntern());
|
||||
},
|
||||
.Float => {
|
||||
if (is_undef) {
|
||||
return mod.undefRef(dest_ty);
|
||||
}
|
||||
if (try sema.resolveMaybeUndefVal(inst)) |val| {
|
||||
if (maybe_inst_val) |val| {
|
||||
const result_val = try val.floatCast(dest_ty, mod);
|
||||
if (!val.eql(try result_val.floatCast(inst_ty, mod), inst_ty, mod)) {
|
||||
return sema.fail(
|
||||
@ -28012,10 +28010,7 @@ fn coerceExtra(
|
||||
}
|
||||
},
|
||||
.Int, .ComptimeInt => int: {
|
||||
if (is_undef) {
|
||||
return mod.undefRef(dest_ty);
|
||||
}
|
||||
const val = (try sema.resolveMaybeUndefVal(inst)) orelse {
|
||||
const val = maybe_inst_val orelse {
|
||||
if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {
|
||||
if (!opts.report_err) return error.NotCoercible;
|
||||
return sema.failWithNeededComptime(block, inst_src, .{
|
||||
@ -28037,9 +28032,6 @@ fn coerceExtra(
|
||||
//}
|
||||
return Air.internedToRef(result_val.toIntern());
|
||||
},
|
||||
.Undefined => {
|
||||
return mod.undefRef(dest_ty);
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.Enum => switch (inst_ty.zigTypeTag(mod)) {
|
||||
@ -28070,9 +28062,6 @@ fn coerceExtra(
|
||||
return sema.unionToTag(block, dest_ty, inst, inst_src);
|
||||
}
|
||||
},
|
||||
.Undefined => {
|
||||
return mod.undefRef(dest_ty);
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.ErrorUnion => switch (inst_ty.zigTypeTag(mod)) {
|
||||
@ -28107,9 +28096,6 @@ fn coerceExtra(
|
||||
// E to E!T
|
||||
return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);
|
||||
},
|
||||
.Undefined => {
|
||||
return mod.undefRef(dest_ty);
|
||||
},
|
||||
else => eu: {
|
||||
// T to E!T
|
||||
return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src) catch |err| switch (err) {
|
||||
@ -28125,9 +28111,6 @@ fn coerceExtra(
|
||||
return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);
|
||||
}
|
||||
},
|
||||
.Undefined => {
|
||||
return mod.undefRef(dest_ty);
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.Array => switch (inst_ty.zigTypeTag(mod)) {
|
||||
@ -28140,9 +28123,6 @@ fn coerceExtra(
|
||||
return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
|
||||
}
|
||||
},
|
||||
.Undefined => {
|
||||
return mod.undefRef(dest_ty);
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.Vector => switch (inst_ty.zigTypeTag(mod)) {
|
||||
@ -28152,9 +28132,6 @@ fn coerceExtra(
|
||||
return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
|
||||
}
|
||||
},
|
||||
.Undefined => {
|
||||
return mod.undefRef(dest_ty);
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.Struct => blk: {
|
||||
@ -28174,9 +28151,7 @@ fn coerceExtra(
|
||||
// undefined to anything. We do this after the big switch above so that
|
||||
// special logic has a chance to run first, such as `*[N]T` to `[]T` which
|
||||
// should initialize the length field of the slice.
|
||||
if (is_undef) {
|
||||
return mod.undefRef(dest_ty);
|
||||
}
|
||||
if (maybe_inst_val) |val| if (val.toIntern() == .undef) return mod.undefRef(dest_ty);
|
||||
|
||||
if (!opts.report_err) return error.NotCoercible;
|
||||
|
||||
@ -34043,10 +34018,10 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
|
||||
switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
.int => |int| switch (int.storage) {
|
||||
.u64, .i64, .big_int => return val,
|
||||
.lazy_align, .lazy_size => return (try mod.intern(.{ .int = .{
|
||||
.ty = int.ty,
|
||||
.storage = .{ .u64 = (try val.getUnsignedIntAdvanced(mod, sema)).? },
|
||||
} })).toValue(),
|
||||
.lazy_align, .lazy_size => return mod.intValue(
|
||||
int.ty.toType(),
|
||||
(try val.getUnsignedIntAdvanced(mod, sema)).?,
|
||||
),
|
||||
},
|
||||
.ptr => |ptr| {
|
||||
const resolved_len = switch (ptr.len) {
|
||||
@ -36217,20 +36192,21 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
|
||||
.auto, .explicit => {
|
||||
if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null;
|
||||
|
||||
switch (enum_type.names.len) {
|
||||
0 => {
|
||||
const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
|
||||
return only.toValue();
|
||||
},
|
||||
1 => return try mod.getCoerced((if (enum_type.values.len == 0)
|
||||
try mod.intern(.{ .int = .{
|
||||
.ty = enum_type.tag_ty,
|
||||
.storage = .{ .u64 = 0 },
|
||||
} })
|
||||
else
|
||||
enum_type.values.get(ip)[0]).toValue(), ty),
|
||||
return switch (enum_type.names.len) {
|
||||
0 => try mod.intern(.{ .empty_enum_value = ty.toIntern() }),
|
||||
1 => try mod.intern(.{ .enum_tag = .{
|
||||
.ty = ty.toIntern(),
|
||||
.int = if (enum_type.values.len == 0)
|
||||
(try mod.intValue(enum_type.tag_ty.toType(), 0)).toIntern()
|
||||
else
|
||||
try mod.intern_pool.getCoercedInts(
|
||||
mod.gpa,
|
||||
mod.intern_pool.indexToKey(enum_type.values.get(ip)[0]).int,
|
||||
enum_type.tag_ty,
|
||||
),
|
||||
} }),
|
||||
else => return null,
|
||||
}
|
||||
}.toValue();
|
||||
},
|
||||
},
|
||||
|
||||
@ -37069,6 +37045,8 @@ fn intSubWithOverflowScalar(
|
||||
};
|
||||
}
|
||||
|
||||
const IntFromFloatMode = enum { exact, truncate };
|
||||
|
||||
fn intFromFloat(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
@ -37076,6 +37054,7 @@ fn intFromFloat(
|
||||
val: Value,
|
||||
float_ty: Type,
|
||||
int_ty: Type,
|
||||
mode: IntFromFloatMode,
|
||||
) CompileError!Value {
|
||||
const mod = sema.mod;
|
||||
if (float_ty.zigTypeTag(mod) == .Vector) {
|
||||
@ -37084,14 +37063,14 @@ fn intFromFloat(
|
||||
const scalar_ty = int_ty.scalarType(mod);
|
||||
for (result_data, 0..) |*scalar, i| {
|
||||
const elem_val = try val.elemValue(sema.mod, i);
|
||||
scalar.* = try (try sema.intFromFloatScalar(block, src, elem_val, elem_ty, int_ty.scalarType(mod))).intern(scalar_ty, mod);
|
||||
scalar.* = try (try sema.intFromFloatScalar(block, src, elem_val, elem_ty, int_ty.scalarType(mod), mode)).intern(scalar_ty, mod);
|
||||
}
|
||||
return (try mod.intern(.{ .aggregate = .{
|
||||
.ty = int_ty.toIntern(),
|
||||
.storage = .{ .elems = result_data },
|
||||
} })).toValue();
|
||||
}
|
||||
return sema.intFromFloatScalar(block, src, val, float_ty, int_ty);
|
||||
return sema.intFromFloatScalar(block, src, val, float_ty, int_ty, mode);
|
||||
}
|
||||
|
||||
// float is expected to be finite and non-NaN
|
||||
@ -37126,9 +37105,19 @@ fn intFromFloatScalar(
|
||||
val: Value,
|
||||
float_ty: Type,
|
||||
int_ty: Type,
|
||||
mode: IntFromFloatMode,
|
||||
) CompileError!Value {
|
||||
const mod = sema.mod;
|
||||
|
||||
if (val.isUndef(mod)) return sema.failWithUseOfUndef(block, src);
|
||||
|
||||
if (mode == .exact and val.floatHasFraction(mod)) return sema.fail(
|
||||
block,
|
||||
src,
|
||||
"fractional component prevents float value '{}' from coercion to type '{}'",
|
||||
.{ val.fmtValue(float_ty, mod), int_ty.fmt(mod) },
|
||||
);
|
||||
|
||||
const float = val.toFloat(f128, mod);
|
||||
if (std.math.isNan(float)) {
|
||||
return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{
|
||||
|
||||
@ -1866,7 +1866,7 @@ pub const Value = struct {
|
||||
|
||||
pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value {
|
||||
return switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||
.undef => (try mod.intern(.{ .undef = float_ty.toIntern() })).toValue(),
|
||||
.undef => try mod.undefValue(float_ty),
|
||||
.int => |int| switch (int.storage) {
|
||||
.big_int => |big_int| {
|
||||
const float = bigIntToFloat(big_int.limbs, big_int.positive);
|
||||
|
||||
@ -1155,6 +1155,8 @@ fn foobar(func: PFN_void) !void {
|
||||
}
|
||||
|
||||
test "cast function with an opaque parameter" {
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||
|
||||
const Container = struct {
|
||||
const Ctx = opaque {};
|
||||
ctx: *Ctx,
|
||||
@ -2494,3 +2496,14 @@ test "@intFromBool on vector" {
|
||||
try S.doTheTest();
|
||||
try comptime S.doTheTest();
|
||||
}
|
||||
|
||||
test "numeric coercions with undefined" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
const from: i32 = undefined;
|
||||
var to: f32 = from;
|
||||
to = @floatFromInt(from);
|
||||
to = 42.0;
|
||||
try expectEqual(@as(f32, 42.0), to);
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const mem = std.mem;
|
||||
|
||||
fn initStaticArray() [10]i32 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user