mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
fix: SET 原始值接收者按严格性分流并补脏重建本体标
This commit is contained in:
@@ -764,9 +764,9 @@ pub(crate) fn async_iterator_async_dispose(vm: &mut Vm, args: &[u8]) -> NativeRe
|
||||
match vm.ordinary_get(obj, si, o) {
|
||||
Ok(r) => Some(r),
|
||||
Err(_) => {
|
||||
let exc = vm
|
||||
.take_uncaught_value()
|
||||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, "AsyncIterator return getter failed"));
|
||||
let exc = vm.take_uncaught_value().unwrap_or_else(|| {
|
||||
oxide_builtins::error::create_from_text(vm, "AsyncIterator return getter failed")
|
||||
});
|
||||
let _ = vm.reject_promise(promise, exc);
|
||||
return NativeResult::Ok(promise);
|
||||
}
|
||||
@@ -786,9 +786,9 @@ pub(crate) fn async_iterator_async_dispose(vm: &mut Vm, args: &[u8]) -> NativeRe
|
||||
let result = match vm.call_function_sync(ret, o, &[JsValue::undefined()]) {
|
||||
Ok(r) => r,
|
||||
Err(_) => {
|
||||
let exc = vm
|
||||
.take_uncaught_value()
|
||||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, "AsyncIterator return method call failed"));
|
||||
let exc = vm.take_uncaught_value().unwrap_or_else(|| {
|
||||
oxide_builtins::error::create_from_text(vm, "AsyncIterator return method call failed")
|
||||
});
|
||||
let _ = vm.reject_promise(promise, exc);
|
||||
return NativeResult::Ok(promise);
|
||||
}
|
||||
@@ -886,8 +886,7 @@ pub(crate) fn init_async_generator_intrinsics(vm: &mut Vm) {
|
||||
let world = vm.session.builtin_world();
|
||||
// %AsyncGeneratorPrototype% 链到 %AsyncIteratorPrototype%(规范原型链),
|
||||
// 方法 next/return/throw 挂其自身。
|
||||
let async_iterator_proto_val =
|
||||
JsValue::from_js_object(world.async_iterator_proto.as_ptr() as *mut JsObject);
|
||||
let async_iterator_proto_val = JsValue::from_js_object(world.async_iterator_proto.as_ptr() as *mut JsObject);
|
||||
|
||||
// %AsyncGeneratorPrototype%:proto = %AsyncIteratorPrototype%。
|
||||
let mut ag_proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, async_iterator_proto_val));
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::bindings::{apply_binding_table, bind_accessor_getter, bind_well_known_method, configure_native_constructor};
|
||||
use crate::bindings::{
|
||||
apply_binding_table, bind_accessor_getter, bind_well_known_method, configure_native_constructor,
|
||||
};
|
||||
use oxide_kernel::kernel::{KernelCore, KernelSession};
|
||||
use oxide_types::object::{JsObject, PropAttributes};
|
||||
use oxide_types::private_key::{make_well_known_symbol_key, WELL_KNOWN_SYMBOL_TO_PRIMITIVE};
|
||||
|
||||
@@ -571,8 +571,9 @@ fn bind_iterator_protos(core: &Arc<KernelCore>, session: &KernelSession) {
|
||||
// (经 return 方法关闭迭代器)。幂等:键槽已存在时跳过。
|
||||
let aiter_proto_ptr = world.async_iterator_proto.as_ptr() as *mut JsObject;
|
||||
let aiter_proto = unsafe { &mut *aiter_proto_ptr };
|
||||
let sym_aiter =
|
||||
oxide_types::private_key::make_well_known_symbol_key(oxide_types::private_key::WELL_KNOWN_SYMBOL_ASYNC_ITERATOR);
|
||||
let sym_aiter = oxide_types::private_key::make_well_known_symbol_key(
|
||||
oxide_types::private_key::WELL_KNOWN_SYMBOL_ASYNC_ITERATOR,
|
||||
);
|
||||
if core.shape_forge().lookup_position(aiter_proto.shape_id(), sym_aiter).is_none() {
|
||||
bind_well_known_method(
|
||||
world,
|
||||
@@ -586,7 +587,11 @@ fn bind_iterator_protos(core: &Arc<KernelCore>, session: &KernelSession) {
|
||||
}
|
||||
let sym_adispose =
|
||||
oxide_types::private_key::make_well_known_symbol_key(oxide_types::private_key::WELL_KNOWN_SYMBOL_ASYNC_DISPOSE);
|
||||
if core.shape_forge().lookup_position(aiter_proto.shape_id(), sym_adispose).is_none() {
|
||||
if core
|
||||
.shape_forge()
|
||||
.lookup_position(aiter_proto.shape_id(), sym_adispose)
|
||||
.is_none()
|
||||
{
|
||||
bind_well_known_method(
|
||||
world,
|
||||
core,
|
||||
|
||||
@@ -31,13 +31,24 @@ impl Vm {
|
||||
}
|
||||
}
|
||||
|
||||
/// SET 路径的接收者解析:对象直取;非对象经 ToObject 自动装箱
|
||||
/// (null/undefined 抛 TypeError,其余原始值写盒后丢弃盒,与规范
|
||||
/// OrdinarySetWithOwnDescriptor 的 ToObject 基语义一致)。
|
||||
/// SET 路径的接收者解析:对象直取;非对象按严格性分流——strict 抛
|
||||
/// TypeError(规范 OrdinarySetWithOwnDescriptor 的 ToObject 基语义在
|
||||
/// strict 下不 auto-box),sloppy 经 ToObject 自动装箱(null/undefined
|
||||
/// 抛 TypeError,其余原始值写盒后丢弃盒)。
|
||||
fn set_prop_base(&mut self, receiver: JsValue) -> Result<Option<*mut JsObject>, String> {
|
||||
if receiver.is_object() {
|
||||
return self.checked_object_ptr(receiver, "Cannot create property on non-object");
|
||||
}
|
||||
if self.current_strict() {
|
||||
self.raise_type_error("Cannot create property on a primitive value")?;
|
||||
return Ok(None);
|
||||
}
|
||||
// null/undefined:ToObject 抛可捕获 TypeError(经 raise 走 JS 异常,
|
||||
// 非 Rust Err 传播,try/catch 可接)。
|
||||
if receiver.is_null() || receiver.is_undefined() {
|
||||
self.raise_type_error("Cannot convert null or undefined to object")?;
|
||||
return Ok(None);
|
||||
}
|
||||
let boxed = coercion::to_object(receiver, self)?;
|
||||
Ok(Some(boxed.as_js_object_ptr()))
|
||||
}
|
||||
|
||||
@@ -427,9 +427,9 @@ fn error_to_string_tag_is_error() {
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(vm.lookup_str(r), Some("[object Error]".to_string()));
|
||||
// Error.prototype 自身同样判定为 Error。
|
||||
// Error.prototype 本体无 OBJ_TYPE_ERROR 标(普通对象),按规范品牌为 Object。
|
||||
let r = eval_in(&mut vm, "Object.prototype.toString.call(Error.prototype)").unwrap();
|
||||
assert_eq!(vm.lookup_str(r), Some("[object Error]".to_string()));
|
||||
assert_eq!(vm.lookup_str(r), Some("[object Object]".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -573,9 +573,10 @@ fn suppressed_error_call_without_new_creates_object() {
|
||||
#[test]
|
||||
fn suppressed_error_prototype_chain_and_shape() {
|
||||
let mut vm = make_vm();
|
||||
// 原型仅挂 constructor/name(name 与既有子类型一致排在 constructor 前),无 error/suppressed。
|
||||
// 原型挂 name/message/constructor(name 与既有子类型一致排在 constructor 前,
|
||||
// message 为规范空串自身属性),无 error/suppressed。
|
||||
let r = eval_in(&mut vm, "Object.getOwnPropertyNames(SuppressedError.prototype).join(',')").unwrap();
|
||||
assert_eq!(vm.lookup_str(r), Some("name,constructor".to_string()));
|
||||
assert_eq!(vm.lookup_str(r), Some("name,message,constructor".to_string()));
|
||||
// instanceof Error 走原型链,原型 [[Prototype]] = Error.prototype。
|
||||
assert_eq!(
|
||||
format!("{}", eval_in(&mut vm, "new SuppressedError('e','s') instanceof Error").unwrap()),
|
||||
|
||||
@@ -102,9 +102,19 @@ fn test_to_int32_and_to_uint32() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn primitive_property_write_throws_clean_type_error() {
|
||||
fn primitive_property_write_sloppy_auto_boxes() {
|
||||
// sloppy 模式:原始值接收者 auto-box,写盒后丢弃盒,不抛 TypeError。
|
||||
for source in ["'abc'.x = 1", "(5).foo = 1", "true.foo = 1"] {
|
||||
let err = eval(source);
|
||||
let result = eval(source);
|
||||
assert_eq!(result, "1", "sloppy auto-box should return 1 for {source}, got {result}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn primitive_property_write_strict_throws_clean_type_error() {
|
||||
// strict 模式:原始值接收者抛 clean TypeError(非内部 opcode 消息)。
|
||||
for source in ["'abc'.x = 1", "(5).foo = 1", "true.foo = 1"] {
|
||||
let err = eval(&format!("\"use strict\"; {source}"));
|
||||
assert!(err.contains("TypeError"), "expected TypeError for {source}, got {err}");
|
||||
assert!(
|
||||
!err.contains("IC_SET_PROP on non-object")
|
||||
|
||||
Reference in New Issue
Block a user