fix: 修复编译 class 方法与构造器时丢失 super 上下文的问题

This commit is contained in:
爱特每羊队
2026-06-13 19:00:54 +08:00
parent 6144e51c1c
commit dcc7db2575
2 changed files with 65 additions and 13 deletions
+24 -4
View File
@@ -78,6 +78,13 @@ pub(crate) struct CompileCtx {
pub(crate) reg_overflow: bool, pub(crate) reg_overflow: bool,
} }
#[derive(Clone, Copy)]
pub(crate) enum FunctionBodyContext {
Ordinary,
Arrow,
ClassElement,
}
impl CompileCtx { impl CompileCtx {
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
Self { Self {
@@ -315,12 +322,24 @@ impl Compiler {
&self, param_names: &[String], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, is_expression_body: bool, &self, param_names: &[String], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, is_expression_body: bool,
is_arrow: bool, is_arrow: bool,
) -> Result<CompiledModule, String> { ) -> Result<CompiledModule, String> {
self.compile_function_body_with_bindings(param_names, body_stmts, parent_ctx, is_expression_body, &[], is_arrow) let body_context = if is_arrow {
FunctionBodyContext::Arrow
} else {
FunctionBodyContext::Ordinary
};
self.compile_function_body_with_bindings(
param_names,
body_stmts,
parent_ctx,
is_expression_body,
&[],
body_context,
)
} }
pub(crate) fn compile_function_body_with_bindings<'a>( pub(crate) fn compile_function_body_with_bindings<'a>(
&self, param_names: &[String], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, is_expression_body: bool, &self, param_names: &[String], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, is_expression_body: bool,
extra_bindings: &[(&str, u8)], is_arrow: bool, extra_bindings: &[(&str, u8)], body_context: FunctionBodyContext,
) -> Result<CompiledModule, String> { ) -> Result<CompiledModule, String> {
let mut ctx = CompileCtx::new(); let mut ctx = CompileCtx::new();
@@ -330,8 +349,9 @@ impl Compiler {
// Propagate enclosing_this_reg so nested arrow functions capture the correct `this`. // Propagate enclosing_this_reg so nested arrow functions capture the correct `this`.
ctx.enclosing_this_reg = parent_ctx.enclosing_this_reg; ctx.enclosing_this_reg = parent_ctx.enclosing_this_reg;
// Only arrow functions have lexical super; regular functions create a new super scope. // Arrow functions inherit lexical super. Class method bodies also need the
if is_arrow { // class-provided super context for their top-level body compilation.
if matches!(body_context, FunctionBodyContext::Arrow | FunctionBodyContext::ClassElement) {
ctx.in_derived_constructor = parent_ctx.in_derived_constructor; ctx.in_derived_constructor = parent_ctx.in_derived_constructor;
ctx.in_instance_method = parent_ctx.in_instance_method; ctx.in_instance_method = parent_ctx.in_instance_method;
ctx.in_static_method = parent_ctx.in_static_method; ctx.in_static_method = parent_ctx.in_static_method;
+41 -9
View File
@@ -6,7 +6,7 @@ use oxide_parser::{
VariableDeclarationKind, VariableDeclarationKind,
}; };
use crate::compiler::{is_int_literal, is_side_effect_free, BinaryOperator, CompileCtx, Compiler}; use crate::compiler::{is_int_literal, is_side_effect_free, BinaryOperator, CompileCtx, Compiler, FunctionBodyContext};
use crate::module::Constant; use crate::module::Constant;
impl Compiler { impl Compiler {
@@ -77,9 +77,23 @@ impl Compiler {
let mut ctor_module = if let Some(method) = constructor_method { let mut ctor_module = if let Some(method) = constructor_method {
let (param_names, body_stmts) = self.extract_function_parts(method.value.as_ref())?; let (param_names, body_stmts) = self.extract_function_parts(method.value.as_ref())?;
self.compile_function_body_with_bindings(&param_names, body_stmts, ctx, false, &self_binding, false)? self.compile_function_body_with_bindings(
&param_names,
body_stmts,
ctx,
false,
&self_binding,
FunctionBodyContext::ClassElement,
)?
} else { } else {
let mut module = self.compile_function_body_with_bindings(&[], &[], ctx, false, &self_binding, false)?; let mut module = self.compile_function_body_with_bindings(
&[],
&[],
ctx,
false,
&self_binding,
FunctionBodyContext::ClassElement,
)?;
if is_derived { if is_derived {
module.bytecode.clear(); module.bytecode.clear();
module.constants.clear(); module.constants.clear();
@@ -118,8 +132,14 @@ impl Compiler {
let (param_names, body_stmts) = self.extract_function_parts(method.value.as_ref())?; let (param_names, body_stmts) = self.extract_function_parts(method.value.as_ref())?;
let saved_method = ctx.in_instance_method; let saved_method = ctx.in_instance_method;
ctx.in_instance_method = true; ctx.in_instance_method = true;
let mut method_module = let mut method_module = self.compile_function_body_with_bindings(
self.compile_function_body_with_bindings(&param_names, body_stmts, ctx, false, &self_binding, false)?; &param_names,
body_stmts,
ctx,
false,
&self_binding,
FunctionBodyContext::ClassElement,
)?;
ctx.in_instance_method = saved_method; ctx.in_instance_method = saved_method;
method_module.function_name = Some(method_name.clone()); method_module.function_name = Some(method_name.clone());
method_module.needs_home_object = true; method_module.needs_home_object = true;
@@ -153,8 +173,14 @@ impl Compiler {
let (param_names, body_stmts) = self.extract_function_parts(method.value.as_ref())?; let (param_names, body_stmts) = self.extract_function_parts(method.value.as_ref())?;
let saved_static = ctx.in_static_method; let saved_static = ctx.in_static_method;
ctx.in_static_method = true; ctx.in_static_method = true;
let mut method_module = let mut method_module = self.compile_function_body_with_bindings(
self.compile_function_body_with_bindings(&param_names, body_stmts, ctx, false, &self_binding, false)?; &param_names,
body_stmts,
ctx,
false,
&self_binding,
FunctionBodyContext::ClassElement,
)?;
ctx.in_static_method = saved_static; ctx.in_static_method = saved_static;
method_module.function_name = Some(method_name.clone()); method_module.function_name = Some(method_name.clone());
method_module.needs_home_object = true; method_module.needs_home_object = true;
@@ -213,8 +239,14 @@ impl Compiler {
let saved_static = ctx.in_static_method; let saved_static = ctx.in_static_method;
ctx.in_instance_method = !method.r#static; ctx.in_instance_method = !method.r#static;
ctx.in_static_method = method.r#static; ctx.in_static_method = method.r#static;
let mut method_module = let mut method_module = self.compile_function_body_with_bindings(
self.compile_function_body_with_bindings(&param_names, body_stmts, ctx, false, self_binding, false)?; &param_names,
body_stmts,
ctx,
false,
self_binding,
FunctionBodyContext::ClassElement,
)?;
ctx.in_instance_method = saved_instance; ctx.in_instance_method = saved_instance;
ctx.in_static_method = saved_static; ctx.in_static_method = saved_static;
method_module.function_name = Some(method_name.to_string()); method_module.function_name = Some(method_name.to_string());