mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
Compare commits
1 commit
a17657f881
...
464fcac802
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
464fcac802 |
6 changed files with 150 additions and 2 deletions
|
|
@ -3449,6 +3449,16 @@ void do_a_thing(struct Foo *foo) {
|
||||||
</p>
|
</p>
|
||||||
{#code|test_integer_widening.zig#}
|
{#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_close#}
|
||||||
{#header_open|Type Coercion: Float to Int#}
|
{#header_open|Type Coercion: Float to Int#}
|
||||||
<p>
|
<p>
|
||||||
|
|
|
||||||
8
doc/langref/test_failed_into_to_float_coercion.zig
Normal file
8
doc/langref/test_failed_into_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
|
|
@ -28477,7 +28477,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`
|
/// When coerce is called recursively, this error should be returned instead of using `fail`
|
||||||
/// to ensure correct types in compile errors.
|
/// to ensure correct types in compile errors.
|
||||||
NotCoercible,
|
NotCoercible,
|
||||||
|
|
@ -28516,7 +28516,7 @@ fn coerceExtra(
|
||||||
inst: Air.Inst.Ref,
|
inst: Air.Inst.Ref,
|
||||||
inst_src: LazySrcLoc,
|
inst_src: LazySrcLoc,
|
||||||
opts: CoerceOpts,
|
opts: CoerceOpts,
|
||||||
) CoersionError!Air.Inst.Ref {
|
) CoercionError!Air.Inst.Ref {
|
||||||
if (dest_ty.isGenericPoison()) return inst;
|
if (dest_ty.isGenericPoison()) return inst;
|
||||||
const pt = sema.pt;
|
const pt = sema.pt;
|
||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
|
|
@ -28943,6 +28943,20 @@ fn coerceExtra(
|
||||||
if (!opts.report_err) return error.NotCoercible;
|
if (!opts.report_err) return error.NotCoercible;
|
||||||
return sema.failWithNeededComptime(block, inst_src, .{ .simple = .casted_to_comptime_float });
|
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;
|
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);
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,58 @@ test "@floatFromInt(f80)" {
|
||||||
try comptime S.doTheTest(i256);
|
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);
|
||||||
|
|
||||||
|
// 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" {
|
test "@intFromFloat" {
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_sparc64) 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