mirror of
https://github.com/ziglang/zig.git
synced 2025-01-23 18:31:44 +00:00
allow division and remainder operators sometimes
when the values are comptime known and the result would be the same, allow `/` and `%` for signed integers and floats. closes #365
This commit is contained in:
parent
157af4332a
commit
29beb603b7
@ -259,7 +259,6 @@ bool bignum_rem(BigNum *dest, BigNum *op1, BigNum *op2) {
|
||||
if (dest->kind == BigNumKindFloat) {
|
||||
dest->data.x_float = fmod(op1->data.x_float, op2->data.x_float);
|
||||
} else {
|
||||
assert(!op2->is_negative);
|
||||
dest->data.x_uint = op1->data.x_uint % op2->data.x_uint;
|
||||
dest->is_negative = op1->is_negative;
|
||||
bignum_normalize(dest);
|
||||
@ -274,7 +273,6 @@ bool bignum_mod(BigNum *dest, BigNum *op1, BigNum *op2) {
|
||||
if (dest->kind == BigNumKindFloat) {
|
||||
dest->data.x_float = fmod(fmod(op1->data.x_float, op2->data.x_float) + op2->data.x_float, op2->data.x_float);
|
||||
} else {
|
||||
assert(!op2->is_negative);
|
||||
if (op1->is_negative) {
|
||||
dest->data.x_uint = (op2->data.x_uint - op1->data.x_uint % op2->data.x_uint) % op2->data.x_uint;
|
||||
} else {
|
||||
|
56
src/ir.cpp
56
src/ir.cpp
@ -8209,25 +8209,59 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
|
||||
|
||||
bool is_int = resolved_type->id == TypeTableEntryIdInt || resolved_type->id == TypeTableEntryIdNumLitInt;
|
||||
bool is_signed = ((resolved_type->id == TypeTableEntryIdInt && resolved_type->data.integral.is_signed) ||
|
||||
resolved_type->id == TypeTableEntryIdFloat ||
|
||||
(resolved_type->id == TypeTableEntryIdNumLitFloat &&
|
||||
(op1->value.data.x_bignum.data.x_float < 0.0 || op2->value.data.x_bignum.data.x_float < 0.0)) ||
|
||||
(resolved_type->id == TypeTableEntryIdNumLitInt &&
|
||||
(op1->value.data.x_bignum.is_negative || op2->value.data.x_bignum.is_negative)));
|
||||
if (op_id == IrBinOpDivUnspecified) {
|
||||
if (is_signed) {
|
||||
ir_add_error(ira, &bin_op_instruction->base,
|
||||
buf_sprintf("division with '%s' and '%s': signed integers must use @divTrunc, @divFloor, or @divExact",
|
||||
buf_ptr(&op1->value.type->name),
|
||||
buf_ptr(&op2->value.type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
if (is_int && is_signed) {
|
||||
bool ok = false;
|
||||
if (instr_is_comptime(op1) && instr_is_comptime(op2)) {
|
||||
BigNum trunc_result;
|
||||
BigNum floor_result;
|
||||
if (bignum_div_trunc(&trunc_result, &op1->value.data.x_bignum, &op2->value.data.x_bignum)) {
|
||||
zig_unreachable();
|
||||
}
|
||||
if (bignum_div_floor(&floor_result, &op1->value.data.x_bignum, &op2->value.data.x_bignum)) {
|
||||
zig_unreachable();
|
||||
}
|
||||
if (bignum_cmp_eq(&trunc_result, &floor_result)) {
|
||||
ok = true;
|
||||
op_id = IrBinOpDivTrunc;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
ir_add_error(ira, &bin_op_instruction->base,
|
||||
buf_sprintf("division with '%s' and '%s': signed integers must use @divTrunc, @divFloor, or @divExact",
|
||||
buf_ptr(&op1->value.type->name),
|
||||
buf_ptr(&op2->value.type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
} else if (is_int) {
|
||||
op_id = IrBinOpDivTrunc;
|
||||
}
|
||||
} else if (op_id == IrBinOpRemUnspecified) {
|
||||
if (is_signed) {
|
||||
ir_add_error(ira, &bin_op_instruction->base,
|
||||
buf_sprintf("remainder division with '%s' and '%s': signed integers must use @rem or @mod",
|
||||
buf_ptr(&op1->value.type->name),
|
||||
buf_ptr(&op2->value.type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
bool ok = false;
|
||||
if (instr_is_comptime(op1) && instr_is_comptime(op2)) {
|
||||
BigNum rem_result;
|
||||
BigNum mod_result;
|
||||
if (bignum_rem(&rem_result, &op1->value.data.x_bignum, &op2->value.data.x_bignum)) {
|
||||
zig_unreachable();
|
||||
}
|
||||
if (bignum_mod(&mod_result, &op1->value.data.x_bignum, &op2->value.data.x_bignum)) {
|
||||
zig_unreachable();
|
||||
}
|
||||
ok = bignum_cmp_eq(&rem_result, &mod_result);
|
||||
}
|
||||
if (!ok) {
|
||||
ir_add_error(ira, &bin_op_instruction->base,
|
||||
buf_sprintf("remainder division with '%s' and '%s': signed integers and floats must use @rem or @mod",
|
||||
buf_ptr(&op1->value.type->name),
|
||||
buf_ptr(&op2->value.type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
op_id = IrBinOpRemRem;
|
||||
}
|
||||
|
@ -220,3 +220,12 @@ fn testFloatEqualityImpl(x: f64, y: f64) {
|
||||
const y2 = x + 1.0;
|
||||
assert(y == y2);
|
||||
}
|
||||
|
||||
test "allow signed integer division/remainder when values are comptime known and positive or exact" {
|
||||
assert(5 / 3 == 1);
|
||||
assert(-5 / -3 == 1);
|
||||
assert(-6 / 3 == -2);
|
||||
|
||||
assert(5 % 3 == 2);
|
||||
assert(-6 % 3 == 0);
|
||||
}
|
||||
|
@ -1722,5 +1722,5 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
\\ a % b
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:2:7: error: remainder division with 'i32' and 'i32': signed integers must use @rem or @mod");
|
||||
".tmp_source.zig:2:7: error: remainder division with 'i32' and 'i32': signed integers and floats must use @rem or @mod");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user