mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 顶层 var 撞 accessor 写点改 Set 语义对齐 node 实证
This commit is contained in:
Generated
+18
-18
@@ -1095,7 +1095,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1120,7 +1120,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1128,7 +1128,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1139,7 +1139,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1159,7 +1159,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1168,7 +1168,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1187,7 +1187,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1201,7 +1201,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1216,7 +1216,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1225,7 +1225,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1240,7 +1240,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1252,7 +1252,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1261,7 +1261,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1276,7 +1276,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1292,7 +1292,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1304,7 +1304,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1321,7 +1321,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"hashbrown 0.14.5",
|
||||
@@ -1333,7 +1333,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.8.23"
|
||||
version = "0.8.24"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -304,8 +304,9 @@ impl Vm {
|
||||
/// 定义全局 var 绑定数据属性:rd=全局对象,a=值,b=键。
|
||||
///
|
||||
/// 描述符语义(CreateGlobalVarBinding 写点,对照 node 锚定):
|
||||
/// - 已有 accessor 属性(可配置或不可配置):零修改返回——var 声明写点
|
||||
/// 不覆写访问器(两模式均不抛,值与描述符保持原样)。
|
||||
/// - 已有 accessor 属性(可配置或不可配置):走 Set 语义——有 setter 以
|
||||
/// 全局对象为 receiver 调用之;无 setter strict 抛 TypeError、sloppy 静默
|
||||
/// no-op(值与描述符均保持原样)。
|
||||
/// - 已有数据属性且不可写(可配置或不可配置):strict 抛 TypeError、
|
||||
/// sloppy 静默 no-op(规范不更新既有数据描述符,writable/enumerable/
|
||||
/// configurable 与值均保持原样)。
|
||||
@@ -324,14 +325,22 @@ impl Vm {
|
||||
let prop_name_si = self.property_key_si(self.regs[b])?;
|
||||
let value = self.regs[a];
|
||||
let obj = unsafe { &mut *obj_val.as_js_object_ptr() };
|
||||
// 已有属性:CreateGlobalVarBinding 不改既有描述符——accessor 形零修改
|
||||
// (不覆写、不抛);数据属性不可写时 strict 抛 TypeError、sloppy 静默
|
||||
// no-op;可写数据属性保 enumerable/configurable 仅更新值。
|
||||
// 已有属性:accessor 形走 Set 语义(有 setter 调用之、无 setter strict
|
||||
// 抛、sloppy 静默 no-op);数据属性不可写时 strict 抛 TypeError、sloppy
|
||||
// 静默 no-op;可写数据属性保 enumerable/configurable 仅更新值。
|
||||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(obj.shape_id(), prop_name_si) {
|
||||
if let Some(current) = obj.prop_meta_at(pos) {
|
||||
// accessor 形:var 声明写点不覆写访问器,两模式均零修改。
|
||||
// accessor 形:有 setter 以全局对象为 receiver 调用之;无 setter
|
||||
// strict 抛 TypeError、sloppy 静默 no-op(值与描述符均保持原样)。
|
||||
if current.is_accessor {
|
||||
return Ok(());
|
||||
if current.set.is_undefined() {
|
||||
return if self.current_strict() {
|
||||
self.raise_error_kind("TypeError", "property has no setter")
|
||||
} else {
|
||||
Ok(())
|
||||
};
|
||||
}
|
||||
return self.call_or_push_setter(current.set, obj_val, value, false);
|
||||
}
|
||||
// 既有数据属性不可写(可配置与不可配置同口径):strict 抛
|
||||
// TypeError、sloppy 静默 no-op。
|
||||
@@ -360,9 +369,10 @@ impl Vm {
|
||||
/// eval 脚本 var/函数声明的属性描述符)。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 属性已存在:CreateGlobalVarBinding 不改既有描述符——accessor 形零修改
|
||||
/// (不覆写、不抛);数据属性不可写时 strict 抛 TypeError、sloppy 静默
|
||||
/// no-op;可写数据属性保原描述符仅更新值。
|
||||
/// 1. 属性已存在:accessor 形走 Set 语义(有 setter 以全局对象为 receiver
|
||||
/// 调用之;无 setter strict 抛 TypeError、sloppy 静默 no-op);数据属性
|
||||
/// 不可写时 strict 抛 TypeError、sloppy 静默 no-op;可写数据属性保原
|
||||
/// 描述符仅更新值。
|
||||
/// 2. 属性缺失:新建可写/可枚举/可配置属性;全局对象不可扩展 → TypeError
|
||||
/// (两模式均抛,CreateGlobalVarBinding 语义)。
|
||||
///
|
||||
@@ -380,14 +390,23 @@ impl Vm {
|
||||
let global_ptr = self.session.global_object().as_ptr() as *mut JsObject;
|
||||
// SAFETY: 全局对象钉在 session 永久区,指针在 VM 生命周期内有效。
|
||||
let obj = unsafe { &mut *global_ptr };
|
||||
// 属性已存在:CreateGlobalVarBinding 不改既有描述符——accessor 形零修改
|
||||
// (不覆写、不抛);数据属性不可写时 strict 抛 TypeError、sloppy 静默
|
||||
// no-op;可写数据属性保原描述符仅更新值。
|
||||
// 属性已存在:accessor 形走 Set 语义(有 setter 调用之、无 setter
|
||||
// strict 抛、sloppy 静默 no-op);数据属性不可写时 strict 抛 TypeError、
|
||||
// sloppy 静默 no-op;可写数据属性保原描述符仅更新值。
|
||||
if let Some(pos) = self.kernel_core.shape_forge().lookup_position(obj.shape_id(), si) {
|
||||
if let Some(current) = obj.prop_meta_at(pos) {
|
||||
// accessor 形:var 声明写点不覆写访问器,两模式均零修改。
|
||||
// accessor 形:有 setter 以全局对象为 receiver 调用之;无 setter
|
||||
// strict 抛 TypeError、sloppy 静默 no-op(值与描述符均保持原样)。
|
||||
if current.is_accessor {
|
||||
return Ok(());
|
||||
if current.set.is_undefined() {
|
||||
return if self.current_strict() {
|
||||
self.raise_error_kind("TypeError", "property has no setter")
|
||||
} else {
|
||||
Ok(())
|
||||
};
|
||||
}
|
||||
let receiver = JsValue::from_js_object(global_ptr);
|
||||
return self.call_or_push_setter(current.set, receiver, value, false);
|
||||
}
|
||||
// 既有数据属性不可写:strict 抛 TypeError、sloppy 静默 no-op。
|
||||
if !current.attributes.writable() {
|
||||
|
||||
@@ -637,10 +637,11 @@ fn strict_var_init_on_builtin_math_updates_value() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn var_init_on_accessor_property_does_not_overwrite() {
|
||||
// accessor 形:var 声明写点不覆写访问器,两模式均零修改(描述符保持原样)。
|
||||
// 既有 accessor 须先于 GDI 存在,分两阶段。写面锚定:globalThis 反射见
|
||||
// 访问器原值(getter 返回 1),描述符保持 accessor 形(get 在、无 value 面)。
|
||||
fn var_init_on_accessor_property_no_setter() {
|
||||
// accessor 形(无 setter):var 声明写点走 Set 语义——sloppy 静默 no-op
|
||||
// (值与描述符均保持原样,getter 返回值不变、描述符保持 accessor 形);
|
||||
// strict 抛 TypeError(无 setter 可路由)。既有 accessor 须先于 GDI 存在,
|
||||
// 分两阶段。
|
||||
assert_two_phases_truthy(
|
||||
"Object.defineProperty(globalThis, 'acc', {get() { return 1; }, configurable: true})",
|
||||
"var acc = 2; globalThis.acc === 1",
|
||||
@@ -650,9 +651,42 @@ fn var_init_on_accessor_property_does_not_overwrite() {
|
||||
"var acc2 = 2; var d = Object.getOwnPropertyDescriptor(globalThis, 'acc2'); \
|
||||
typeof d.get === 'function' && d.value === undefined",
|
||||
);
|
||||
// strict 同形:accessor 零修改不抛。
|
||||
assert_two_phases_truthy(
|
||||
// strict:无 setter 抛 TypeError。
|
||||
let err = phase2_err_text(
|
||||
"Object.defineProperty(globalThis, 'acc3', {get() { return 1; }, configurable: true})",
|
||||
"'use strict'; var acc3 = 2; globalThis.acc3 === 1",
|
||||
"'use strict'; var acc3 = 2;",
|
||||
);
|
||||
assert!(err.contains("TypeError"), "应抛 TypeError,实际: {err}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn var_init_on_accessor_property_with_setter_calls_setter() {
|
||||
// accessor 形(有 setter):var 声明写点以全局对象为 receiver 调用 setter,
|
||||
// 两模式均不抛,描述符保持 accessor 形(getter 返回值不变)。
|
||||
assert_two_phases_truthy(
|
||||
"Object.defineProperty(globalThis, 'accs', {get() { return 1; }, \
|
||||
set(v) { globalThis.setterSaw = v; }, configurable: true}); true",
|
||||
"var accs = 2; globalThis.setterSaw === 2 && globalThis.accs === 1",
|
||||
);
|
||||
// strict 同形:setter 被调用、不抛。
|
||||
assert_two_phases_truthy(
|
||||
"Object.defineProperty(globalThis, 'accs2', {get() { return 1; }, \
|
||||
set(v) { globalThis.setterSaw2 = v; }, configurable: true}); true",
|
||||
"'use strict'; var accs2 = 2; globalThis.setterSaw2 === 2 && globalThis.accs2 === 1",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn var_init_on_nonconfigurable_accessor_no_setter() {
|
||||
// 不可配置 accessor 形(无 setter):与可配置形同口径——sloppy 静默 no-op、
|
||||
// strict 抛 TypeError(值与描述符均保持原样)。
|
||||
assert_two_phases_truthy(
|
||||
"Object.defineProperty(globalThis, 'accnc', {get() { return 1; }, configurable: false})",
|
||||
"var accnc = 2; globalThis.accnc === 1",
|
||||
);
|
||||
let err = phase2_err_text(
|
||||
"Object.defineProperty(globalThis, 'accnc2', {get() { return 1; }, configurable: false})",
|
||||
"'use strict'; var accnc2 = 2;",
|
||||
);
|
||||
assert!(err.contains("TypeError"), "应抛 TypeError,实际: {err}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user