fix: BigInt SUB/MUL with 0n no longer raise Division by zero

binary_arith! applied an unconditional is_zero() guard, so x - 0n and
x * 0n (and wrapped-object variants) incorrectly threw RangeError.
Only DIV/MOD legitimately reject BigInt zero divisors; SUB/MUL must
compute normally. test262 language/expressions/subtraction:
29/6 -> 30/5 (bigint-arithmetic now passes).
This commit is contained in:
爱特每羊队
2026-08-12 03:30:03 +08:00
parent f3c37911f7
commit b844505ec7
+9 -8
View File
@@ -80,7 +80,7 @@ macro_rules! throw_err {
} }
macro_rules! binary_arith { macro_rules! binary_arith {
($self:ident, $a:expr, $b:expr, $rd:expr, $op:tt) => {{ ($self:ident, $a:expr, $b:expr, $rd:expr, $op:tt, $check_zero:expr) => {{
let lv = $self.regs[$a]; let lv = $self.regs[$a];
let rv = $self.regs[$b]; let rv = $self.regs[$b];
if lv.is_int() && rv.is_int() { if lv.is_int() && rv.is_int() {
@@ -88,8 +88,9 @@ macro_rules! binary_arith {
} else if lv.is_bigint() && rv.is_bigint() { } else if lv.is_bigint() && rv.is_bigint() {
let l = $self.bigint_value(lv).clone(); let l = $self.bigint_value(lv).clone();
let r = $self.bigint_value(rv).clone(); let r = $self.bigint_value(rv).clone();
if r.is_zero() { if r.is_zero() && $check_zero {
// BigInt 除/模零:规范要求 RangeError(Number 路径走 f64 inf/NaN)。 // 仅除/模对 BigInt 零除数抛 RangeError;SUB/MUL 等其余二元运算
// 遇到 0n 必须正常计算(Number 路径走 f64 inf/NaN)。
$self.raise_error_kind("RangeError", "Division by zero")?; $self.raise_error_kind("RangeError", "Division by zero")?;
$self.regs[$rd] = JsValue::undefined(); $self.regs[$rd] = JsValue::undefined();
} else { } else {
@@ -104,7 +105,7 @@ macro_rules! binary_arith {
// 包装对象 coerce 后暴露双 BigInt(如 Object(2n) / 2n)。 // 包装对象 coerce 后暴露双 BigInt(如 Object(2n) / 2n)。
let lv = $self.bigint_value(l).clone(); let lv = $self.bigint_value(l).clone();
let rv = $self.bigint_value(r).clone(); let rv = $self.bigint_value(r).clone();
if rv.is_zero() { if rv.is_zero() && $check_zero {
$self.raise_error_kind("RangeError", "Division by zero")?; $self.raise_error_kind("RangeError", "Division by zero")?;
$self.regs[$rd] = JsValue::undefined(); $self.regs[$rd] = JsValue::undefined();
} else { } else {
@@ -1254,19 +1255,19 @@ impl Vm {
} }
OpCode::SUB => { OpCode::SUB => {
binary_arith!(self, a, b, rd, -); binary_arith!(self, a, b, rd, -, false);
} }
OpCode::MUL => { OpCode::MUL => {
binary_arith!(self, a, b, rd, *); binary_arith!(self, a, b, rd, *, false);
} }
OpCode::DIV => { OpCode::DIV => {
binary_arith!(self, a, b, rd, /); binary_arith!(self, a, b, rd, /, true);
} }
OpCode::MOD => { OpCode::MOD => {
binary_arith!(self, a, b, rd, %); binary_arith!(self, a, b, rd, %, true);
} }
OpCode::NEG => { OpCode::NEG => {