commit 8b0abf84292e85a3c09eba92d8bd0da79770ec8f Author: moe-charm 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 ¶ms { 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 = 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 ¶ms { 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 = 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; } } }