diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-01-29 14:25:43 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-01-29 14:27:28 -0700 |
| commit | f8e418c47d13189674bdf5f131c19fd811964579 (patch) | |
| tree | 7695c4d6ef606bae5f58c6a978b2f5642b298078 /src/Sema.zig | |
| parent | 5e60ee41272579bc5fef3d95c59180df6ab824c1 (diff) | |
| download | zig-f8e418c47d13189674bdf5f131c19fd811964579.tar.gz zig-f8e418c47d13189674bdf5f131c19fd811964579.zip | |
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
Diffstat (limited to 'src/Sema.zig')
| -rw-r--r-- | src/Sema.zig | 29 |
1 files changed, 19 insertions, 10 deletions
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()) { |
