diff --git a/crates/oxide_compiler/src/compiler.rs b/crates/oxide_compiler/src/compiler.rs index 7aaebc22..8438f662 100644 --- a/crates/oxide_compiler/src/compiler.rs +++ b/crates/oxide_compiler/src/compiler.rs @@ -78,6 +78,13 @@ pub(crate) struct CompileCtx { pub(crate) reg_overflow: bool, } +#[derive(Clone, Copy)] +pub(crate) enum FunctionBodyContext { + Ordinary, + Arrow, + ClassElement, +} + impl CompileCtx { pub(crate) fn new() -> Self { Self { @@ -315,12 +322,24 @@ impl Compiler { &self, param_names: &[String], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, is_expression_body: bool, is_arrow: bool, ) -> Result { - 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>( &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 { let mut ctx = CompileCtx::new(); @@ -330,8 +349,9 @@ impl Compiler { // Propagate enclosing_this_reg so nested arrow functions capture the correct `this`. ctx.enclosing_this_reg = parent_ctx.enclosing_this_reg; - // Only arrow functions have lexical super; regular functions create a new super scope. - if is_arrow { + // Arrow functions inherit lexical super. Class method bodies also need the + // 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_instance_method = parent_ctx.in_instance_method; ctx.in_static_method = parent_ctx.in_static_method; diff --git a/crates/oxide_compiler/src/emitter.rs b/crates/oxide_compiler/src/emitter.rs index 0759300f..3f6615b0 100644 --- a/crates/oxide_compiler/src/emitter.rs +++ b/crates/oxide_compiler/src/emitter.rs @@ -6,7 +6,7 @@ use oxide_parser::{ 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; impl Compiler { @@ -77,9 +77,23 @@ impl Compiler { let mut ctor_module = if let Some(method) = constructor_method { 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 { - 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 { module.bytecode.clear(); module.constants.clear(); @@ -118,8 +132,14 @@ impl Compiler { let (param_names, body_stmts) = self.extract_function_parts(method.value.as_ref())?; let saved_method = ctx.in_instance_method; ctx.in_instance_method = true; - let mut method_module = - self.compile_function_body_with_bindings(¶m_names, body_stmts, ctx, false, &self_binding, false)?; + let mut method_module = self.compile_function_body_with_bindings( + ¶m_names, + body_stmts, + ctx, + false, + &self_binding, + FunctionBodyContext::ClassElement, + )?; ctx.in_instance_method = saved_method; method_module.function_name = Some(method_name.clone()); 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 saved_static = ctx.in_static_method; ctx.in_static_method = true; - let mut method_module = - self.compile_function_body_with_bindings(¶m_names, body_stmts, ctx, false, &self_binding, false)?; + let mut method_module = self.compile_function_body_with_bindings( + ¶m_names, + body_stmts, + ctx, + false, + &self_binding, + FunctionBodyContext::ClassElement, + )?; ctx.in_static_method = saved_static; method_module.function_name = Some(method_name.clone()); method_module.needs_home_object = true; @@ -213,8 +239,14 @@ impl Compiler { let saved_static = ctx.in_static_method; ctx.in_instance_method = !method.r#static; ctx.in_static_method = method.r#static; - let mut method_module = - self.compile_function_body_with_bindings(¶m_names, body_stmts, ctx, false, self_binding, false)?; + let mut method_module = self.compile_function_body_with_bindings( + ¶m_names, + body_stmts, + ctx, + false, + self_binding, + FunctionBodyContext::ClassElement, + )?; ctx.in_instance_method = saved_instance; ctx.in_static_method = saved_static; method_module.function_name = Some(method_name.to_string());