fix: 符号原语数值与字符串转换改抛类型错误

This commit is contained in:
2026-09-17 23:32:28 +00:00
parent 5768febadb
commit 4d0f11e30a
11 changed files with 219 additions and 60 deletions
+5 -1
View File
@@ -31,7 +31,11 @@ macro_rules! binary_arith {
// `{valueOf: () => 2n}` 需先 ToPrimitive 再判定),统一放 coerce 之后。
let l = $self.coerce_primitive_bounded(lv, false)?;
let r = $self.coerce_primitive_bounded(rv, false)?;
if l.is_bigint() && r.is_bigint() {
if l.is_symbol() || r.is_symbol() {
// ToNumber(Symbol) 抛 TypeError(ECMA-262 §7.1.4),先于 BigInt 混合判定。
$self.raise_type_error("Cannot convert a Symbol value to a number")?;
$self.regs[$rd] = JsValue::undefined();
} else if l.is_bigint() && r.is_bigint() {
// 包装对象 coerce 后暴露双 BigInt(如 Object(2n) / 2n)。
let lv = $self.bigint_value(l).clone();
let rv = $self.bigint_value(r).clone();
+10 -5
View File
@@ -5,15 +5,12 @@ use oxide_runtime_api as coercion;
use oxide_types::error::JsError;
use oxide_types::object::JsObject;
use oxide_types::private_key::make_well_known_symbol_key;
use oxide_types::private_key::{make_well_known_symbol_key, WELL_KNOWN_SYMBOL_TO_PRIMITIVE};
use oxide_types::value::{JsValue, PTR_MASK};
use super::{format_error_message, js_error_kind, js_error_kind_name, Vm};
use crate::vm_debug;
/// `Symbol.toPrimitive` 的 well-known symbol 下标。
const TO_PRIMITIVE_SYMBOL_ID: u32 = 5;
impl Vm {
/// ToPrimitive 有界版:按规范序把对象转为原始值,失败统一抛 `TypeError`。
///
@@ -51,7 +48,7 @@ impl Vm {
// ECMA-262 §7.1.1 step 1:exotic 对象上(沿原型链读取)的 Symbol.toPrimitive 优先于
// OrdinaryToPrimitive;well-known symbol 键恒定,直接取保留槽。
let sym_si = make_well_known_symbol_key(TO_PRIMITIVE_SYMBOL_ID);
let sym_si = make_well_known_symbol_key(WELL_KNOWN_SYMBOL_TO_PRIMITIVE);
let exotic = {
let obj = unsafe { &*obj_ptr };
self.ordinary_get(obj, sym_si, value)?
@@ -148,8 +145,16 @@ impl Vm {
}
/// ToNumber 有界版:先按 number hint 做 ToPrimitive,再转 `f64`。
///
/// # 边界与前提
/// 原始值为 Symbol 时按规范(ECMA-262 §7.1.4)抛 `TypeError`,不落入
/// [`coercion::to_number`] 的宽松快路径(后者对该输入返回 `NaN`)。
pub(crate) fn coerce_number_bounded(&mut self, value: JsValue) -> Result<f64, String> {
let primitive = self.coerce_primitive_bounded(value, false)?;
if primitive.is_symbol() {
self.conversion_error("Cannot convert a Symbol value to a number")?;
return Ok(f64::NAN);
}
Ok(coercion::to_number(primitive))
}