mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
Compare commits
1 commit
47bb210317
...
a17657f881
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a17657f881 |
6 changed files with 152 additions and 2 deletions
|
|
@ -3449,6 +3449,16 @@ void do_a_thing(struct Foo *foo) {
|
|||
</p>
|
||||
{#code|test_integer_widening.zig#}
|
||||
|
||||
{#header_close#}
|
||||
{#header_open|Type Coercion: Int to Float#}
|
||||
<p>
|
||||
{#link|Integers#} coerce to {#link|Floats#} if every possible integer value can be stored in the float
|
||||
without rounding (i.e. the integer's precision does not exceed the float's significand precision).
|
||||
Larger integer types that cannot be safely coerced must be explicitly casted with {#link|@floatFromInt#}.
|
||||
</p>
|
||||
{#code|test_int_to_float_coercion.zig#}
|
||||
{#code|test_failed_int_to_float_coercion.zig#}
|
||||
|
||||
{#header_close#}
|
||||
{#header_open|Type Coercion: Float to Int#}
|
||||
<p>
|
||||
|
|
|
|||
8
doc/langref/test_failed_int_to_float_coercion.zig
Normal file
8
doc/langref/test_failed_int_to_float_coercion.zig
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
test "integer type is too large for implicit cast to float" {
|
||||
var int: u25 = 123;
|
||||
_ = ∫
|
||||
const float: f32 = int;
|
||||
_ = float;
|
||||
}
|
||||
|
||||
// test_error=
|
||||
12
doc/langref/test_int_to_float_coercion.zig
Normal file
12
doc/langref/test_int_to_float_coercion.zig
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
const std = @import("std");
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
|
||||
test "implicit integer to float" {
|
||||
var int: u8 = 123;
|
||||
_ = ∫
|
||||
const float: f32 = int;
|
||||
const int_from_float: u8 = @intFromFloat(float);
|
||||
try expectEqual(int, int_from_float);
|
||||
}
|
||||
|
||||
// test
|
||||
18
src/Sema.zig
18
src/Sema.zig
|
|
@ -28479,7 +28479,7 @@ pub fn coerce(
|
|||
};
|
||||
}
|
||||
|
||||
const CoersionError = CompileError || error{
|
||||
const CoercionError = CompileError || error{
|
||||
/// When coerce is called recursively, this error should be returned instead of using `fail`
|
||||
/// to ensure correct types in compile errors.
|
||||
NotCoercible,
|
||||
|
|
@ -28518,7 +28518,7 @@ fn coerceExtra(
|
|||
inst: Air.Inst.Ref,
|
||||
inst_src: LazySrcLoc,
|
||||
opts: CoerceOpts,
|
||||
) CoersionError!Air.Inst.Ref {
|
||||
) CoercionError!Air.Inst.Ref {
|
||||
if (dest_ty.isGenericPoison()) return inst;
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
|
|
@ -28945,6 +28945,20 @@ fn coerceExtra(
|
|||
if (!opts.report_err) return error.NotCoercible;
|
||||
return sema.failWithNeededComptime(block, inst_src, .{ .simple = .casted_to_comptime_float });
|
||||
}
|
||||
const int_info = inst_ty.intInfo(zcu);
|
||||
const int_precision = int_info.bits - @intFromBool(int_info.signedness == .signed);
|
||||
const float_precision: u8 = switch (dest_ty.toIntern()) {
|
||||
.f16_type => 11,
|
||||
.f32_type => 24,
|
||||
.f64_type => 53,
|
||||
.f80_type => 64,
|
||||
.f128_type => 113,
|
||||
else => unreachable,
|
||||
};
|
||||
if (int_precision <= float_precision) {
|
||||
try sema.requireRuntimeBlock(block, inst_src, null);
|
||||
return block.addTyOp(.float_from_int, dest_ty, inst);
|
||||
}
|
||||
break :int;
|
||||
};
|
||||
const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, pt, .sema);
|
||||
|
|
|
|||
|
|
@ -157,6 +157,60 @@ test "@floatFromInt(f80)" {
|
|||
try comptime S.doTheTest(i256);
|
||||
}
|
||||
|
||||
test "type coercion from int to float" {
|
||||
const check = struct {
|
||||
// Check that an integer value can be coerced to a float type and
|
||||
// then converted back to the original value without rounding issues.
|
||||
fn value(Float: type, int: anytype) !void {
|
||||
const float: Float = int;
|
||||
const Int = @TypeOf(int);
|
||||
try std.testing.expectEqual(int, @as(Int, @intFromFloat(float)));
|
||||
if (Float != f80) { // https://codeberg.org/ziglang/zig/issues/30035
|
||||
try std.testing.expectEqual(int, @as(Int, @intFromFloat(@ceil(float))));
|
||||
try std.testing.expectEqual(int, @as(Int, @intFromFloat(@floor(float))));
|
||||
}
|
||||
}
|
||||
|
||||
// Exhaustively check that all possible values of the integer type can
|
||||
// safely be coerced to the float type.
|
||||
fn allValues(Float: type, Int: type) !void {
|
||||
var int: Int = std.math.minInt(Int);
|
||||
while (int < std.math.maxInt(Int)) : (int += 1)
|
||||
try value(Float, int);
|
||||
}
|
||||
|
||||
// Check that the min and max values of the integer type can safely be
|
||||
// coerced to the float type.
|
||||
fn edgeValues(Float: type, Int: type) !void {
|
||||
var int: Int = std.math.minInt(Int);
|
||||
try value(Float, int);
|
||||
int = std.math.maxInt(Int);
|
||||
try value(Float, int);
|
||||
}
|
||||
};
|
||||
|
||||
try check.allValues(f16, u11);
|
||||
try check.allValues(f16, i12);
|
||||
|
||||
try check.edgeValues(f32, u24);
|
||||
try check.edgeValues(f32, i25);
|
||||
|
||||
try check.edgeValues(f64, u53);
|
||||
try check.edgeValues(f64, i54);
|
||||
|
||||
try check.edgeValues(f80, u64);
|
||||
try check.edgeValues(f80, i65);
|
||||
|
||||
try check.edgeValues(f128, u113);
|
||||
try check.edgeValues(f128, i114);
|
||||
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
|
||||
// Basic sanity check that the coercions work for vectors too.
|
||||
const int_vec: @Vector(2, u24) = @splat(123);
|
||||
try check.value(@Vector(2, f32), int_vec);
|
||||
}
|
||||
|
||||
test "@intFromFloat" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
|
|
|
|||
52
test/cases/compile_errors/coerce_int_to_float.zig
Normal file
52
test/cases/compile_errors/coerce_int_to_float.zig
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// Test that integer types above a certain size will not coerce to a float.
|
||||
|
||||
fn testCoerce(Float: type, Int: type) void {
|
||||
var i: Int = 0;
|
||||
_ = &i;
|
||||
_ = @as(Float, i);
|
||||
}
|
||||
|
||||
export fn entry() void {
|
||||
testCoerce(f16, u11); // Okay
|
||||
testCoerce(f16, u12); // Too big
|
||||
|
||||
testCoerce(f16, i12);
|
||||
testCoerce(f16, i13);
|
||||
|
||||
testCoerce(f32, u24);
|
||||
testCoerce(f32, u25);
|
||||
|
||||
testCoerce(f32, i25);
|
||||
testCoerce(f32, i26);
|
||||
|
||||
testCoerce(f64, u53);
|
||||
testCoerce(f64, u54);
|
||||
|
||||
testCoerce(f64, i54);
|
||||
testCoerce(f64, i55);
|
||||
|
||||
testCoerce(f80, u64);
|
||||
testCoerce(f80, u65);
|
||||
|
||||
testCoerce(f80, i65);
|
||||
testCoerce(f80, i66);
|
||||
|
||||
testCoerce(f128, u113);
|
||||
testCoerce(f128, u114);
|
||||
|
||||
testCoerce(f128, i114);
|
||||
testCoerce(f128, i115);
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :6:20: error: expected type 'f16', found 'u12'
|
||||
// :6:20: error: expected type 'f16', found 'i13'
|
||||
// :6:20: error: expected type 'f32', found 'u25'
|
||||
// :6:20: error: expected type 'f32', found 'i26'
|
||||
// :6:20: error: expected type 'f64', found 'u54'
|
||||
// :6:20: error: expected type 'f64', found 'i55'
|
||||
// :6:20: error: expected type 'f80', found 'u65'
|
||||
// :6:20: error: expected type 'f80', found 'i66'
|
||||
// :6:20: error: expected type 'f128', found 'u114'
|
||||
// :6:20: error: expected type 'f128', found 'i115'
|
||||
Loading…
Add table
Reference in a new issue