fix: 类型化数组索引助手对 BigInt 实参按截断语义处理

This commit is contained in:
2026-09-22 10:13:30 +00:00
parent 550d8f4cba
commit f5c109c80e
+18 -1
View File
@@ -35,6 +35,15 @@ fn range_error<H: VmHost>(vm: &mut H, msg: &str) -> JsValue {
} }
fn to_index<H: VmHost>(vm: &mut H, value: JsValue, msg: &str) -> Result<usize, JsValue> { fn to_index<H: VmHost>(vm: &mut H, value: JsValue, msg: &str) -> Result<usize, JsValue> {
// ToIndex 的 BigInt 面:整数原语截断即自身,负值或超 2^53-1 抛
// RangeError(与数值臂同消息),无 NaN 概念。
if value.is_bigint() {
let b = vm.bigint_value(value);
if *b < BigInt::from(0) || *b > BigInt::from(9_007_199_254_740_991u64) {
return Err(range_error(vm, msg));
}
return Ok(b.to_usize().unwrap_or(0));
}
let n = match vm.coerce_number_bounded(value) { let n = match vm.coerce_number_bounded(value) {
Ok(n) => n, Ok(n) => n,
Err(e) => return Err(crate::iterator::engine_error(vm, &e)), Err(e) => return Err(crate::iterator::engine_error(vm, &e)),
@@ -51,6 +60,13 @@ fn to_index<H: VmHost>(vm: &mut H, value: JsValue, msg: &str) -> Result<usize, J
/// 按 ToIntegerOrInfinity 语义把索引归一化到 `[0, len]`(越界夹取);符号等不可 /// 按 ToIntegerOrInfinity 语义把索引归一化到 `[0, len]`(越界夹取);符号等不可
/// 转换值透传异常。 /// 转换值透传异常。
fn normalize_index<H: VmHost>(vm: &mut H, value: JsValue, len: usize) -> Result<usize, JsValue> { fn normalize_index<H: VmHost>(vm: &mut H, value: JsValue, len: usize) -> Result<usize, JsValue> {
// BigInt 面:ToIntegerOrInfinity 对整数原语即截断自身(无 NaN/±Infinity 臂),
// 超 isize 域饱和到对应端点后走同一负/正夹取尾段。
let int: isize = if value.is_bigint() {
let b = vm.bigint_value(value);
b.to_isize()
.unwrap_or(if *b < BigInt::from(0) { isize::MIN } else { isize::MAX })
} else {
let n = match vm.coerce_number_bounded(value) { let n = match vm.coerce_number_bounded(value) {
Ok(n) => n, Ok(n) => n,
Err(e) => return Err(crate::iterator::engine_error(vm, &e)), Err(e) => return Err(crate::iterator::engine_error(vm, &e)),
@@ -63,7 +79,8 @@ fn normalize_index<H: VmHost>(vm: &mut H, value: JsValue, len: usize) -> Result<
if n.is_infinite() { if n.is_infinite() {
return Ok(if n < 0.0 { 0 } else { len }); return Ok(if n < 0.0 { 0 } else { len });
} }
let int = n.trunc() as isize; n.trunc() as isize
};
if int < 0 { if int < 0 {
Ok(len.saturating_sub(int.unsigned_abs())) Ok(len.saturating_sub(int.unsigned_abs()))
} else { } else {