fix: 复合赋值旧值读改抛错读并补严格隐式全局写检查

This commit is contained in:
2026-10-19 01:12:24 +00:00
parent 8c87f5e5fa
commit 673d007b79
13 changed files with 382 additions and 77 deletions
@@ -86,17 +86,19 @@ fn sloppy_update_operator_undeclared_write_lands_on_global() {
assert!(r.is_bool() && r.as_bool(), "z++ 未声明写应落全局 NaN(undefined+1),实际 {:?}", r);
}
// ── 复合赋值:未声明名旧值读在 lval 求值步抛 ReferenceError(未解析引用不可
// GetValue,两模式同),不物化全局 NaN ──
#[test]
fn sloppy_compound_operator_undeclared_write_is_nan() {
let s = eval_str("w += 1; typeof w");
assert_eq!(s, "number", "w += 1 未声明名应为 NaN(typeof number),实际 {s}");
fn sloppy_compound_operator_undeclared_write_throws() {
let result = eval("w += 1");
assert_err_contains(result, "w is not defined");
}
// ── 逻辑赋值:未声明名 ||= 短路建全局 ──
// ── 逻辑赋值:未声明名旧值读抛 ReferenceError,短路路径不可达,不物化全局 ──
#[test]
fn sloppy_logical_assign_undeclared_write_lands_on_global() {
let r = eval_many(&["p ||= 5", "globalThis.p === 5"]).unwrap();
assert!(r.is_bool() && r.as_bool(), "p ||= 5 未声明写应落全局为 5,实际 {:?}", r);
fn sloppy_logical_assign_undeclared_write_throws() {
let result = eval("p ||= 5");
assert_err_contains(result, "p is not defined");
}
// ── for-in 左侧未声明标识符:首个键后建全局 ──
@@ -59,12 +59,12 @@ fn with_fallback_declared_var_writes_outer_binding() {
}
#[test]
fn with_fallback_compound_undeclared_write_keeps_existing_behavior() {
// 复合赋值回退臂走静态复合路径:未声明名旧值按 undefined 读
// (GetBaseValue 语义不抛),复合运算结果落隐式全局。
assert_eq!(
eval("var o={}; with(o){x+=1;} isNaN(globalThis.x)"),
"true",
"with 回退未声明名复合赋值保持既有读 undefined 行为"
fn with_fallback_compound_undeclared_write_throws() {
// 复合赋值回退臂走静态复合路径:未声明名旧值读在 lval 求值步抛
// ReferenceError(未解析引用不可 GetValue,两模式同),不物化隐式全局。
let s = eval("var o={}; with(o){x+=1;}");
assert!(
s.contains("ReferenceError") && s.contains("x is not defined"),
"with 回退未声明名复合赋值应抛 ReferenceError,实际 {s}"
);
}