style: 格式化存量未整理文件

This commit is contained in:
2026-10-10 10:24:44 +00:00
parent 55313cf3a9
commit ba09284da5
5 changed files with 44 additions and 55 deletions
+2 -1
View File
@@ -76,7 +76,8 @@ impl CodeForge {
// 整结构比较(递归覆盖子模块树):只比顶层字节码会漏检嵌套 // 整结构比较(递归覆盖子模块树):只比顶层字节码会漏检嵌套
// 函数体内的同键异码。 // 函数体内的同键异码。
debug_assert_eq!( debug_assert_eq!(
module.as_ref(), &fresh, module.as_ref(),
&fresh,
"structural hash collision: cached module differs from recompiled for hash {hash}", "structural hash collision: cached module differs from recompiled for hash {hash}",
); );
} }
+1 -1
View File
@@ -10,7 +10,7 @@
//! 其内部绑定名仅精确键计入。 //! 其内部绑定名仅精确键计入。
use oxide_parser::{ use oxide_parser::{
ArrayAssignmentTarget, ArrayExpressionElement, Argument, AssignmentTarget, AssignmentTargetMaybeDefault, Argument, ArrayAssignmentTarget, ArrayExpressionElement, AssignmentTarget, AssignmentTargetMaybeDefault,
AssignmentTargetProperty, BindingPattern, ChainElement, Class, ClassElement, Declaration, AssignmentTargetProperty, BindingPattern, ChainElement, Class, ClassElement, Declaration,
ExportDefaultDeclarationKind, Expression, ForStatementInit, ForStatementLeft, Function, ImportDeclarationSpecifier, ExportDefaultDeclarationKind, Expression, ForStatementInit, ForStatementLeft, Function, ImportDeclarationSpecifier,
ModuleExportName, ObjectAssignmentTarget, ObjectPropertyKind, PropertyKey, SimpleAssignmentTarget, Statement, ModuleExportName, ObjectAssignmentTarget, ObjectPropertyKind, PropertyKey, SimpleAssignmentTarget, Statement,
@@ -255,7 +255,11 @@ fn call_spread_arguments_distinguished() {
fn array_spread_elements_distinguished() { fn array_spread_elements_distinguished() {
// spread 元素与值元素同位置须区分(形态标记逐位计入)。 // spread 元素与值元素同位置须区分(形态标记逐位计入)。
assert_ne!(compiled("[...a]"), compiled("[a]"), "spread vs value element must differ"); assert_ne!(compiled("[...a]"), compiled("[a]"), "spread vs value element must differ");
assert_ne!(structural("[...a, 1]"), structural("[a, 1]"), "spread element shape must be in both granularities"); assert_ne!(
structural("[...a, 1]"),
structural("[a, 1]"),
"spread element shape must be in both granularities"
);
} }
#[test] #[test]
+10 -2
View File
@@ -462,7 +462,9 @@ impl oxide_runtime_api::VmHost for Vm {
fn et_unregister(&self, target: *mut JsObject, type_si: u32, callback: JsValue, capture: bool) { fn et_unregister(&self, target: *mut JsObject, type_si: u32, callback: JsValue, capture: bool) {
let mut gc = self.realm.gc.borrow_mut(); let mut gc = self.realm.gc.borrow_mut();
let should_remove = gc.event_targets.get_mut(&target).is_some_and(|state| { let should_remove = gc.event_targets.get_mut(&target).is_some_and(|state| {
state.listeners.retain(|e| !(e.type_si == type_si && e.capture == capture && e.callback == callback)); state
.listeners
.retain(|e| !(e.type_si == type_si && e.capture == capture && e.callback == callback));
state.listeners.is_empty() state.listeners.is_empty()
}); });
if should_remove { if should_remove {
@@ -470,6 +472,12 @@ impl oxide_runtime_api::VmHost for Vm {
} }
} }
fn et_lookup(&self, target: *mut JsObject) -> Vec<ListenerEntry> { fn et_lookup(&self, target: *mut JsObject) -> Vec<ListenerEntry> {
self.realm.gc.borrow().event_targets.get(&target).map(|s| s.listeners.clone()).unwrap_or_default() self.realm
.gc
.borrow()
.event_targets
.get(&target)
.map(|s| s.listeners.clone())
.unwrap_or_default()
} }
} }
+19 -43
View File
@@ -62,22 +62,17 @@ const TARGET: &str = "var mc = new MessageChannel(); var t = mc.port1;";
/// dispatchEvent(new Event('x')) 返回 true(无 preventDefault)。 /// dispatchEvent(new Event('x')) 返回 true(无 preventDefault)。
#[test] #[test]
fn dispatch_event_returns_true() { fn dispatch_event_returns_true() {
assert_eq!( assert_eq!(eval(&format!("{TARGET} t.dispatchEvent(new Event('x'));")), "true");
eval(&format!("{TARGET} t.dispatchEvent(new Event('x'));")),
"true"
);
} }
/// preventDefault() 后 dispatchEvent 返回 false(cancelable 事件)。 /// preventDefault() 后 dispatchEvent 返回 false(cancelable 事件)。
#[test] #[test]
fn dispatch_event_returns_false_after_prevent_default() { fn dispatch_event_returns_false_after_prevent_default() {
assert_eq!( assert_eq!(
eval( eval(&format!(
&format!(
"{TARGET} t.addEventListener('x', function(e) {{ e.preventDefault(); }}); \ "{TARGET} t.addEventListener('x', function(e) {{ e.preventDefault(); }}); \
t.dispatchEvent(new Event('x', {{ cancelable: true }}));" t.dispatchEvent(new Event('x', {{ cancelable: true }}));"
) )),
),
"false" "false"
); );
} }
@@ -86,12 +81,10 @@ fn dispatch_event_returns_false_after_prevent_default() {
#[test] #[test]
fn dispatch_event_non_cancelable_stays_true() { fn dispatch_event_non_cancelable_stays_true() {
assert_eq!( assert_eq!(
eval( eval(&format!(
&format!(
"{TARGET} t.addEventListener('x', function(e) {{ e.preventDefault(); }}); \ "{TARGET} t.addEventListener('x', function(e) {{ e.preventDefault(); }}); \
t.dispatchEvent(new Event('x'));" t.dispatchEvent(new Event('x'));"
) )),
),
"true" "true"
); );
} }
@@ -100,16 +93,14 @@ fn dispatch_event_non_cancelable_stays_true() {
#[test] #[test]
fn remove_event_listener_works() { fn remove_event_listener_works() {
assert_eq!( assert_eq!(
eval( eval(&format!(
&format!(
"{TARGET} var calls = 0; \ "{TARGET} var calls = 0; \
var fn = function(e) {{ calls++; }}; \ var fn = function(e) {{ calls++; }}; \
t.addEventListener('x', fn); \ t.addEventListener('x', fn); \
t.removeEventListener('x', fn); \ t.removeEventListener('x', fn); \
t.dispatchEvent(new Event('x')); \ t.dispatchEvent(new Event('x')); \
calls;" calls;"
) )),
),
"0" "0"
); );
} }
@@ -118,16 +109,14 @@ fn remove_event_listener_works() {
#[test] #[test]
fn duplicate_add_event_listener_is_noop() { fn duplicate_add_event_listener_is_noop() {
assert_eq!( assert_eq!(
eval( eval(&format!(
&format!(
"{TARGET} var calls = 0; \ "{TARGET} var calls = 0; \
var fn = function(e) {{ calls++; }}; \ var fn = function(e) {{ calls++; }}; \
t.addEventListener('x', fn); \ t.addEventListener('x', fn); \
t.addEventListener('x', fn); \ t.addEventListener('x', fn); \
t.dispatchEvent(new Event('x')); \ t.dispatchEvent(new Event('x')); \
calls;" calls;"
) )),
),
"1" "1"
); );
} }
@@ -136,16 +125,14 @@ fn duplicate_add_event_listener_is_noop() {
#[test] #[test]
fn once_listener_removed_after_call() { fn once_listener_removed_after_call() {
assert_eq!( assert_eq!(
eval( eval(&format!(
&format!(
"{TARGET} var calls = 0; \ "{TARGET} var calls = 0; \
var fn = function(e) {{ calls++; }}; \ var fn = function(e) {{ calls++; }}; \
t.addEventListener('x', fn, {{ once: true }}); \ t.addEventListener('x', fn, {{ once: true }}); \
t.dispatchEvent(new Event('x')); \ t.dispatchEvent(new Event('x')); \
t.dispatchEvent(new Event('x')); \ t.dispatchEvent(new Event('x')); \
calls;" calls;"
) )),
),
"1" "1"
); );
} }
@@ -154,15 +141,13 @@ fn once_listener_removed_after_call() {
#[test] #[test]
fn stop_immediate_propagation_truncates() { fn stop_immediate_propagation_truncates() {
assert_eq!( assert_eq!(
eval( eval(&format!(
&format!(
"{TARGET} var calls = 0; \ "{TARGET} var calls = 0; \
t.addEventListener('x', function(e) {{ calls++; e.stopImmediatePropagation(); }}); \ t.addEventListener('x', function(e) {{ calls++; e.stopImmediatePropagation(); }}); \
t.addEventListener('x', function(e) {{ calls++; }}); \ t.addEventListener('x', function(e) {{ calls++; }}); \
t.dispatchEvent(new Event('x')); \ t.dispatchEvent(new Event('x')); \
calls;" calls;"
) )),
),
"1" "1"
); );
} }
@@ -171,14 +156,12 @@ fn stop_immediate_propagation_truncates() {
#[test] #[test]
fn listener_receives_target_this_and_event() { fn listener_receives_target_this_and_event() {
assert_eq!( assert_eq!(
eval( eval(&format!(
&format!(
"{TARGET} var gotThis = null; var gotType = null; \ "{TARGET} var gotThis = null; var gotType = null; \
t.addEventListener('x', function(e) {{ gotThis = (this === t); gotType = e.type; }}); \ t.addEventListener('x', function(e) {{ gotThis = (this === t); gotType = e.type; }}); \
t.dispatchEvent(new Event('x')); \ t.dispatchEvent(new Event('x')); \
gotThis + ':' + gotType;" gotThis + ':' + gotType;"
) )),
),
"true:x" "true:x"
); );
} }
@@ -237,27 +220,20 @@ fn listener_survives_gc_while_target_live() {
// 强制完整收集:目标存活(globalThis.t),监听器回调应保活。 // 强制完整收集:目标存活(globalThis.t),监听器回调应保活。
vm.collect_session_gc(); vm.collect_session_gc();
// 收集后派发:监听器仍应被调用(无悬垂)。 // 收集后派发:监听器仍应被调用(无悬垂)。
assert_eq!( assert_eq!(vm_eval(&mut vm, "globalThis.t.dispatchEvent(new Event('x')); globalThis.calls;"), "1");
vm_eval(&mut vm, "globalThis.t.dispatchEvent(new Event('x')); globalThis.calls;"),
"1"
);
} }
/// 目标对象被回收后注册表剪枝(GC 后无悬垂指针)。 /// 目标对象被回收后注册表剪枝(GC 后无悬垂指针)。
#[test] #[test]
fn registry_pruned_after_target_collected() { fn registry_pruned_after_target_collected() {
// t 是局部变量,脚本结束后无引用 → 目标死亡。 // t 是局部变量,脚本结束后无引用 → 目标死亡。
let mut vm = vm_with_script( let mut vm =
"var mc = new MessageChannel(); var t = mc.port1; t.addEventListener('x', function() {});", vm_with_script("var mc = new MessageChannel(); var t = mc.port1; t.addEventListener('x', function() {});");
);
// 强制完整收集:注册表应按 mark 位剪枝死目标条目。 // 强制完整收集:注册表应按 mark 位剪枝死目标条目。
vm.collect_session_gc(); vm.collect_session_gc();
// 剪枝后无悬垂:新建同型目标派发不触发旧监听器(旧条目已剪),无崩溃。 // 剪枝后无悬垂:新建同型目标派发不触发旧监听器(旧条目已剪),无崩溃。
assert_eq!( assert_eq!(
vm_eval( vm_eval(&mut vm, "var mc2 = new MessageChannel(); mc2.port1.dispatchEvent(new Event('x')); 'ok';"),
&mut vm,
"var mc2 = new MessageChannel(); mc2.port1.dispatchEvent(new Event('x')); 'ok';"
),
"ok" "ok"
); );
} }