fix: 默认导出匿名函数与类设置隐式名

This commit is contained in:
2026-09-17 22:16:17 +00:00
parent e4b17d2ecf
commit c1dcc7a8f3
4 changed files with 121 additions and 14 deletions
+6 -3
View File
@@ -14,7 +14,7 @@ impl Emitter {
// 类表达式:类名在类体内为 const 绑定;不向调用方复用寄存器时,
// 由 emit_class_with_binding 新建块作用域声明(TDZ),类构建完成后
// STORE_VAR 初始化再弹出作用域,类名不泄漏到外层。
self.emit_class_with_binding(class, ctx, None)
self.emit_class_with_binding(class, ctx, None, None)
}
/// 类名绑定可复用调用方寄存器的类整体 emit。
@@ -23,8 +23,11 @@ impl Emitter {
/// 类表达式无外部槽时,在独立块作用域声明 const 绑定(未初始化)。
/// 无论哪种形态,绑定都在 `extends` 求值前建立:extends 引用类名按规范
/// 抛 TDZ ReferenceError;类构建完成后 `init_var` + `STORE_VAR` 初始化。
///
/// `implicit_name` 供 `export default` 的匿名类做 SetFunctionName:类名缺省时
/// 以它为构造器 `name`;具名类由 `ctor_name` 优先,不受影响。
pub(crate) fn emit_class_with_binding(
&self, class: &Class, ctx: &mut CompileCtx, binding_reg: Option<u32>,
&self, class: &Class, ctx: &mut CompileCtx, binding_reg: Option<u32>, implicit_name: Option<&str>,
) -> Result<u32, String> {
// 类定义体是严格模式代码:字段初始化/静态块/extends 表达式内嵌套函数以
// 本 ctx 为父 ctx,类编译期间强制 strict(函数末尾恢复外层标志)。
@@ -314,7 +317,7 @@ impl Emitter {
ctx.in_derived_constructor = saved_derived;
ctor_module.is_class_constructor = true;
ctor_module.is_derived_constructor = is_derived;
ctor_module.function_name = ctor_name.clone();
ctor_module.function_name = ctor_name.clone().or_else(|| implicit_name.map(str::to_string));
ctx.nested.push(ctor_module);
// 键数组构建会在 keys 表达式中压入嵌套模块(箭头/函数/类键),
// 必须在压入后用固定下标引用构造器模块,避免嵌套长度偏移。
+63 -10
View File
@@ -18,8 +18,8 @@ use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_ir::{IRFunction, ParamLayout};
use oxide_parser::{
BindingPattern, Declaration, ExportDefaultDeclarationKind, ImportAttributeKey, ImportDeclarationSpecifier,
ModuleExportName, Statement, VariableDeclarationKind, WithClause,
BindingPattern, Declaration, ExportDefaultDeclarationKind, Expression, ImportAttributeKey,
ImportDeclarationSpecifier, ModuleExportName, Statement, VariableDeclarationKind, WithClause,
};
/// 数据模块种类(非 JS 源码模块)。
@@ -50,6 +50,35 @@ pub trait ModuleSourceLoader {
) -> Result<ResolvedModule, String>;
}
/// `export default` 的默认导出名,也是匿名默认导出函数/类的隐式 `name`。
const DEFAULT_EXPORT_NAME: &str = "default";
/// 剥离可能的多层括号表达式,供隐式名分派判定内层函数/类形态。
fn strip_parens<'a, 'b>(expr: &'b Expression<'a>) -> &'b Expression<'a> {
let mut cur = expr;
while let Expression::ParenthesizedExpression(p) = cur {
cur = &p.expression;
}
cur
}
/// 把隐式名写到刚发射的匿名函数子模块。
///
/// # 副作用
/// - 修改 `ctx.nested` 末项的 `function_name`;已有名(具名函数)不覆盖。
///
/// # 注意事项
/// - 仅用于函数/箭头/生成器:它们在发射期只 push 一个子模块,末项即目标。
/// 类在构造器之后还会 push 方法子模块,末项不是构造器,类名必须经
/// `emit_class_with_binding` 的 `implicit_name` 参数落名。
fn set_implicit_name_of_last_nested(ctx: &mut CompileCtx, name: &str) {
if let Some(m) = ctx.nested.last_mut() {
if m.function_name.is_none() {
m.function_name = Some(name.to_string());
}
}
}
/// 把 `ModuleExportName`(标识符名 / 标识符引用 / 字符串字面量)统一转为字符串导出名。
fn module_export_name_str(m: &ModuleExportName) -> String {
match m {
@@ -109,7 +138,7 @@ fn module_own_export_names(body: &[Statement]) -> HashSet<String> {
}
}
Statement::ExportDefaultDeclaration(_) => {
names.insert("default".to_string());
names.insert(DEFAULT_EXPORT_NAME.to_string());
}
Statement::ExportAllDeclaration(exp) => {
if let Some(exported) = &exp.exported {
@@ -302,7 +331,7 @@ impl Emitter {
}
ImportDeclarationSpecifier::ImportDefaultSpecifier(s) => {
if is_self {
if !own_export_names.contains("default") {
if !own_export_names.contains(DEFAULT_EXPORT_NAME) {
return Err("requested module export is not exported: default".into());
}
let undef_idx = ctx.add_constant(Constant::Undefined);
@@ -317,10 +346,10 @@ impl Emitter {
ctx,
)?;
if let Ok(reg) = ctx.lookup(s.local.name.as_str()) {
ctx.module_self_aliases.insert("default".to_string(), reg);
ctx.module_self_aliases.insert(DEFAULT_EXPORT_NAME.to_string(), reg);
}
} else {
let name_reg = self.load_string_const("default", ctx);
let name_reg = self.load_string_const(DEFAULT_EXPORT_NAME, ctx);
let val_reg =
self.emit_module_call(ctx, "__moduleLinkGet", &[dep_ns_reg, name_reg])?;
self.emit_bind_target(
@@ -573,11 +602,18 @@ impl Emitter {
false,
ctx,
)?;
} else {
set_implicit_name_of_last_nested(ctx, DEFAULT_EXPORT_NAME);
}
reg
}
ExportDefaultDeclarationKind::ClassDeclaration(cl) => {
let reg = self.emit_class_expression(cl, ctx)?;
let reg = self.emit_class_with_binding(
cl,
ctx,
None,
cl.id.is_none().then_some(DEFAULT_EXPORT_NAME),
)?;
if let Some(id) = &cl.id {
self.emit_bind_target(
id.name.as_str(),
@@ -594,11 +630,28 @@ impl Emitter {
let expr = other
.as_expression()
.ok_or_else(|| "unsupported export default declaration".to_string())?;
self.emit_expression(expr, ctx)?
if crate::is_anonymous_function_definition(expr) {
match strip_parens(expr) {
// 匿名类:构造器落名后还会 push 方法子模块,必须经
// implicit_name 写构造器;具名类由 ctor_name 优先。
Expression::ClassExpression(cl) => {
self.emit_class_with_binding(cl, ctx, None, Some(DEFAULT_EXPORT_NAME))?
}
// 函数/生成器/箭头:发射期只 push 一个子模块,末项即目标;
// 具名函数表达式已有名,守卫不覆盖。
_ => {
let reg = self.emit_expression(expr, ctx)?;
set_implicit_name_of_last_nested(ctx, DEFAULT_EXPORT_NAME);
reg
}
}
} else {
self.emit_expression(expr, ctx)?
}
}
};
self.emit_module_set(ctx, ns_reg, "default", val_reg)?;
self.emit_self_alias_write(ctx, "default", val_reg);
self.emit_module_set(ctx, ns_reg, DEFAULT_EXPORT_NAME, val_reg)?;
self.emit_self_alias_write(ctx, DEFAULT_EXPORT_NAME, val_reg);
}
Statement::ExportAllDeclaration(exp) => {
let source = exp.source.value.as_str();
@@ -32,7 +32,7 @@ impl Emitter {
};
// 类名绑定在 emit_class_with_binding 内于 extends 求值后初始化:
// 先声明未初始化绑定(TDZ),extends 引用类名按规范抛 ReferenceError。
self.emit_class_with_binding(class, ctx, Some(var_reg))?;
self.emit_class_with_binding(class, ctx, Some(var_reg), None)?;
Ok(None)
}
}