fix: 修复编译 class 方法与构造器时丢失 super 上下文的问题
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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(¶m_names, body_stmts, ctx, false, &self_binding, false)?
|
self.compile_function_body_with_bindings(
|
||||||
|
¶m_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(¶m_names, body_stmts, ctx, false, &self_binding, false)?;
|
¶m_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(¶m_names, body_stmts, ctx, false, &self_binding, false)?;
|
¶m_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(¶m_names, body_stmts, ctx, false, self_binding, false)?;
|
¶m_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());
|
||||||
|
|||||||
Reference in New Issue
Block a user