fix: guard unified BoxCall recursion and document Stage-B stack overflow status

This commit is contained in:
nyash-codex
2025-11-17 17:53:40 +09:00
parent 4f3831c07b
commit e5b9b84aca
5 changed files with 78 additions and 9 deletions

View File

@ -66,6 +66,27 @@ impl MirBuilder {
object: ASTNode,
method: String,
arguments: Vec<ASTNode>,
) -> Result<ValueId, String> {
// Debug: Check recursion depth
const MAX_METHOD_DEPTH: usize = 100;
self.recursion_depth += 1;
if self.recursion_depth > MAX_METHOD_DEPTH {
eprintln!("[FATAL] build_method_call recursion depth exceeded {}", MAX_METHOD_DEPTH);
eprintln!("[FATAL] Current depth: {}", self.recursion_depth);
eprintln!("[FATAL] Method: {}", method);
return Err(format!("build_method_call recursion depth exceeded: {}", self.recursion_depth));
}
let result = self.build_method_call_impl(object, method, arguments);
self.recursion_depth -= 1;
result
}
fn build_method_call_impl(
&mut self,
object: ASTNode,
method: String,
arguments: Vec<ASTNode>,
) -> Result<ValueId, String> {
if std::env::var("NYASH_STATIC_CALL_TRACE").ok().as_deref() == Some("1") {
let kind = match &object {

View File

@ -18,12 +18,34 @@ impl MirBuilder {
target: CallTarget,
args: Vec<ValueId>,
) -> Result<(), String> {
// Check environment variable for unified call usage
if !call_unified::is_unified_call_enabled() {
// Fall back to legacy implementation
return self.emit_legacy_call(dst, target, args);
// Debug: Check recursion depth
const MAX_EMIT_DEPTH: usize = 100;
self.recursion_depth += 1;
if self.recursion_depth > MAX_EMIT_DEPTH {
eprintln!("[FATAL] emit_unified_call recursion depth exceeded {}", MAX_EMIT_DEPTH);
eprintln!("[FATAL] Current depth: {}", self.recursion_depth);
eprintln!("[FATAL] Target: {:?}", target);
return Err(format!("emit_unified_call recursion depth exceeded: {}", self.recursion_depth));
}
// Check environment variable for unified call usage
let result = if !call_unified::is_unified_call_enabled() {
// Fall back to legacy implementation
self.emit_legacy_call(dst, target, args)
} else {
self.emit_unified_call_impl(dst, target, args)
};
self.recursion_depth -= 1;
result
}
fn emit_unified_call_impl(
&mut self,
dst: Option<ValueId>,
target: CallTarget,
args: Vec<ValueId>,
) -> Result<(), String> {
// Emit resolve.try for method targets (dev-only; default OFF)
let arity_for_try = args.len();
if let CallTarget::Method { ref box_type, ref method, receiver } = target {
@ -166,7 +188,13 @@ impl MirBuilder {
// LEGACY PATH (after unified migration):
// Instance→Function rewrite is centralized in unified call path.
// Legacy path no longer functionizes; always use Box/Plugin call here.
self.emit_box_or_plugin_call(dst, receiver, method, None, args, EffectMask::IO)
// CRITICAL FIX: Prevent bouncing back to emit_unified_call
// Set flag to prevent emit_box_or_plugin_call from calling emit_unified_call
let prev_flag = self.in_unified_boxcall_fallback;
self.in_unified_boxcall_fallback = true;
let result = self.emit_box_or_plugin_call(dst, receiver, method, None, args, EffectMask::IO);
self.in_unified_boxcall_fallback = prev_flag;
result
},
CallTarget::Constructor(box_type) => {
// Use existing NewBox