diff --git a/crates/oxide_dce/tests/runtime_eq.rs b/crates/oxide_dce/tests/runtime_eq.rs new file mode 100644 index 00000000..1bc7ab68 --- /dev/null +++ b/crates/oxide_dce/tests/runtime_eq.rs @@ -0,0 +1,66 @@ +//! 运行时等价对比(D-08):DCE 开/关两份字节码 lower + VM 执行结果一致。 +//! +//! 同一 JS 源码走两条管线:parse → emit →(dce 开/关)→ lower → `Vm::run`, +//! 对比顶层执行结果。纯表读错 VM handler 也能被此兜底(D-08)。 +//! **不经 `Compiler::compile`**(D-10:测试层直调底层函数,不依赖开关)。 + +use oxide_vm::vm::Vm; +use oxide_vm::JsValue; + +/// parse→emit→(可选 DCE)→lower→run 全链路,返回顶层执行结果。 +fn run_source(src: &str, dce: bool) -> Result { + let allocator = oxide_parser::Allocator::default(); + let program = oxide_parser::parse(&allocator, src).expect("parse failed"); + let mut ir = oxide_emit::Emitter::new().emit_program(&program).expect("emit failed"); + if dce { + oxide_dce::dce(&mut ir); + } + let module = oxide_ir::lower::lower(&ir).expect("lower failed"); + let mut vm = Vm::new(); + vm.run(&module) +} + +/// 结果规约成可断言形态:`(是否 Ok, 字符串化结果或错误消息)`。 +/// Err 双方同为 Err 且消息一致视为一致(如 const 重赋值样例两跑均抛 TypeError)。 +fn normalize(r: Result) -> (bool, String) { + match r { + Ok(v) => (true, v.to_string()), + Err(e) => (false, e), + } +} + +/// 死代码样例集(04-RESEARCH.md Pattern 5 清单)。 +/// 对每个样例:DCE 开与关分别执行,断言结果一致。 +#[test] +fn dead_code_removed_semantics_preserved() { + // 覆盖:表达式语句丢弃结果、重复赋值只读最后值、if(false) 分支、死闭包、 + // try/catch 内死代码、对象操作数算术(D-05 coerce 风险兜底)、 + // 顶层表达式返回值(HALT reg0 链,Pitfall 2)、先调用后丢弃(CALL 隐式 reg0,Pitfall 1)、 + // const 重赋值抛错保留(Pitfall 5)。 + let samples = [ + "1+2;3+4", // 语句丢弃结果 + "'a'+'b';5;", // 语句丢弃结果(字符串) + "var x=1; x=2; x;", // 重复赋值只读最后值 + "function a(){return 1;} if(false){a();} 3;", // if(false) 分支 + "function f(){}; 1;", // 死闭包 + "try{1+2;}catch(e){3;} 4;", // try/catch 内死代码 + "({valueOf(){side=1; return 1}})+2;", // 对象操作数算术(coerce 兜底) + "1+2", // 顶层表达式返回值(Pitfall 2) + "function f(){return 1;} f(); 2+3;", // 先调用后丢弃(Pitfall 1) + "const x=1; x=2;", // const 重赋值(Pitfall 5) + ]; + for src in samples { + let a = normalize(run_source(src, true)); + let b = normalize(run_source(src, false)); + assert_eq!(a, b, "DCE 前后语义不一致: {src}"); + } +} + +/// 单个样例 DCE 开/关断言(失败时给出独立测试名,便于定位)。 +#[test] +fn single_sample_top_level_return_value() { + let a = normalize(run_source("1+2", true)); + let b = normalize(run_source("1+2", false)); + assert_eq!(a, b, "顶层返回值在 DCE 后变化"); + assert_eq!(a, (true, "3".to_string()), "顶层 1+2 应返回 3"); +}