From 1ad4c63c94726bab667cf66c417bf561758700b9 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Tue, 13 Oct 2026 18:43:45 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20TLA=20=E6=B8=B8=E8=B5=B0=E5=99=A8?= =?UTF-8?q?=E8=A1=A5=20if=20=E6=B5=8B=E8=AF=95=E8=87=82=E4=B8=8E=E7=B1=BB?= =?UTF-8?q?=E5=A3=B0=E6=98=8E=20extends=20=E8=87=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 42 ++++++++++---------- Cargo.toml | 2 +- crates/oxide_emit/src/module.rs | 28 +++++++++---- crates/oxide_emit/tests/module_link_tests.rs | 32 +++++++++++++++ 4 files changed, 74 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 61a43ac8..1b80525f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,7 +1160,7 @@ dependencies = [ [[package]] name = "oxide_builtins" -version = "0.18.8" +version = "0.18.9" dependencies = [ "chrono", "fast-float", @@ -1185,7 +1185,7 @@ dependencies = [ [[package]] name = "oxide_bytecode" -version = "0.18.8" +version = "0.18.9" dependencies = [ "num-bigint", "oxide_log", @@ -1193,7 +1193,7 @@ dependencies = [ [[package]] name = "oxide_cfg" -version = "0.18.8" +version = "0.18.9" dependencies = [ "oxide_bytecode", "oxide_emit", @@ -1204,7 +1204,7 @@ dependencies = [ [[package]] name = "oxide_cli" -version = "0.18.8" +version = "0.18.9" dependencies = [ "ansi_term", "bumpalo", @@ -1228,7 +1228,7 @@ dependencies = [ [[package]] name = "oxide_code_cache" -version = "0.18.8" +version = "0.18.9" dependencies = [ "lru", "oxide_bytecode", @@ -1237,7 +1237,7 @@ dependencies = [ [[package]] name = "oxide_compiler" -version = "0.18.8" +version = "0.18.9" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1258,7 +1258,7 @@ dependencies = [ [[package]] name = "oxide_dce" -version = "0.18.8" +version = "0.18.9" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1272,7 +1272,7 @@ dependencies = [ [[package]] name = "oxide_emit" -version = "0.18.8" +version = "0.18.9" dependencies = [ "num-bigint", "oxc_allocator", @@ -1288,7 +1288,7 @@ dependencies = [ [[package]] name = "oxide_engine" -version = "0.18.8" +version = "0.18.9" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1300,7 +1300,7 @@ dependencies = [ [[package]] name = "oxide_fold" -version = "0.18.8" +version = "0.18.9" dependencies = [ "num-bigint", "oxide_bytecode", @@ -1312,7 +1312,7 @@ dependencies = [ [[package]] name = "oxide_ir" -version = "0.18.8" +version = "0.18.9" dependencies = [ "oxide_bytecode", "oxide_log", @@ -1321,7 +1321,7 @@ dependencies = [ [[package]] name = "oxide_kernel" -version = "0.18.8" +version = "0.18.9" dependencies = [ "bumpalo", "dashmap", @@ -1335,7 +1335,7 @@ dependencies = [ [[package]] name = "oxide_liveness" -version = "0.18.8" +version = "0.18.9" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1347,7 +1347,7 @@ dependencies = [ [[package]] name = "oxide_log" -version = "0.18.8" +version = "0.18.9" dependencies = [ "tracing", "tracing-appender", @@ -1356,11 +1356,11 @@ dependencies = [ [[package]] name = "oxide_net" -version = "0.18.8" +version = "0.18.9" [[package]] name = "oxide_parser" -version = "0.18.8" +version = "0.18.9" dependencies = [ "oxc_allocator", "oxc_ast", @@ -1375,7 +1375,7 @@ dependencies = [ [[package]] name = "oxide_regalloc" -version = "0.18.8" +version = "0.18.9" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1391,7 +1391,7 @@ dependencies = [ [[package]] name = "oxide_runtime_api" -version = "0.18.8" +version = "0.18.9" dependencies = [ "num-bigint", "num-traits", @@ -1404,7 +1404,7 @@ dependencies = [ [[package]] name = "oxide_test262" -version = "0.18.8" +version = "0.18.9" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1424,7 +1424,7 @@ dependencies = [ [[package]] name = "oxide_types" -version = "0.18.8" +version = "0.18.9" dependencies = [ "bumpalo", "dashmap", @@ -1437,7 +1437,7 @@ dependencies = [ [[package]] name = "oxide_vm" -version = "0.18.8" +version = "0.18.9" dependencies = [ "bumpalo", "chrono", diff --git a/Cargo.toml b/Cargo.toml index fdf6f02b..54a6f809 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ members = [ ] [workspace.package] -version = "0.18.8" +version = "0.18.9" edition = "2021" license = "MIT" rust-version = "1.80" diff --git a/crates/oxide_emit/src/module.rs b/crates/oxide_emit/src/module.rs index 393e8d5c..7030bc7b 100644 --- a/crates/oxide_emit/src/module.rs +++ b/crates/oxide_emit/src/module.rs @@ -356,7 +356,8 @@ fn stmt_has_top_level_await(stmt: &Statement) -> bool { match stmt { Statement::BlockStatement(block) => block.body.iter().any(|s| stmt_has_top_level_await(s)), Statement::IfStatement(if_stmt) => { - stmt_has_top_level_await(&if_stmt.consequent) + expr_has_top_level_await(&if_stmt.test) + || stmt_has_top_level_await(&if_stmt.consequent) || if_stmt.alternate.as_ref().is_some_and(|alt| stmt_has_top_level_await(alt)) } Statement::ForStatement(for_stmt) => { @@ -419,21 +420,32 @@ fn stmt_has_top_level_await(stmt: &Statement) -> bool { .declarations .iter() .any(|d| d.init.as_ref().is_some_and(|i| expr_has_top_level_await(i))), - // 函数/类声明:体不进入(函数体是独立异步语义边界)。 - Statement::FunctionDeclaration(_) | Statement::ClassDeclaration(_) => false, + // 函数声明:体不进入(函数体是独立异步语义边界)。 + Statement::FunctionDeclaration(_) => false, + // 类声明:类体不进入(独立异步语义边界),extends 表达式是顶层 await + // (如 `export class A extends (await x) {}`)。 + Statement::ClassDeclaration(cls) => cls.super_class.as_ref().is_some_and(expr_has_top_level_await), // `export const/let/var x = await ...` 是顶层 await; - // 函数/类声明形态不进入(体是独立异步语义边界,与裸声明臂同口径)。 + // 函数/类声明形态不进入(体是独立异步语义边界,与裸声明臂同口径), + // 但类声明的 extends 表达式照常游走。 Statement::ExportNamedDeclaration(exp) => exp.declaration.as_ref().is_some_and(|decl| match decl { Declaration::VariableDeclaration(vd) => vd .declarations .iter() .any(|d| d.init.as_ref().is_some_and(|i| expr_has_top_level_await(i))), + Declaration::ClassDeclaration(cls) => { + cls.super_class.as_ref().is_some_and(expr_has_top_level_await) + } _ => false, }), - // `export default await ...` 是顶层 await;函数/类声明形态不进入(同口径)。 - Statement::ExportDefaultDeclaration(exp) => { - exp.declaration.as_expression().is_some_and(expr_has_top_level_await) - } + // `export default await ...` 是顶层 await;函数/类声明形态体不进入(同口径), + // 但类声明的 extends 表达式照常游走。 + Statement::ExportDefaultDeclaration(exp) => match &exp.declaration { + ExportDefaultDeclarationKind::ClassDeclaration(cls) => { + cls.super_class.as_ref().is_some_and(expr_has_top_level_await) + } + _ => exp.declaration.as_expression().is_some_and(expr_has_top_level_await), + }, // import、`export *`、`export { x }`(无声明)与无子表达式的语句 // (break/continue/debugger/empty)不含顶层 await。 _ => false, diff --git a/crates/oxide_emit/tests/module_link_tests.rs b/crates/oxide_emit/tests/module_link_tests.rs index 9fde5446..aedad2b0 100644 --- a/crates/oxide_emit/tests/module_link_tests.rs +++ b/crates/oxide_emit/tests/module_link_tests.rs @@ -584,3 +584,35 @@ fn export_named_async_fn_expr_not_tla() { assert!(!ir.is_async, "异步函数表达式体不得使模块标记异步"); assert_eq!(ir.insts.iter().filter(|i| i.op == OpCode::AWAIT).count(), 0, "主身不得含 AWAIT"); } + +/// 面 28:`if (await ...)`(IfStatement 的 test 表达式)是顶层 await, +/// 模块标记异步、体 await 编译为 AWAIT。 +#[test] +fn if_test_await_makes_module_async() { + let (ir, _) = emit_module("if (await Promise.resolve(1)) { globalThis.v = 1; }", "./entry.js", &[]) + .expect("if (await ...) 模块应编译成功"); + assert!(ir.is_async, "if (await ...) 应标记模块异步求值"); + assert_eq!( + ir.insts.iter().filter(|i| i.op == OpCode::AWAIT).count(), + 1, + "顶层 await 应编译为一条 AWAIT" + ); +} + +/// 面 29:`export class A extends (await ...)`(ClassDeclaration 的 extends +/// 表达式)是顶层 await,模块标记异步、体 await 编译为 AWAIT;类体不进入游走。 +#[test] +fn extends_await_makes_module_async() { + let (ir, _) = emit_module( + "export class A extends (await Promise.resolve(1)) {}", + "./entry.js", + &[], + ) + .expect("extends (await ...) 模块应编译成功"); + assert!(ir.is_async, "extends (await ...) 应标记模块异步求值"); + assert_eq!( + ir.insts.iter().filter(|i| i.op == OpCode::AWAIT).count(), + 1, + "顶层 await 应编译为一条 AWAIT" + ); +}