From f8e418c47d13189674bdf5f131c19fd811964579 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 29 Jan 2022 14:25:43 -0700 Subject: Sema: improved comptime `%` syntax * comptime known 0 as a numerator returns comptime 0 independent of denominator. * negative numerator and denominator are allowed when the remainder is zero because that means the modulus would be also zero. * organize math behavior tests --- src/Sema.zig | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/Sema.zig b/src/Sema.zig index ac67b3f07f..1de4e2bb98 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8674,7 +8674,6 @@ fn analyzeArithmetic( // For integers: // Either operand being undef is a compile error because there exists // a possible value (TODO what is it?) that would invoke illegal behavior. - // TODO: can lhs zero be handled better? // TODO: can lhs undef be handled better? // // For floats: @@ -8690,8 +8689,8 @@ fn analyzeArithmetic( if (lhs_val.isUndef()) { return sema.failWithUseOfUndef(block, lhs_src); } - if (lhs_val.compareWithZero(.lt)) { - return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); + if (lhs_val.compareWithZero(.eq)) { + return sema.addConstant(scalar_type, Value.zero); } } else if (lhs_ty.isSignedInt()) { return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); @@ -8703,14 +8702,24 @@ fn analyzeArithmetic( if (rhs_val.compareWithZero(.eq)) { return sema.failWithDivideByZero(block, rhs_src); } - if (rhs_val.compareWithZero(.lt)) { - return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); - } if (maybe_lhs_val) |lhs_val| { - return sema.addConstant( - scalar_type, - try lhs_val.intRem(rhs_val, sema.arena), - ); + const rem_result = try lhs_val.intRem(rhs_val, sema.arena); + // If this answer could possibly be different by doing `intMod`, + // we must emit a compile error. Otherwise, it's OK. + if (rhs_val.compareWithZero(.lt) != lhs_val.compareWithZero(.lt) and + !rem_result.compareWithZero(.eq)) + { + const bad_src = if (lhs_val.compareWithZero(.lt)) + lhs_src + else + rhs_src; + return sema.failWithModRemNegative(block, bad_src, lhs_ty, rhs_ty); + } + if (lhs_val.compareWithZero(.lt)) { + // Negative + return sema.addConstant(scalar_type, Value.zero); + } + return sema.addConstant(scalar_type, rem_result); } break :rs .{ .src = lhs_src, .air_tag = .rem }; } else if (rhs_ty.isSignedInt()) { -- cgit v1.2.3