From e664bf4d81e9266ee4749b5da88cab4554499bf6 Mon Sep 17 00:00:00 2001 From: mlugg Date: Wed, 30 Jul 2025 23:22:32 +0100 Subject: [PATCH] Sema: compile error on lossy int to float coercion Resolves: #21586 --- src/Sema.zig | 41 ++++++++++++++----- .../int_to_float_coercion_loses_precision.zig | 9 ++++ 2 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 test/cases/compile_errors/int_to_float_coercion_loses_precision.zig diff --git a/src/Sema.zig b/src/Sema.zig index 94bf21e03b..edba4e6874 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -28733,17 +28733,36 @@ fn coerceExtra( break :int; }; const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, pt, .sema); - // TODO implement this compile error - //const int_again_val = try result_val.intFromFloat(sema.arena, inst_ty); - //if (!int_again_val.eql(val, inst_ty, zcu)) { - // return sema.fail( - // block, - // inst_src, - // "type '{f}' cannot represent integer value '{f}'", - // .{ dest_ty.fmt(pt), val }, - // ); - //} - return Air.internedToRef(result_val.toIntern()); + const fits: bool = switch (ip.indexToKey(result_val.toIntern())) { + else => unreachable, + .undef => true, + .float => |float| fits: { + var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined; + const operand_big_int = val.toBigInt(&buffer, zcu); + switch (float.storage) { + inline else => |x| { + if (!std.math.isFinite(x)) break :fits false; + var result_big_int: std.math.big.int.Mutable = .{ + .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 => {}, }, diff --git a/test/cases/compile_errors/int_to_float_coercion_loses_precision.zig b/test/cases/compile_errors/int_to_float_coercion_loses_precision.zig new file mode 100644 index 0000000000..bc1d8e7dee --- /dev/null +++ b/test/cases/compile_errors/int_to_float_coercion_loses_precision.zig @@ -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'