authorgravatar for adria.arrufat@gmail.comAdrià Arrufat <adria.arrufat@gmail.com> 2026-03-11 22:17:26+09:00
committergravatar for adria.arrufat@gmail.comAdrià Arrufat <adria.arrufat@gmail.com> 2026-03-11 22:17:26+09:00
loga25f94ddb26d218af2ecbf7cdf943ac755a355a6
treea4f01ead7ab55c864765531b303d829ccd92b906
parented6baf2d67c97184da5b041cb0810dafdda444a3

Sema: handle generic poison in rounding builtins


2 files changed, 42 insertions(+), 17 deletions(-)

src/Sema.zig+25-17
......@@ -20850,30 +20850,36 @@ fn zirRoundCast(
2085020850 const src = block.nodeOffset(extra.node);
2085120851 const operand_src = block.builtinCallArgSrc(extra.node, 0);
2085220852
20853 const builtin_name = switch (mode) {
20854 .round => "@round",
20855 .floor => "@floor",
20856 .ceil => "@ceil",
20857 .truncate => "@trunc",
20858 .exact => unreachable,
20859 };
20853 const dest_ty_or_poison = try sema.resolveTypeOrPoison(block, src, extra.lhs) orelse Type.generic_poison;
20854 var dest_ty = dest_ty_or_poison;
20855 if (!dest_ty.isGenericPoison()) {
20856 if (dest_ty.zigTypeTag(zcu) == .error_union) {
20857 dest_ty = dest_ty.errorUnionPayload(zcu);
20858 }
20859 if (dest_ty.zigTypeTag(zcu) == .optional) {
20860 dest_ty = dest_ty.childType(zcu);
20861 }
20862 }
2086020863
20861 const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu_opt, builtin_name);
2086220864 const operand = sema.resolveInst(extra.rhs);
2086320865 const operand_ty = sema.typeOf(operand);
2086420866
20865 try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, src, operand_src);
20866 const dest_scalar_ty = dest_ty.scalarType(zcu);
20867 const is_poison = dest_ty.isGenericPoison();
20868 if (!is_poison) {
20869 try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, src, operand_src);
20870 }
20871 const dest_scalar_ty = if (is_poison) dest_ty else dest_ty.scalarType(zcu);
2086720872 const operand_scalar_ty = operand_ty.scalarType(zcu);
2086820873
20869 if (dest_scalar_ty.zigTypeTag(zcu) == .float or dest_scalar_ty.zigTypeTag(zcu) == .comptime_float) {
20874 if (is_poison or dest_scalar_ty.zigTypeTag(zcu) == .float or dest_scalar_ty.zigTypeTag(zcu) == .comptime_float) {
2087020875 const coerced_operand = try sema.coerce(block, dest_ty, operand, operand_src);
20876 const math_ty = if (is_poison) operand_ty else dest_ty;
2087120877
2087220878 const result_ref = switch (mode) {
20873 .round => try sema.maybeConstantUnaryMath(coerced_operand, dest_ty, Value.round),
20874 .floor => try sema.maybeConstantUnaryMath(coerced_operand, dest_ty, Value.floor),
20875 .ceil => try sema.maybeConstantUnaryMath(coerced_operand, dest_ty, Value.ceil),
20876 .truncate => try sema.maybeConstantUnaryMath(coerced_operand, dest_ty, Value.trunc),
20879 .round => try sema.maybeConstantUnaryMath(coerced_operand, math_ty, Value.round),
20880 .floor => try sema.maybeConstantUnaryMath(coerced_operand, math_ty, Value.floor),
20881 .ceil => try sema.maybeConstantUnaryMath(coerced_operand, math_ty, Value.ceil),
20882 .truncate => try sema.maybeConstantUnaryMath(coerced_operand, math_ty, Value.trunc),
2087720883 else => unreachable,
2087820884 };
2087920885
......@@ -25122,9 +25128,11 @@ fn zirRoundOpType(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDa
2512225128 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
2512325129 const operand_src = block.builtinCallArgSrc(extra.node, 0);
2512425130
25125 const dest_ty = try sema.resolveDestType(block, operand_src, extra.operand, .remove_eu_opt, "type hint");
25131 const dest_ty_or_poison = try sema.resolveTypeOrPoison(block, operand_src, extra.operand) orelse Type.generic_poison;
25132
25133 if (dest_ty_or_poison.isGenericPoison()) return .generic_poison_type;
2512625134
25127 const float_ty = dest_ty.optEuBaseType(zcu);
25135 const float_ty = dest_ty_or_poison.optEuBaseType(zcu);
2512825136 switch (float_ty.scalarType(zcu).zigTypeTag(zcu)) {
2512925137 .float, .comptime_float => return .fromType(float_ty),
2513025138 else => return .comptime_float_type,
test/behavior/cast.zig+17
......@@ -253,6 +253,23 @@ fn testIntFromFloats() !void {
253253 try expectTruncCast(f32, -128.2, i8, -128);
254254}
255255
256test "rounding builtins with anytype and context propagation" {
257 const S = struct {
258 const x: i32 = 10;
259 fn check(expected: anytype, actual: anytype) !void {
260 try expectEqual(expected, actual);
261 }
262 };
263 try expectEqual(@as(f32, 1.0), @round(@as(f32, 1.4)));
264 try S.check(@as(f32, 1.0), @round(@as(f32, 1.4)));
265
266 const y: f64 = @floor(@floatFromInt(S.x));
267 try expect(y == 10.0);
268
269 try expectEqual(1.0, @round(1.4));
270 try S.check(1.0, @round(1.4));
271}
272
256273fn expectIntFromFloat(comptime F: type, f: F, comptime I: type, i: I) !void {
257274 try expect(@as(I, @intFromFloat(f)) == i);
258275}