diff --git a/src/mir/control_tree/normalized_shadow/builder.rs b/src/mir/control_tree/normalized_shadow/builder.rs index edb574d7..8ecfb181 100644 --- a/src/mir/control_tree/normalized_shadow/builder.rs +++ b/src/mir/control_tree/normalized_shadow/builder.rs @@ -102,6 +102,13 @@ impl StepTreeNormalizedShadowLowererBox { }) .collect(); + // Phase 124: env マッピング(変数名 → ValueId) + let env: BTreeMap = env_fields + .iter() + .cloned() + .zip(env_params.iter().cloned()) + .collect(); + // main 関数生成 let mut main_func = JoinFunction::new( main_func_id, @@ -109,18 +116,20 @@ impl StepTreeNormalizedShadowLowererBox { env_params.clone(), ); - // Phase 123: Return node lowering - // If Phase 123 patterns are not supported, return Ok(None) + // Phase 123-124: Return node lowering + // If Phase 123-124 patterns are not supported, return Ok(None) match Self::lower_return_from_tree( &step_tree.root, &mut main_func.body, &mut next_value_id, + &env, + &step_tree.contract, ) { Ok(()) => { // Success - continue } - Err(msg) if msg.starts_with("[phase123/") => { - // Phase 123 limitation - out of scope + Err(msg) if msg.starts_with("[phase123/") || msg.starts_with("[phase124/") => { + // Phase 123-124 limitation - out of scope return Ok(None); } Err(msg) => { @@ -141,18 +150,21 @@ impl StepTreeNormalizedShadowLowererBox { Ok(Some((module, meta))) } - /// Phase 123 P1-P3: Lower node from StepTree + /// Phase 123-124 P1-P3: Lower node from StepTree /// - /// ## Support (Phase 123) + /// ## Support (Phase 123-124) /// /// - Return(Integer literal): Generate Const + Ret(Some(vid)) /// - Return(void): Ret(None) + /// - Return(Variable): Phase 124 - lookup from env (dev-only) /// - Return(other): Fail-Fast with structured error /// - If(minimal compare): Generate Compare + Branch + Ret (P3) fn lower_return_from_tree( node: &crate::mir::control_tree::step_tree::StepNode, body: &mut Vec, next_value_id: &mut u32, + env: &std::collections::BTreeMap, + contract: &crate::mir::control_tree::step_tree_contract_box::StepTreeContract, ) -> Result<(), String> { use crate::ast::{ASTNode, LiteralValue}; use crate::mir::control_tree::step_tree::{StepNode, StepStmtKind}; @@ -168,11 +180,11 @@ impl StepTreeNormalizedShadowLowererBox { kind: StepStmtKind::Return { value_ast }, .. } => { - return Self::lower_return_value(value_ast, body, next_value_id); + return Self::lower_return_value(value_ast, body, next_value_id, env, contract); } StepNode::If { .. } => { // Phase 123 P3: Lower If node - return Self::lower_if_node(n, body, next_value_id); + return Self::lower_if_node(n, body, next_value_id, env, contract); } _ => { // Other nodes not yet supported @@ -186,10 +198,10 @@ impl StepTreeNormalizedShadowLowererBox { StepNode::Stmt { kind: StepStmtKind::Return { value_ast }, .. - } => Self::lower_return_value(value_ast, body, next_value_id), + } => Self::lower_return_value(value_ast, body, next_value_id, env, contract), StepNode::If { .. } => { // Phase 123 P3: Lower If node - Self::lower_if_node(node, body, next_value_id) + Self::lower_if_node(node, body, next_value_id, env, contract) } _ => { // No return in tree - default to void @@ -199,12 +211,12 @@ impl StepTreeNormalizedShadowLowererBox { } } - /// Phase 123 P3: Lower If node with minimal compare + /// Phase 123-124 P3: Lower If node with minimal compare /// /// ## Support /// /// - Minimal binary comparison: Variable vs Integer literal - /// - then/else: Return(Integer literal) only + /// - then/else: Return(Integer literal) or Return(Variable) (Phase 124) /// - Merge: Not yet implemented (will use join_k tail-call in future) /// /// ## Not Supported (Fail-Fast) @@ -217,6 +229,8 @@ impl StepTreeNormalizedShadowLowererBox { node: &crate::mir::control_tree::step_tree::StepNode, body: &mut Vec, next_value_id: &mut u32, + env: &std::collections::BTreeMap, + contract: &crate::mir::control_tree::step_tree_contract_box::StepTreeContract, ) -> Result<(), String> { use crate::ast::{ASTNode, BinaryOperator}; use crate::mir::control_tree::step_tree::StepNode; @@ -273,10 +287,10 @@ impl StepTreeNormalizedShadowLowererBox { Self::verify_branch_is_return_literal(else_br)?; } - // For Phase 123, we generate a simplified structure: + // For Phase 123-124, we generate a simplified structure: // The actual branching logic will be added in future phases // For now, just emit the then branch return - Self::lower_return_from_tree(then_branch, body, next_value_id)?; + Self::lower_return_from_tree(then_branch, body, next_value_id, env, contract)?; Ok(()) } else { @@ -390,18 +404,20 @@ impl StepTreeNormalizedShadowLowererBox { } } - /// Phase 123 P1-P2: Lower return value + /// Phase 123-124 P1-P2-P3: Lower return value /// /// ## Support /// /// - Integer literal: Generate Const + Ret(Some(vid)) /// - None: Ret(None) - /// - Variable: Fail-Fast (needs reads fact - Phase 124) + /// - Variable: Phase 124 - lookup from env (dev-only, Fail-Fast if not in env) /// - Other: Fail-Fast (out of scope) fn lower_return_value( value_ast: &Option, body: &mut Vec, next_value_id: &mut u32, + env: &std::collections::BTreeMap, + contract: &crate::mir::control_tree::step_tree_contract_box::StepTreeContract, ) -> Result<(), String> { use crate::ast::{ASTNode, LiteralValue}; use crate::mir::join_ir::{ConstValue, JoinInst, MirLikeInst}; @@ -442,11 +458,21 @@ impl StepTreeNormalizedShadowLowererBox { } }, ASTNode::Variable { name, .. } => { - // Phase 123 P2: Variable not supported (needs reads fact) - Err(format!( - "[phase123/return/var_unsupported] Phase 123 only supports return with integer literals (found variable: {}). Hint: Add reads fact (Phase 124) or return literal only", - name - )) + // Phase 124 P3: Variable return support (dev-only) + // Check if variable is in env (writes-derived) + if let Some(&vid) = env.get(name) { + // Variable found in env - return it + body.push(JoinInst::Ret { value: Some(vid) }); + Ok(()) + } else { + // Variable not in env - out of scope for Phase 124 + // Phase 124 only supports Return(Variable) when variable is in env (writes) + // Variables in reads-only or undefined are not supported + Err(format!( + "[phase124/return/var_not_in_env] Variable '{}' not in env (writes). Phase 124 only supports return of written variables. Hint: Assign variable before return", + name + )) + } } _ => { // Phase 123: Other expressions not supported @@ -755,4 +781,57 @@ mod tests { }); assert!(has_compare, "Should have Compare instruction"); } + + #[test] + fn test_return_variable_from_env() { + // Phase 124 P3: Test Return(Variable) when variable is in env (writes) + use crate::ast::{ASTNode, Span}; + use crate::mir::control_tree::step_tree::AstNodeHandle; + use std::collections::BTreeSet; + + // Create StepTree with "local x; return x" + let mut tree = make_if_only_tree(); + + // Add x to writes (simulating "local x" or assignment) + tree.contract.writes.insert("x".to_string()); + + // Create return x node + tree.root = StepNode::Stmt { + kind: StepStmtKind::Return { + value_ast: Some(AstNodeHandle(Box::new(ASTNode::Variable { + name: "x".to_string(), + span: Span::unknown(), + }))), + }, + span: Span::unknown(), + }; + + // Lower to JoinModule - should succeed + let result = StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree); + assert!(result.is_ok()); + + let option = result.unwrap(); + assert!(option.is_some(), "Should generate JoinModule for return x (x in writes)"); + + let (module, _meta) = option.unwrap(); + + // Verify structure + assert_eq!(module.functions.len(), 1); + let func = &module.functions.values().next().unwrap(); + + // Should have exactly 1 parameter (x from writes/env) + assert_eq!(func.params.len(), 1, "Should have 1 parameter (x)"); + + // Should have exactly 1 instruction: Ret(Some(x)) + assert_eq!(func.body.len(), 1, "Should have 1 instruction (Ret)"); + + // Verify Ret instruction returns the parameter (ValueId(1)) + use crate::mir::join_ir::JoinInst; + use crate::mir::ValueId; + if let JoinInst::Ret { value } = &func.body[0] { + assert_eq!(value, &Some(ValueId(1)), "Should return ValueId(1) (parameter x)"); + } else { + panic!("Expected Ret instruction"); + } + } }