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.
|
/// Supports only pointers, not pointer-like optionals.
|
||||||
pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
|
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 = .{
|
const i = try intern(mod, .{ .ptr = .{
|
||||||
.ty = ty.toIntern(),
|
.ty = ty.toIntern(),
|
||||||
.addr = .{ .int = (try mod.intValue_u64(Type.usize, x)).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| {
|
for (enum_field_vals, 0..) |*field_val, i| {
|
||||||
const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
|
const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
|
||||||
const value_val = if (enum_type.values.len > 0)
|
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
|
else
|
||||||
try mod.intern(.{ .int = .{
|
(try mod.intValue(Type.comptime_int, i)).toIntern();
|
||||||
.ty = .comptime_int_type,
|
|
||||||
.storage = .{ .u64 = @intCast(i) },
|
|
||||||
} });
|
|
||||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
// 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 = try sema.arena.dupe(u8, ip.stringToSlice(enum_type.names.get(ip)[i]));
|
||||||
const name_val = v: {
|
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);
|
try sema.checkFloatType(block, operand_src, operand_scalar_ty);
|
||||||
|
|
||||||
if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
|
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());
|
return Air.internedToRef(result_val.toIntern());
|
||||||
} else if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
|
} else if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
|
||||||
return sema.failWithNeededComptime(block, operand_src, .{
|
return sema.failWithNeededComptime(block, operand_src, .{
|
||||||
@ -27575,21 +27576,21 @@ fn coerceExtra(
|
|||||||
return block.addBitCast(dest_ty, inst);
|
return block.addBitCast(dest_ty, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
const is_undef = inst_ty.zigTypeTag(mod) == .Undefined;
|
|
||||||
|
|
||||||
switch (dest_ty.zigTypeTag(mod)) {
|
switch (dest_ty.zigTypeTag(mod)) {
|
||||||
.Optional => optional: {
|
.Optional => optional: {
|
||||||
// undefined sets the optional bit also to undefined.
|
if (maybe_inst_val) |val| {
|
||||||
if (is_undef) {
|
// undefined sets the optional bit also to undefined.
|
||||||
return mod.undefRef(dest_ty);
|
if (val.toIntern() == .undef) {
|
||||||
}
|
return mod.undefRef(dest_ty);
|
||||||
|
}
|
||||||
|
|
||||||
// null to ?T
|
// null to ?T
|
||||||
if (inst_ty.zigTypeTag(mod) == .Null) {
|
if (val.toIntern() == .null_value) {
|
||||||
return Air.internedToRef((try mod.intern(.{ .opt = .{
|
return Air.internedToRef((try mod.intern(.{ .opt = .{
|
||||||
.ty = dest_ty.toIntern(),
|
.ty = dest_ty.toIntern(),
|
||||||
.val = .none,
|
.val = .none,
|
||||||
} })));
|
} })));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// cast from ?*T and ?[*]T to ?*anyopaque
|
// cast from ?*T and ?[*]T to ?*anyopaque
|
||||||
@ -27681,7 +27682,9 @@ fn coerceExtra(
|
|||||||
|
|
||||||
if (dest_info.sentinel != .none) {
|
if (dest_info.sentinel != .none) {
|
||||||
if (array_ty.sentinel(mod)) |inst_sent| {
|
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 = .{
|
in_memory_result = .{ .ptr_sentinel = .{
|
||||||
.actual = inst_sent,
|
.actual = inst_sent,
|
||||||
.wanted = dest_info.sentinel.toValue(),
|
.wanted = dest_info.sentinel.toValue(),
|
||||||
@ -27758,9 +27761,10 @@ fn coerceExtra(
|
|||||||
switch (dest_info.flags.size) {
|
switch (dest_info.flags.size) {
|
||||||
// coercion to C pointer
|
// coercion to C pointer
|
||||||
.C => switch (inst_ty.zigTypeTag(mod)) {
|
.C => switch (inst_ty.zigTypeTag(mod)) {
|
||||||
.Null => {
|
.Null => return Air.internedToRef(try mod.intern(.{ .ptr = .{
|
||||||
return Air.internedToRef((try mod.getCoerced(Value.null, dest_ty)).toIntern());
|
.ty = dest_ty.toIntern(),
|
||||||
},
|
.addr = .{ .int = .zero_usize },
|
||||||
|
} })),
|
||||||
.ComptimeInt => {
|
.ComptimeInt => {
|
||||||
const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
|
const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
|
||||||
error.NotCoercible => break :pointer,
|
error.NotCoercible => break :pointer,
|
||||||
@ -27865,10 +27869,19 @@ fn coerceExtra(
|
|||||||
// we use a dummy pointer value with the required alignment.
|
// we use a dummy pointer value with the required alignment.
|
||||||
return Air.internedToRef((try mod.intern(.{ .ptr = .{
|
return Air.internedToRef((try mod.intern(.{ .ptr = .{
|
||||||
.ty = dest_ty.toIntern(),
|
.ty = dest_ty.toIntern(),
|
||||||
.addr = .{ .int = (if (dest_info.flags.alignment != .none)
|
.addr = .{ .int = if (dest_info.flags.alignment != .none)
|
||||||
try mod.intValue(Type.usize, dest_info.flags.alignment.toByteUnitsOptional().?)
|
(try mod.intValue(
|
||||||
|
Type.usize,
|
||||||
|
dest_info.flags.alignment.toByteUnitsOptional().?,
|
||||||
|
)).toIntern()
|
||||||
else
|
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(),
|
.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
|
if (dest_info.sentinel == .none or inst_info.sentinel == .none or
|
||||||
dest_info.sentinel !=
|
Air.internedToRef(dest_info.sentinel) !=
|
||||||
try mod.intern_pool.getCoerced(sema.gpa, inst_info.sentinel, dest_info.child))
|
try sema.coerceInMemory(inst_info.sentinel.toValue(), dest_info.child.toType()))
|
||||||
break :p;
|
break :p;
|
||||||
|
|
||||||
const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty);
|
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)) {
|
.Int, .ComptimeInt => switch (inst_ty.zigTypeTag(mod)) {
|
||||||
.Float, .ComptimeFloat => float: {
|
.Float, .ComptimeFloat => float: {
|
||||||
if (is_undef) {
|
const val = maybe_inst_val orelse {
|
||||||
return mod.undefRef(dest_ty);
|
|
||||||
}
|
|
||||||
const val = (try sema.resolveMaybeUndefVal(inst)) orelse {
|
|
||||||
if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
|
if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
|
||||||
if (!opts.report_err) return error.NotCoercible;
|
if (!opts.report_err) return error.NotCoercible;
|
||||||
return sema.failWithNeededComptime(block, inst_src, .{
|
return sema.failWithNeededComptime(block, inst_src, .{
|
||||||
@ -27927,29 +27937,23 @@ fn coerceExtra(
|
|||||||
}
|
}
|
||||||
break :float;
|
break :float;
|
||||||
};
|
};
|
||||||
|
const result_val = try sema.intFromFloat(block, inst_src, val, inst_ty, dest_ty, .exact);
|
||||||
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);
|
|
||||||
return Air.internedToRef(result_val.toIntern());
|
return Air.internedToRef(result_val.toIntern());
|
||||||
},
|
},
|
||||||
.Int, .ComptimeInt => {
|
.Int, .ComptimeInt => {
|
||||||
if (is_undef) {
|
if (maybe_inst_val) |val| {
|
||||||
return mod.undefRef(dest_ty);
|
|
||||||
}
|
|
||||||
if (try sema.resolveMaybeUndefVal(inst)) |val| {
|
|
||||||
// comptime-known integer to other number
|
// comptime-known integer to other number
|
||||||
if (!(try sema.intFitsInType(val, dest_ty, null))) {
|
if (!(try sema.intFitsInType(val, dest_ty, null))) {
|
||||||
if (!opts.report_err) return error.NotCoercible;
|
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 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 (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
|
||||||
if (!opts.report_err) return error.NotCoercible;
|
if (!opts.report_err) return error.NotCoercible;
|
||||||
@ -27970,9 +27974,6 @@ fn coerceExtra(
|
|||||||
return block.addTyOp(.intcast, dest_ty, inst);
|
return block.addTyOp(.intcast, dest_ty, inst);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Undefined => {
|
|
||||||
return mod.undefRef(dest_ty);
|
|
||||||
},
|
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
.Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(mod)) {
|
.Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(mod)) {
|
||||||
@ -27982,10 +27983,7 @@ fn coerceExtra(
|
|||||||
return Air.internedToRef(result_val.toIntern());
|
return Air.internedToRef(result_val.toIntern());
|
||||||
},
|
},
|
||||||
.Float => {
|
.Float => {
|
||||||
if (is_undef) {
|
if (maybe_inst_val) |val| {
|
||||||
return mod.undefRef(dest_ty);
|
|
||||||
}
|
|
||||||
if (try sema.resolveMaybeUndefVal(inst)) |val| {
|
|
||||||
const result_val = try val.floatCast(dest_ty, mod);
|
const result_val = try val.floatCast(dest_ty, mod);
|
||||||
if (!val.eql(try result_val.floatCast(inst_ty, mod), inst_ty, mod)) {
|
if (!val.eql(try result_val.floatCast(inst_ty, mod), inst_ty, mod)) {
|
||||||
return sema.fail(
|
return sema.fail(
|
||||||
@ -28012,10 +28010,7 @@ fn coerceExtra(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Int, .ComptimeInt => int: {
|
.Int, .ComptimeInt => int: {
|
||||||
if (is_undef) {
|
const val = maybe_inst_val orelse {
|
||||||
return mod.undefRef(dest_ty);
|
|
||||||
}
|
|
||||||
const val = (try sema.resolveMaybeUndefVal(inst)) orelse {
|
|
||||||
if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {
|
if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {
|
||||||
if (!opts.report_err) return error.NotCoercible;
|
if (!opts.report_err) return error.NotCoercible;
|
||||||
return sema.failWithNeededComptime(block, inst_src, .{
|
return sema.failWithNeededComptime(block, inst_src, .{
|
||||||
@ -28037,9 +28032,6 @@ fn coerceExtra(
|
|||||||
//}
|
//}
|
||||||
return Air.internedToRef(result_val.toIntern());
|
return Air.internedToRef(result_val.toIntern());
|
||||||
},
|
},
|
||||||
.Undefined => {
|
|
||||||
return mod.undefRef(dest_ty);
|
|
||||||
},
|
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
.Enum => switch (inst_ty.zigTypeTag(mod)) {
|
.Enum => switch (inst_ty.zigTypeTag(mod)) {
|
||||||
@ -28070,9 +28062,6 @@ fn coerceExtra(
|
|||||||
return sema.unionToTag(block, dest_ty, inst, inst_src);
|
return sema.unionToTag(block, dest_ty, inst, inst_src);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Undefined => {
|
|
||||||
return mod.undefRef(dest_ty);
|
|
||||||
},
|
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
.ErrorUnion => switch (inst_ty.zigTypeTag(mod)) {
|
.ErrorUnion => switch (inst_ty.zigTypeTag(mod)) {
|
||||||
@ -28107,9 +28096,6 @@ fn coerceExtra(
|
|||||||
// E to E!T
|
// E to E!T
|
||||||
return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);
|
return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);
|
||||||
},
|
},
|
||||||
.Undefined => {
|
|
||||||
return mod.undefRef(dest_ty);
|
|
||||||
},
|
|
||||||
else => eu: {
|
else => eu: {
|
||||||
// T to E!T
|
// T to E!T
|
||||||
return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src) catch |err| switch (err) {
|
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);
|
return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Undefined => {
|
|
||||||
return mod.undefRef(dest_ty);
|
|
||||||
},
|
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
.Array => switch (inst_ty.zigTypeTag(mod)) {
|
.Array => switch (inst_ty.zigTypeTag(mod)) {
|
||||||
@ -28140,9 +28123,6 @@ fn coerceExtra(
|
|||||||
return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
|
return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Undefined => {
|
|
||||||
return mod.undefRef(dest_ty);
|
|
||||||
},
|
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
.Vector => switch (inst_ty.zigTypeTag(mod)) {
|
.Vector => switch (inst_ty.zigTypeTag(mod)) {
|
||||||
@ -28152,9 +28132,6 @@ fn coerceExtra(
|
|||||||
return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
|
return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Undefined => {
|
|
||||||
return mod.undefRef(dest_ty);
|
|
||||||
},
|
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
.Struct => blk: {
|
.Struct => blk: {
|
||||||
@ -28174,9 +28151,7 @@ fn coerceExtra(
|
|||||||
// undefined to anything. We do this after the big switch above so that
|
// 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
|
// special logic has a chance to run first, such as `*[N]T` to `[]T` which
|
||||||
// should initialize the length field of the slice.
|
// should initialize the length field of the slice.
|
||||||
if (is_undef) {
|
if (maybe_inst_val) |val| if (val.toIntern() == .undef) return mod.undefRef(dest_ty);
|
||||||
return mod.undefRef(dest_ty);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!opts.report_err) return error.NotCoercible;
|
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())) {
|
switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
||||||
.int => |int| switch (int.storage) {
|
.int => |int| switch (int.storage) {
|
||||||
.u64, .i64, .big_int => return val,
|
.u64, .i64, .big_int => return val,
|
||||||
.lazy_align, .lazy_size => return (try mod.intern(.{ .int = .{
|
.lazy_align, .lazy_size => return mod.intValue(
|
||||||
.ty = int.ty,
|
int.ty.toType(),
|
||||||
.storage = .{ .u64 = (try val.getUnsignedIntAdvanced(mod, sema)).? },
|
(try val.getUnsignedIntAdvanced(mod, sema)).?,
|
||||||
} })).toValue(),
|
),
|
||||||
},
|
},
|
||||||
.ptr => |ptr| {
|
.ptr => |ptr| {
|
||||||
const resolved_len = switch (ptr.len) {
|
const resolved_len = switch (ptr.len) {
|
||||||
@ -36217,20 +36192,21 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
|
|||||||
.auto, .explicit => {
|
.auto, .explicit => {
|
||||||
if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null;
|
if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null;
|
||||||
|
|
||||||
switch (enum_type.names.len) {
|
return switch (enum_type.names.len) {
|
||||||
0 => {
|
0 => try mod.intern(.{ .empty_enum_value = ty.toIntern() }),
|
||||||
const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
|
1 => try mod.intern(.{ .enum_tag = .{
|
||||||
return only.toValue();
|
.ty = ty.toIntern(),
|
||||||
},
|
.int = if (enum_type.values.len == 0)
|
||||||
1 => return try mod.getCoerced((if (enum_type.values.len == 0)
|
(try mod.intValue(enum_type.tag_ty.toType(), 0)).toIntern()
|
||||||
try mod.intern(.{ .int = .{
|
else
|
||||||
.ty = enum_type.tag_ty,
|
try mod.intern_pool.getCoercedInts(
|
||||||
.storage = .{ .u64 = 0 },
|
mod.gpa,
|
||||||
} })
|
mod.intern_pool.indexToKey(enum_type.values.get(ip)[0]).int,
|
||||||
else
|
enum_type.tag_ty,
|
||||||
enum_type.values.get(ip)[0]).toValue(), ty),
|
),
|
||||||
|
} }),
|
||||||
else => return null,
|
else => return null,
|
||||||
}
|
}.toValue();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -37069,6 +37045,8 @@ fn intSubWithOverflowScalar(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const IntFromFloatMode = enum { exact, truncate };
|
||||||
|
|
||||||
fn intFromFloat(
|
fn intFromFloat(
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
block: *Block,
|
block: *Block,
|
||||||
@ -37076,6 +37054,7 @@ fn intFromFloat(
|
|||||||
val: Value,
|
val: Value,
|
||||||
float_ty: Type,
|
float_ty: Type,
|
||||||
int_ty: Type,
|
int_ty: Type,
|
||||||
|
mode: IntFromFloatMode,
|
||||||
) CompileError!Value {
|
) CompileError!Value {
|
||||||
const mod = sema.mod;
|
const mod = sema.mod;
|
||||||
if (float_ty.zigTypeTag(mod) == .Vector) {
|
if (float_ty.zigTypeTag(mod) == .Vector) {
|
||||||
@ -37084,14 +37063,14 @@ fn intFromFloat(
|
|||||||
const scalar_ty = int_ty.scalarType(mod);
|
const scalar_ty = int_ty.scalarType(mod);
|
||||||
for (result_data, 0..) |*scalar, i| {
|
for (result_data, 0..) |*scalar, i| {
|
||||||
const elem_val = try val.elemValue(sema.mod, 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 = .{
|
return (try mod.intern(.{ .aggregate = .{
|
||||||
.ty = int_ty.toIntern(),
|
.ty = int_ty.toIntern(),
|
||||||
.storage = .{ .elems = result_data },
|
.storage = .{ .elems = result_data },
|
||||||
} })).toValue();
|
} })).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
|
// float is expected to be finite and non-NaN
|
||||||
@ -37126,9 +37105,19 @@ fn intFromFloatScalar(
|
|||||||
val: Value,
|
val: Value,
|
||||||
float_ty: Type,
|
float_ty: Type,
|
||||||
int_ty: Type,
|
int_ty: Type,
|
||||||
|
mode: IntFromFloatMode,
|
||||||
) CompileError!Value {
|
) CompileError!Value {
|
||||||
const mod = sema.mod;
|
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);
|
const float = val.toFloat(f128, mod);
|
||||||
if (std.math.isNan(float)) {
|
if (std.math.isNan(float)) {
|
||||||
return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{
|
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 {
|
pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value {
|
||||||
return switch (mod.intern_pool.indexToKey(val.toIntern())) {
|
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) {
|
.int => |int| switch (int.storage) {
|
||||||
.big_int => |big_int| {
|
.big_int => |big_int| {
|
||||||
const float = bigIntToFloat(big_int.limbs, big_int.positive);
|
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" {
|
test "cast function with an opaque parameter" {
|
||||||
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||||
|
|
||||||
const Container = struct {
|
const Container = struct {
|
||||||
const Ctx = opaque {};
|
const Ctx = opaque {};
|
||||||
ctx: *Ctx,
|
ctx: *Ctx,
|
||||||
@ -2494,3 +2496,14 @@ test "@intFromBool on vector" {
|
|||||||
try S.doTheTest();
|
try S.doTheTest();
|
||||||
try comptime 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 std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const expect = std.testing.expect;
|
const expect = std.testing.expect;
|
||||||
|
const expectEqual = std.testing.expectEqual;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|
||||||
fn initStaticArray() [10]i32 {
|
fn initStaticArray() [10]i32 {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user