mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Merge pull request #24632 from mlugg/lossy-int-to-float-coercion
Sema: compile error on lossy int to float coercion
This commit is contained in:
commit
04d7b491b4
7 changed files with 68 additions and 36 deletions
|
|
@ -1345,11 +1345,15 @@ pub fn lossyCast(comptime T: type, value: anytype) T {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.float, .comptime_float => {
|
.float, .comptime_float => {
|
||||||
|
// In extreme cases, we probably need a language enhancement to be able to
|
||||||
|
// specify a rounding mode here to prevent `@intFromFloat` panics.
|
||||||
|
const max: @TypeOf(value) = @floatFromInt(maxInt(T));
|
||||||
|
const min: @TypeOf(value) = @floatFromInt(minInt(T));
|
||||||
if (isNan(value)) {
|
if (isNan(value)) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (value >= maxInt(T)) {
|
} else if (value >= max) {
|
||||||
return maxInt(T);
|
return maxInt(T);
|
||||||
} else if (value <= minInt(T)) {
|
} else if (value <= min) {
|
||||||
return minInt(T);
|
return minInt(T);
|
||||||
} else {
|
} else {
|
||||||
return @intFromFloat(value);
|
return @intFromFloat(value);
|
||||||
|
|
@ -1366,7 +1370,7 @@ test lossyCast {
|
||||||
try testing.expect(lossyCast(i16, 70000.0) == @as(i16, 32767));
|
try testing.expect(lossyCast(i16, 70000.0) == @as(i16, 32767));
|
||||||
try testing.expect(lossyCast(u32, @as(i16, -255)) == @as(u32, 0));
|
try testing.expect(lossyCast(u32, @as(i16, -255)) == @as(u32, 0));
|
||||||
try testing.expect(lossyCast(i9, @as(u32, 200)) == @as(i9, 200));
|
try testing.expect(lossyCast(i9, @as(u32, 200)) == @as(i9, 200));
|
||||||
try testing.expect(lossyCast(u32, @as(f32, maxInt(u32))) == maxInt(u32));
|
try testing.expect(lossyCast(u32, @as(f32, @floatFromInt(maxInt(u32)))) == maxInt(u32));
|
||||||
try testing.expect(lossyCast(u32, nan(f32)) == 0);
|
try testing.expect(lossyCast(u32, nan(f32)) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -189,19 +189,19 @@ fn series(comptime T: type, abs: T) T {
|
||||||
2.5066282746310002701649081771338373386264310793408,
|
2.5066282746310002701649081771338373386264310793408,
|
||||||
};
|
};
|
||||||
const denominator = [_]T{
|
const denominator = [_]T{
|
||||||
0,
|
0.0,
|
||||||
39916800,
|
39916800.0,
|
||||||
120543840,
|
120543840.0,
|
||||||
150917976,
|
150917976.0,
|
||||||
105258076,
|
105258076.0,
|
||||||
45995730,
|
45995730.0,
|
||||||
13339535,
|
13339535.0,
|
||||||
2637558,
|
2637558.0,
|
||||||
357423,
|
357423.0,
|
||||||
32670,
|
32670.0,
|
||||||
1925,
|
1925.0,
|
||||||
66,
|
66.0,
|
||||||
1,
|
1.0,
|
||||||
};
|
};
|
||||||
var num: T = 0;
|
var num: T = 0;
|
||||||
var den: T = 0;
|
var den: T = 0;
|
||||||
|
|
@ -244,9 +244,9 @@ const expectApproxEqRel = std.testing.expectApproxEqRel;
|
||||||
test gamma {
|
test gamma {
|
||||||
inline for (&.{ f32, f64 }) |T| {
|
inline for (&.{ f32, f64 }) |T| {
|
||||||
const eps = @sqrt(std.math.floatEps(T));
|
const eps = @sqrt(std.math.floatEps(T));
|
||||||
try expectApproxEqRel(@as(T, 120), gamma(T, 6), eps);
|
try expectApproxEqRel(@as(T, 120.0), gamma(T, 6), eps);
|
||||||
try expectApproxEqRel(@as(T, 362880), gamma(T, 10), eps);
|
try expectApproxEqRel(@as(T, 362880.0), gamma(T, 10), eps);
|
||||||
try expectApproxEqRel(@as(T, 6402373705728000), gamma(T, 19), eps);
|
try expectApproxEqRel(@as(T, 6402373705728000.0), gamma(T, 19), eps);
|
||||||
|
|
||||||
try expectApproxEqRel(@as(T, 332.7590766955334570), gamma(T, 0.003), eps);
|
try expectApproxEqRel(@as(T, 332.7590766955334570), gamma(T, 0.003), eps);
|
||||||
try expectApproxEqRel(@as(T, 1.377260301981044573), gamma(T, 0.654), eps);
|
try expectApproxEqRel(@as(T, 1.377260301981044573), gamma(T, 0.654), eps);
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ fn ModfTests(comptime T: type) type {
|
||||||
r = modf(@as(T, 43874.3));
|
r = modf(@as(T, 43874.3));
|
||||||
try expectEqual(43874.0, r.ipart);
|
try expectEqual(43874.0, r.ipart);
|
||||||
// account for precision error
|
// account for precision error
|
||||||
const expected_b: T = 43874.3 - @as(T, 43874);
|
const expected_b: T = 43874.3 - @as(T, 43874.0);
|
||||||
try expectApproxEqAbs(expected_b, r.fpart, epsilon);
|
try expectApproxEqAbs(expected_b, r.fpart, epsilon);
|
||||||
|
|
||||||
r = modf(@as(T, 1234.340780));
|
r = modf(@as(T, 1234.340780));
|
||||||
|
|
|
||||||
|
|
@ -192,8 +192,8 @@ fn isOddInteger(x: f64) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
test isOddInteger {
|
test isOddInteger {
|
||||||
try expect(isOddInteger(math.maxInt(i64) * 2) == false);
|
try expect(isOddInteger(@floatFromInt(math.maxInt(i64) * 2)) == false);
|
||||||
try expect(isOddInteger(math.maxInt(i64) * 2 + 1) == false);
|
try expect(isOddInteger(@floatFromInt(math.maxInt(i64) * 2 + 1)) == false);
|
||||||
try expect(isOddInteger(1 << 53) == false);
|
try expect(isOddInteger(1 << 53) == false);
|
||||||
try expect(isOddInteger(12.0) == false);
|
try expect(isOddInteger(12.0) == false);
|
||||||
try expect(isOddInteger(15.0) == true);
|
try expect(isOddInteger(15.0) == true);
|
||||||
|
|
|
||||||
|
|
@ -2774,11 +2774,11 @@ test "std.zon parse float" {
|
||||||
|
|
||||||
// Test big integers
|
// Test big integers
|
||||||
try std.testing.expectEqual(
|
try std.testing.expectEqual(
|
||||||
@as(f32, 36893488147419103231),
|
@as(f32, 36893488147419103231.0),
|
||||||
try fromSlice(f32, gpa, "36893488147419103231", null, .{}),
|
try fromSlice(f32, gpa, "36893488147419103231", null, .{}),
|
||||||
);
|
);
|
||||||
try std.testing.expectEqual(
|
try std.testing.expectEqual(
|
||||||
@as(f32, -36893488147419103231),
|
@as(f32, -36893488147419103231.0),
|
||||||
try fromSlice(f32, gpa, "-36893488147419103231", null, .{}),
|
try fromSlice(f32, gpa, "-36893488147419103231", null, .{}),
|
||||||
);
|
);
|
||||||
try std.testing.expectEqual(@as(f128, 0x1ffffffffffffffff), try fromSlice(
|
try std.testing.expectEqual(@as(f128, 0x1ffffffffffffffff), try fromSlice(
|
||||||
|
|
@ -2788,7 +2788,7 @@ test "std.zon parse float" {
|
||||||
null,
|
null,
|
||||||
.{},
|
.{},
|
||||||
));
|
));
|
||||||
try std.testing.expectEqual(@as(f32, 0x1ffffffffffffffff), try fromSlice(
|
try std.testing.expectEqual(@as(f32, @floatFromInt(0x1ffffffffffffffff)), try fromSlice(
|
||||||
f32,
|
f32,
|
||||||
gpa,
|
gpa,
|
||||||
"0x1ffffffffffffffff",
|
"0x1ffffffffffffffff",
|
||||||
|
|
|
||||||
41
src/Sema.zig
41
src/Sema.zig
|
|
@ -28745,17 +28745,36 @@ fn coerceExtra(
|
||||||
break :int;
|
break :int;
|
||||||
};
|
};
|
||||||
const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, pt, .sema);
|
const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, pt, .sema);
|
||||||
// TODO implement this compile error
|
const fits: bool = switch (ip.indexToKey(result_val.toIntern())) {
|
||||||
//const int_again_val = try result_val.intFromFloat(sema.arena, inst_ty);
|
else => unreachable,
|
||||||
//if (!int_again_val.eql(val, inst_ty, zcu)) {
|
.undef => true,
|
||||||
// return sema.fail(
|
.float => |float| fits: {
|
||||||
// block,
|
var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
|
||||||
// inst_src,
|
const operand_big_int = val.toBigInt(&buffer, zcu);
|
||||||
// "type '{f}' cannot represent integer value '{f}'",
|
switch (float.storage) {
|
||||||
// .{ dest_ty.fmt(pt), val },
|
inline else => |x| {
|
||||||
// );
|
if (!std.math.isFinite(x)) break :fits false;
|
||||||
//}
|
var result_big_int: std.math.big.int.Mutable = .{
|
||||||
return Air.internedToRef(result_val.toIntern());
|
.limbs = try sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(x)),
|
||||||
|
.len = undefined,
|
||||||
|
.positive = undefined,
|
||||||
|
};
|
||||||
|
switch (result_big_int.setFloat(x, .nearest_even)) {
|
||||||
|
.inexact => break :fits false,
|
||||||
|
.exact => {},
|
||||||
|
}
|
||||||
|
break :fits result_big_int.toConst().eql(operand_big_int);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (!fits) return sema.fail(
|
||||||
|
block,
|
||||||
|
inst_src,
|
||||||
|
"type '{f}' cannot represent integer value '{f}'",
|
||||||
|
.{ dest_ty.fmt(pt), val.fmtValue(pt) },
|
||||||
|
);
|
||||||
|
return .fromValue(result_val);
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
export fn foo() void {
|
||||||
|
const int: u16 = 65535;
|
||||||
|
const float: f16 = int;
|
||||||
|
_ = float;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error
|
||||||
|
//
|
||||||
|
// :3:24: error: type 'f16' cannot represent integer value '65535'
|
||||||
Loading…
Add table
Reference in a new issue