Files
hakorune/archive/codex-solutions/codex-nested-returns-solution.patch
Selfhosting Dev 2e93403de0 phase15: implement Phase S root treatment for break control flow
🔧 **Phase S (Immediate Stabilization) Implementation**
- Create control flow utilities module (src/mir/utils/)
- Refactor loop_builder.rs duplicated code to utilities
- Fix PHI incoming predecessor capture per ChatGPT Pro analysis

📊 **AI Collaborative Analysis Complete**
- Task agent: Root cause identification
- Gemini: Strategic 3-phase approach
- codex: Advanced type inference solution (archived)
- ChatGPT Pro: Definitive staged treatment strategy

🗂️ **Documentation & Archive**
- Strategy document: docs/development/strategies/break-control-flow-strategy.md
- codex solutions: archive/codex-solutions/ (100+ lines changes)
- Update CLAUDE.md with 2025-09-23 progress

 **Expected Impact**
- Resolve collect_prints null return issue
- Eliminate code duplication (4 locations unified)
- Foundation for Phase M (PHI unification) and Phase L (BuildOutcome)

🎯 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-23 07:13:32 +09:00

216 lines
9.1 KiB
Diff

commit 8b0abf84292e85a3c09eba92d8bd0da79770ec8f
Author: moe-charm <moecharm.dev@gmail.com>
Date: Tue Sep 23 06:41:07 2025 +0900
mir: detect nested returns in static lowering
diff --git a/apps/selfhost/vm/boxes/mini_vm_core.nyash b/apps/selfhost/vm/boxes/mini_vm_core.nyash
index bac66c4..184cd2f 100644
--- a/apps/selfhost/vm/boxes/mini_vm_core.nyash
+++ b/apps/selfhost/vm/boxes/mini_vm_core.nyash
@@ -541,10 +541,20 @@ static box MiniVm {
local k_print = "\"kind\":\"Print\""
loop (true) {
guard = guard + 1
- if guard > 200 { if trace == 1 { print("[collect][guard_break] guard="+guard) } break }
+ if guard > 200 {
+ if trace == 1 { print("[collect][guard_break] guard="+guard) }
+ if trace == 1 { print("[collect][loop_exit] guard="+guard+" out.size="+out.size()) }
+ if trace == 1 { print("[collect][return] out.size="+out.size()) }
+ return out
+ }
local p = index_of_from(json, k_print, pos)
if trace == 1 { print("[collect][loop] pos="+pos+" p="+p+" guard="+guard) }
- if p < 0 { if trace == 1 { print("[collect][p_break] p="+p) } break }
+ if p < 0 {
+ if trace == 1 { print("[collect][p_break] p="+p) }
+ if trace == 1 { print("[collect][loop_exit] guard="+guard+" out.size="+out.size()) }
+ if trace == 1 { print("[collect][return] out.size="+out.size()) }
+ return out
+ }
// bound current Print slice to [this, next)
local obj_start = p
local next_p = index_of_from(json, k_print, p + k_print.length())
diff --git a/src/mir/builder/builder_calls.rs b/src/mir/builder/builder_calls.rs
index 6b5bf7e..3432a75 100644
--- a/src/mir/builder/builder_calls.rs
+++ b/src/mir/builder/builder_calls.rs
@@ -1,6 +1,41 @@
// Extracted call-related builders from builder.rs to keep files lean
use super::{Effect, EffectMask, FunctionSignature, MirInstruction, MirType, ValueId};
use crate::ast::{ASTNode, LiteralValue, MethodCallExpr};
+
+fn contains_value_return(nodes: &[ASTNode]) -> bool {
+ fn node_has_value_return(node: &ASTNode) -> bool {
+ match node {
+ ASTNode::Return { value: Some(_), .. } => true,
+ ASTNode::If { then_body, else_body, .. } => {
+ contains_value_return(then_body)
+ || else_body
+ .as_ref()
+ .map_or(false, |body| contains_value_return(body))
+ }
+ ASTNode::Loop { body, .. } => contains_value_return(body),
+ ASTNode::TryCatch {
+ try_body,
+ catch_clauses,
+ finally_body,
+ ..
+ } => {
+ contains_value_return(try_body)
+ || catch_clauses
+ .iter()
+ .any(|clause| contains_value_return(&clause.body))
+ || finally_body
+ .as_ref()
+ .map_or(false, |body| contains_value_return(body))
+ }
+ ASTNode::Program { statements, .. } => contains_value_return(statements),
+ ASTNode::ScopeBox { body, .. } => contains_value_return(body),
+ ASTNode::FunctionDeclaration { body, .. } => contains_value_return(body),
+ _ => false,
+ }
+ }
+
+ nodes.iter().any(node_has_value_return)
+}
use crate::mir::{slot_registry, TypeOpKind};
impl super::MirBuilder {
@@ -321,13 +356,7 @@ impl super::MirBuilder {
for _ in &params {
param_types.push(MirType::Unknown);
}
- let mut returns_value = false;
- for st in &body {
- if let ASTNode::Return { value: Some(_), .. } = st {
- returns_value = true;
- break;
- }
- }
+ let returns_value = contains_value_return(&body);
let ret_ty = if returns_value {
MirType::Unknown
} else {
@@ -365,17 +394,39 @@ impl super::MirBuilder {
span: crate::ast::Span::unknown(),
};
let _last = self.build_expression(program_ast)?;
+ if !returns_value && !self.is_current_block_terminated() {
+ let void_val = self.value_gen.next();
+ self.emit_instruction(MirInstruction::Const {
+ dst: void_val,
+ value: super::ConstValue::Void,
+ })?;
+ self.emit_instruction(MirInstruction::Return {
+ value: Some(void_val),
+ })?;
+ }
if let Some(ref mut f) = self.current_function {
- if let Some(block) = f.get_block(self.current_block.unwrap()) {
- if !block.is_terminated() {
- let void_val = self.value_gen.next();
- self.emit_instruction(MirInstruction::Const {
- dst: void_val,
- value: super::ConstValue::Void,
- })?;
- self.emit_instruction(MirInstruction::Return {
- value: Some(void_val),
- })?;
+ if returns_value
+ && matches!(f.signature.return_type, MirType::Void | MirType::Unknown)
+ {
+ let mut inferred: Option<MirType> = None;
+ 'search: for (_bid, bb) in f.blocks.iter() {
+ for inst in bb.instructions.iter() {
+ if let MirInstruction::Return { value: Some(v) } = inst {
+ if let Some(mt) = self.value_types.get(v).cloned() {
+ inferred = Some(mt);
+ break 'search;
+ }
+ }
+ }
+ if let Some(MirInstruction::Return { value: Some(v) }) = &bb.terminator {
+ if let Some(mt) = self.value_types.get(v).cloned() {
+ inferred = Some(mt);
+ break;
+ }
+ }
+ }
+ if let Some(mt) = inferred {
+ f.signature.return_type = mt;
}
}
}
@@ -401,13 +452,7 @@ impl super::MirBuilder {
for _ in &params {
param_types.push(MirType::Unknown);
}
- let mut returns_value = false;
- for st in &body {
- if let ASTNode::Return { value: Some(_), .. } = st {
- returns_value = true;
- break;
- }
- }
+ let returns_value = contains_value_return(&body);
let ret_ty = if returns_value {
MirType::Unknown
} else {
@@ -441,17 +486,45 @@ impl super::MirBuilder {
span: crate::ast::Span::unknown(),
};
let _last = self.build_expression(program_ast)?;
+ if !returns_value {
+ if let Some(ref mut f) = self.current_function {
+ if let Some(block) = f.get_block(self.current_block.unwrap()) {
+ if !block.is_terminated() {
+ let void_val = self.value_gen.next();
+ self.emit_instruction(MirInstruction::Const {
+ dst: void_val,
+ value: super::ConstValue::Void,
+ })?;
+ self.emit_instruction(MirInstruction::Return {
+ value: Some(void_val),
+ })?;
+ }
+ }
+ }
+ }
if let Some(ref mut f) = self.current_function {
- if let Some(block) = f.get_block(self.current_block.unwrap()) {
- if !block.is_terminated() {
- let void_val = self.value_gen.next();
- self.emit_instruction(MirInstruction::Const {
- dst: void_val,
- value: super::ConstValue::Void,
- })?;
- self.emit_instruction(MirInstruction::Return {
- value: Some(void_val),
- })?;
+ if returns_value
+ && matches!(f.signature.return_type, MirType::Void | MirType::Unknown)
+ {
+ let mut inferred: Option<MirType> = None;
+ 'search: for (_bid, bb) in f.blocks.iter() {
+ for inst in bb.instructions.iter() {
+ if let MirInstruction::Return { value: Some(v) } = inst {
+ if let Some(mt) = self.value_types.get(v).cloned() {
+ inferred = Some(mt);
+ break 'search;
+ }
+ }
+ }
+ if let Some(MirInstruction::Return { value: Some(v) }) = &bb.terminator {
+ if let Some(mt) = self.value_types.get(v).cloned() {
+ inferred = Some(mt);
+ break;
+ }
+ }
+ }
+ if let Some(mt) = inferred {
+ f.signature.return_type = mt;
}
}
}