feat: 解构计算键通用 fallback 支持任意键表达式

This commit is contained in:
2026-08-16 13:49:17 +08:00
parent 457b1b874d
commit fd2b290927
2 changed files with 93 additions and 1 deletions
+3 -1
View File
@@ -286,7 +286,9 @@ impl Emitter {
ctx.inst(Inst::load_const(Operand::Reg(key_reg), key_idx)); ctx.inst(Inst::load_const(Operand::Reg(key_reg), key_idx));
Ok(key_reg) Ok(key_reg)
} }
_ => Err("computed destructuring key expression not supported".into()), // 其余键形态(CallExpression/Template/BigInt/RegExp 等):转回 Expression
// 走通用 emit 分发,键值运行时求值后由 GET_PROP_DYNAMIC 做 ToPropertyKey。
_ => self.emit_expression(key.to_expression(), ctx),
} }
} }
@@ -160,3 +160,93 @@ fn object_rest_keeps_numeric_key_from_shape_source() {
let s = unsafe { &*result.as_string_ptr() }.as_str().to_string(); let s = unsafe { &*result.as_string_ptr() }.as_str().to_string();
assert_eq!(s, "1,2"); assert_eq!(s, "1,2");
} }
// computed 解构键通用 fallback:CallExpression / Template / BigInt 等键表达式
// 走既有 emit 全域,键值运行时求值后经 ToPropertyKey 读属性。
#[test]
fn computed_key_call_expression_binding() {
let mut vm = Vm::new();
let result = eval(&mut vm, "function f() { return 'x'; } const { [f()]: a } = {x: 42}; a").unwrap();
assert_num(result, 42.0);
}
#[test]
fn computed_key_call_expression_throw_propagates() {
// 键求值抛错在属性读与绑定前抛出,错误透传不吞。
let mut vm = Vm::new();
let err = eval(
&mut vm,
"function thrower() { throw new TypeError('boom'); } const { [thrower()]: a } = {};",
)
.unwrap_err();
assert!(err.contains("boom"), "expected thrown error, got {err:?}");
}
#[test]
fn computed_key_template_literal_binding() {
// 无插值模板键折叠不可用,仍须正确求值(DYNAMIC 路径语义等价)。
let mut vm = Vm::new();
let result = eval(&mut vm, "const { [`x`]: a } = {x: 5}; a").unwrap();
assert_num(result, 5.0);
let result = eval(&mut vm, "const { [`x${'y'}`]: a } = {xy: 3}; a").unwrap();
assert_num(result, 3.0);
}
#[test]
fn computed_key_bigint_binding() {
// 1n 经 ToPropertyKey 转 "1",命中对象数字键。
let mut vm = Vm::new();
let result = eval(&mut vm, "const { [1n]: a } = {1: 9}; a").unwrap();
assert_num(result, 9.0);
}
#[test]
fn computed_key_call_expression_rest_excludes() {
// rest 排除数组收集运行时键值,computed 键与 rest 语义正确。
let mut vm = Vm::new();
let result = eval(
&mut vm,
"function k() { return 'x'; } const { [k()]: a, ...rest } = {x:1,y:2}; a + rest.y",
)
.unwrap();
assert_num(result, 3.0);
}
#[test]
fn computed_key_assignment_target() {
let mut vm = Vm::new();
let result = eval(&mut vm, "let a; function k() { return 'x'; } ({ [k()]: a } = {x: 7}); a").unwrap();
assert_num(result, 7.0);
}
#[test]
fn computed_key_nested_pattern() {
// 嵌套解构的 computed 键逐层求值。
let mut vm = Vm::new();
let result = eval(
&mut vm,
"function k1() { return 'x'; } function k2() { return 'y'; } const { [k1()]: { [k2()]: b } } = {x: {y: 3}}; b",
)
.unwrap();
assert_num(result, 3.0);
}
#[test]
fn computed_key_evaluated_before_default_and_getter() {
// 求值序:键先于默认值(键未命中才走默认值);getter 副作用发生在键求值之后。
let mut vm = Vm::new();
let result = eval(
&mut vm,
"const log = []; function k() { log.push('k'); return 'x'; } const { [k()]: a = (log.push('d'), 99) } = {}; log.join(',')",
)
.unwrap();
let s = unsafe { &*result.as_string_ptr() }.as_str().to_string();
assert_eq!(s, "k,d");
let result = eval(
&mut vm,
"let order=[]; function k() { order.push('key'); return 'x'; } const o = { get x() { order.push('get'); return 5; } }; const { [k()]: a } = o; a + ':' + order.join(',')",
)
.unwrap();
let s = unsafe { &*result.as_string_ptr() }.as_str().to_string();
assert_eq!(s, "5:key,get");
}