Files
hakorune/src/mir/control_tree/normalized_shadow/builder.rs

1010 lines
39 KiB
Rust
Raw Normal View History

//! Phase 121: StepTree → JoinModule shadow lowering (if-only)
//!
//! ## Responsibility
//!
//! - Convert StepTree to JoinModule (Normalized dialect)
//! - Only for if-only patterns (no loops)
//! - Returns None for out-of-scope patterns
//! - Returns Err for patterns that should be supported but conversion failed
//!
//! ## Design
//!
//! - Input: `&StepTree` with pre-computed contract
//! - No AST re-analysis (contract-only decisions)
//! - Single responsibility: structure → JoinIR conversion
use crate::mir::control_tree::step_tree::StepTree;
use crate::mir::join_ir::lowering::carrier_info::{ExitMeta, JoinFragmentMeta};
use crate::mir::join_ir::JoinModule;
use crate::mir::ValueId; // Phase 126
use std::collections::BTreeMap; // Phase 126
use super::contracts::{check_if_only, CapabilityCheckResult};
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
/// Phase 125: Normalized env layout (writes + inputs)
///
/// ## Design
///
/// - writes: Variables written in the function (generate ValueId)
/// - inputs: Variables read from outer scope (reference ValueId, don't generate)
///
/// ## SSOT
///
/// - writes: From StepTreeContract.writes
/// - inputs: From (StepTreeContract.reads ∩ available_inputs)
#[derive(Debug, Clone)]
pub struct EnvLayout {
/// Variables written (generate ValueId for these)
pub writes: Vec<String>,
/// Variables read from outer scope (reference ValueId from available_inputs)
pub inputs: Vec<String>,
}
impl EnvLayout {
/// Create env layout from contract and available_inputs (Phase 125)
///
/// ## Contract
///
/// - writes: All variables from contract.writes (deterministic order)
/// - inputs: Variables in contract.reads that are available from outer scope
///
/// ## SSOT
///
/// - available_inputs source: function params + CapturedEnv (pinned/captured)
/// - No AST inference (don't capture from AST)
pub fn from_contract(
contract: &crate::mir::control_tree::step_tree_contract_box::StepTreeContract,
available_inputs: &std::collections::BTreeMap<String, crate::mir::ValueId>,
) -> Self {
use std::collections::BTreeSet;
// Phase 125 P2: writes from contract
let writes: Vec<String> = contract.writes.iter().cloned().collect();
// Phase 125 P2: inputs = reads ∩ available_inputs (deterministic order)
let inputs: Vec<String> = contract
.reads
.iter()
.filter(|name| available_inputs.contains_key(*name))
.cloned()
.collect();
EnvLayout { writes, inputs }
}
}
/// Box-First: StepTree → Normalized shadow lowering
pub struct StepTreeNormalizedShadowLowererBox;
impl StepTreeNormalizedShadowLowererBox {
/// Try to lower an if-only StepTree to normalized form
///
/// ## Returns
///
/// - `Ok(None)`: Out of scope (e.g., contains loops)
/// - `Ok(Some(...))`: Shadow generation succeeded
/// - `Err(...)`: Should be supported but conversion failed (internal error)
///
/// ## Contract
///
/// - Only processes if-only patterns (no loops/breaks/continues)
/// - Uses contract information only (no AST re-analysis)
/// - Dev-only: caller must check `joinir_dev_enabled()` before calling
///
/// ## Phase 122-126 Implementation
///
/// - Generates Normalized JoinIR (env + continuation)
/// - env layout: writes + inputs (Phase 125-126)
/// - merge = join_k(env) tail-call (no PHI)
/// - Minimal node support: If/Return/Assign(Const/Variable/BinOp(Add))
///
/// ## Phase 126: available_inputs
///
/// - available_inputs: function params + CapturedEnv (SSOT)
/// - inputs = reads ∩ available_inputs (deterministic order)
pub fn try_lower_if_only(
step_tree: &StepTree,
available_inputs: &BTreeMap<String, ValueId>,
) -> Result<Option<(JoinModule, JoinFragmentMeta)>, String> {
// Phase 121 P1: Capability check (if-only scope)
let capability = check_if_only(step_tree);
match capability {
CapabilityCheckResult::Supported => {
// Phase 122-126: Generate Normalized JoinModule
Self::lower_if_only_to_normalized(step_tree, available_inputs)
}
CapabilityCheckResult::Unsupported(_reason) => {
// Out of scope for Phase 121/122
Ok(None)
}
}
}
/// Lower if-only StepTree to Normalized JoinModule (Phase 122-126)
///
/// ## Design
///
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
/// - env レイアウト: writes + inputs決定的順序
/// - merge 形式: `join_k(env)` への tail-callPHI 禁止)
/// - 対応ノード: If/Return/Assign(最小セット)
///
/// ## Phase 123-126 Node Support
///
/// - Return(Integer literal): `Const + Ret(Some(vid))`
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
/// - Return(Variable from writes): Phase 124
/// - Return(Variable from inputs): Phase 125-126 (reads-only)
/// - Return(void): `Ret(None)`
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
/// - If(minimal compare): Compare with Integer literal only
///
/// ## Phase 126: available_inputs
///
/// - available_inputs: function params + CapturedEnv (SSOT)
/// - inputs = reads ∩ available_inputs (deterministic order)
///
/// ## Returns
///
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
/// - `Ok(Some((module, meta)))`: Normalized JoinModule生成成功
/// - `Ok(None)`: Out of scope for Phase 123-126 (unsupported patterns)
/// - `Err(msg)`: 生成できるはずなのに失敗(内部エラー)
fn lower_if_only_to_normalized(
step_tree: &StepTree,
available_inputs: &BTreeMap<String, ValueId>,
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
) -> Result<Option<(JoinModule, JoinFragmentMeta)>, String> {
use crate::mir::join_ir::{JoinFunction, JoinFuncId, JoinInst};
use crate::mir::ValueId;
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
// Phase 126: EnvLayout 生成available_inputs を使用)
let env_layout = EnvLayout::from_contract(&step_tree.contract, available_inputs);
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
let main_func_id = JoinFuncId::new(0);
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
// Phase 125 P2: writes 用の ValueId 生成
let mut next_value_id = 1;
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
let writes_params: Vec<ValueId> = env_layout
.writes
.iter()
.map(|_| {
let vid = ValueId(next_value_id);
next_value_id += 1;
vid
})
.collect();
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
// Phase 125 P2: inputs 用の ValueId 生成今は空だが、P3 で available_inputs から参照)
let inputs_params: Vec<ValueId> = env_layout
.inputs
.iter()
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
.map(|name| {
// Phase 125 P3: available_inputs から取得
// 今は空なので到達しないはずだが、念のため placeholder
available_inputs
.get(name)
.copied()
.unwrap_or_else(|| {
// Should not reach here (inputs は available_inputs にある前提)
ValueId(0) // placeholder
})
})
.collect();
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
// Phase 125 P2: env マッピングwrites + inputs
let mut env: BTreeMap<String, ValueId> = BTreeMap::new();
for (name, vid) in env_layout.writes.iter().zip(writes_params.iter()) {
env.insert(name.clone(), *vid);
}
for (name, vid) in env_layout.inputs.iter().zip(inputs_params.iter()) {
env.insert(name.clone(), *vid);
}
// Phase 125 P2: 関数パラメータは writes のみinputs は外側から来る前提)
// TODO P3: inputs も params に含める必要があるか検討
let env_params = writes_params;
// main 関数生成
let mut main_func = JoinFunction::new(
main_func_id,
"main".to_string(),
env_params.clone(),
);
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
// Phase 123-125: Return node lowering
// If Phase 123-125 patterns are not supported, return Ok(None)
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
match Self::lower_return_from_tree(
&step_tree.root,
&mut main_func.body,
&mut next_value_id,
&env,
&step_tree.contract,
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
) {
Ok(()) => {
// Success - continue
}
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
Err(msg)
if msg.starts_with("[phase123/")
|| msg.starts_with("[phase124/")
|| msg.starts_with("[phase125/") =>
{
// Phase 123-125 limitation - out of scope
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
return Ok(None);
}
Err(msg) => {
// Real error - propagate
return Err(msg);
}
}
// JoinModule 構築
let mut module = JoinModule::new();
module.add_function(main_func);
module.entry = Some(main_func_id);
module.mark_normalized();
// JoinFragmentMeta 生成(最小)
let meta = JoinFragmentMeta::empty();
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
Ok(Some((module, meta)))
}
/// Phase 123-124 P1-P3: Lower node from StepTree
///
/// ## 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
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
/// - If(minimal compare): Generate Compare + Branch + Ret (P3)
fn lower_return_from_tree(
node: &crate::mir::control_tree::step_tree::StepNode,
body: &mut Vec<crate::mir::join_ir::JoinInst>,
next_value_id: &mut u32,
env: &std::collections::BTreeMap<String, crate::mir::ValueId>,
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};
use crate::mir::join_ir::JoinInst;
use crate::mir::ValueId;
match node {
StepNode::Block(nodes) => {
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
// Process nodes in order
for n in nodes {
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
match n {
StepNode::Stmt {
kind: StepStmtKind::Return { value_ast },
..
} => {
return Self::lower_return_value(value_ast, body, next_value_id, env, contract);
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
}
StepNode::If { .. } => {
// Phase 123 P3: Lower If node
return Self::lower_if_node(n, body, next_value_id, env, contract);
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
}
_ => {
// Other nodes not yet supported
}
}
}
// No return found - default to void
body.push(JoinInst::Ret { value: None });
Ok(())
}
StepNode::Stmt {
kind: StepStmtKind::Return { value_ast },
..
} => Self::lower_return_value(value_ast, body, next_value_id, env, contract),
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
StepNode::If { .. } => {
// Phase 123 P3: Lower If node
Self::lower_if_node(node, body, next_value_id, env, contract)
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
}
_ => {
// No return in tree - default to void
body.push(JoinInst::Ret { value: None });
Ok(())
}
}
}
/// Phase 123-124 P3: Lower If node with minimal compare
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
///
/// ## Support
///
/// - Minimal binary comparison: Variable vs Integer literal
/// - then/else: Return(Integer literal) or Return(Variable) (Phase 124)
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
/// - Merge: Not yet implemented (will use join_k tail-call in future)
///
/// ## Not Supported (Fail-Fast)
///
/// - Compound expressions (&&, ||)
/// - Method calls
/// - Complex expressions
/// - Non-return statements in branches
fn lower_if_node(
node: &crate::mir::control_tree::step_tree::StepNode,
body: &mut Vec<crate::mir::join_ir::JoinInst>,
next_value_id: &mut u32,
env: &std::collections::BTreeMap<String, crate::mir::ValueId>,
contract: &crate::mir::control_tree::step_tree_contract_box::StepTreeContract,
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
) -> Result<(), String> {
use crate::ast::{ASTNode, BinaryOperator};
use crate::mir::control_tree::step_tree::StepNode;
use crate::mir::join_ir::{CompareOp, ConstValue, JoinInst, MirLikeInst};
use crate::mir::ValueId;
if let StepNode::If {
cond_ast,
then_branch,
else_branch,
..
} = node
{
let ast = &cond_ast.0;
// Phase 123 P3: Parse minimal binary comparison only
let (_lhs_var, op, rhs_literal) = Self::parse_minimal_compare(ast)?;
// Generate Compare instruction
// 1. Load/create lhs variable (for now, assume it's a parameter)
// For Phase 123 minimal: we'll just create a load instruction placeholder
// This is a simplification - real implementation would need variable resolution
let lhs_vid = ValueId(*next_value_id);
*next_value_id += 1;
// For now, emit a const for the variable (placeholder)
// Real implementation in Phase 124 will use reads facts
body.push(JoinInst::Compute(MirLikeInst::Const {
dst: lhs_vid,
value: ConstValue::Integer(0), // Placeholder
}));
// 2. Create constant for rhs literal
let rhs_vid = ValueId(*next_value_id);
*next_value_id += 1;
body.push(JoinInst::Compute(MirLikeInst::Const {
dst: rhs_vid,
value: ConstValue::Integer(rhs_literal),
}));
// 3. Generate Compare instruction
let cond_vid = ValueId(*next_value_id);
*next_value_id += 1;
body.push(JoinInst::Compute(MirLikeInst::Compare {
dst: cond_vid,
op,
lhs: lhs_vid,
rhs: rhs_vid,
}));
// Phase 123 P3: Verify then/else branches contain only Return(Integer literal)
Self::verify_branch_is_return_literal(then_branch)?;
if let Some(else_br) = else_branch {
Self::verify_branch_is_return_literal(else_br)?;
}
// For Phase 123-124, we generate a simplified structure:
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
// 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, env, contract)?;
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
Ok(())
} else {
Err("[phase123/if/internal] Expected If node".to_string())
}
}
/// Parse minimal binary comparison: Variable op Integer
///
/// Returns: (variable_name, compare_op, integer_value)
fn parse_minimal_compare(
ast: &crate::ast::ASTNode,
) -> Result<(String, crate::mir::join_ir::CompareOp, i64), String> {
use crate::ast::{ASTNode, BinaryOperator, LiteralValue};
use crate::mir::join_ir::CompareOp;
match ast {
ASTNode::BinaryOp {
operator,
left,
right,
..
} => {
// Phase 123: Only support Variable on left, Integer literal on right
let var_name = match &**left {
ASTNode::Variable { name, .. } => name.clone(),
_ => {
return Err(format!(
"[phase123/if/compare_lhs_unsupported] Phase 123 only supports Variable on left side of comparison. Hint: Use simple variable comparison or wait for Phase 124"
));
}
};
let int_value = match &**right {
ASTNode::Literal {
value: LiteralValue::Integer(i),
..
} => *i,
_ => {
return Err(format!(
"[phase123/if/compare_rhs_unsupported] Phase 123 only supports Integer literal on right side of comparison. Hint: Use integer literal or wait for Phase 124"
));
}
};
let compare_op = match operator {
BinaryOperator::Equal => CompareOp::Eq,
BinaryOperator::NotEqual => CompareOp::Ne,
BinaryOperator::Less => CompareOp::Lt,
BinaryOperator::LessEqual => CompareOp::Le,
BinaryOperator::Greater => CompareOp::Gt,
BinaryOperator::GreaterEqual => CompareOp::Ge,
_ => {
return Err(format!(
"[phase123/if/compare_op_unsupported] Phase 123 only supports comparison operators (==, !=, <, <=, >, >=). Hint: Use comparison operator or wait for Phase 124"
));
}
};
Ok((var_name, compare_op, int_value))
}
_ => Err(format!(
"[phase123/if/cond_unsupported] Phase 123 only supports binary comparisons. Hint: Use simple comparison (var == literal) or wait for Phase 124"
)),
}
}
/// Verify branch contains only Return(Integer literal)
fn verify_branch_is_return_literal(
branch: &crate::mir::control_tree::step_tree::StepNode,
) -> Result<(), String> {
use crate::ast::{ASTNode, LiteralValue};
use crate::mir::control_tree::step_tree::{StepNode, StepStmtKind};
match branch {
StepNode::Stmt {
kind: StepStmtKind::Return { value_ast },
..
} => {
if let Some(ast_handle) = value_ast {
let ast = &ast_handle.0;
if let ASTNode::Literal {
value: LiteralValue::Integer(_),
..
} = &**ast
{
Ok(())
} else {
Err(format!(
"[phase123/if/branch_return_not_int_literal] Phase 123 only supports Return(Integer literal) in then/else branches. Hint: Return integer literal only or wait for Phase 124"
))
}
} else {
Err(format!(
"[phase123/if/branch_return_void] Phase 123 requires Return(Integer literal) in branches, not void return. Hint: Return integer literal or wait for Phase 124"
))
}
}
StepNode::Block(nodes) => {
// Check first node only
if nodes.is_empty() {
return Err(format!(
"[phase123/if/branch_empty] Phase 123 requires Return(Integer literal) in branches. Hint: Add return statement"
));
}
Self::verify_branch_is_return_literal(&nodes[0])
}
_ => Err(format!(
"[phase123/if/branch_not_return] Phase 123 only supports Return(Integer literal) in then/else branches. Hint: Use return statement with integer literal"
)),
}
}
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
/// Phase 123-125 P1-P2-P3-P4: Lower return value
///
/// ## Support
///
/// - Integer literal: Generate Const + Ret(Some(vid))
/// - None: Ret(None)
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
/// - Variable (Phase 124-125): lookup from env (writes + inputs)
/// - Phase 124: writes (written variables)
/// - Phase 125: inputs (reads-only from outer scope)
/// - Fail-Fast if not in env (structured error with hint)
/// - Other: Fail-Fast (out of scope)
fn lower_return_value(
value_ast: &Option<crate::mir::control_tree::step_tree::AstNodeHandle>,
body: &mut Vec<crate::mir::join_ir::JoinInst>,
next_value_id: &mut u32,
env: &std::collections::BTreeMap<String, crate::mir::ValueId>,
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};
use crate::mir::ValueId;
match value_ast {
None => {
body.push(JoinInst::Ret { value: None });
Ok(())
}
Some(ast_handle) => {
let ast = &ast_handle.0;
match &**ast {
ASTNode::Literal { value, .. } => match value {
LiteralValue::Integer(i) => {
// Phase 123 P1: Integer literal → Const + Ret(Some(vid))
let const_vid = ValueId(*next_value_id);
*next_value_id += 1;
// Generate Const instruction (wrapped in Compute)
body.push(JoinInst::Compute(MirLikeInst::Const {
dst: const_vid,
value: ConstValue::Integer(*i),
}));
// Generate Ret instruction
body.push(JoinInst::Ret {
value: Some(const_vid),
});
Ok(())
}
_ => {
// Phase 123: Other literals not supported
Err(format!(
"[phase123/return/literal_unsupported] Phase 123 only supports integer literals. Hint: Use integer literal or wait for Phase 124"
))
}
},
ASTNode::Variable { name, .. } => {
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
// Phase 124-125 P3-P4: Variable return support (dev-only)
// Check if variable is in env (writes + inputs)
if let Some(&vid) = env.get(name) {
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
// Phase 125 P4: Variable found in env (writes or inputs) - return it
body.push(JoinInst::Ret { value: Some(vid) });
Ok(())
} else {
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
// Phase 125 P4: Variable not in env - Fail-Fast with hint
// Check if variable is in reads (potential input)
let in_reads = contract.reads.contains(name);
let in_writes = contract.writes.contains(name);
let hint = if in_reads && !in_writes {
// Variable is read but not available as input
format!(
"Variable '{}' is read but not available from outer scope. \
Hint: Pass as function parameter, add to pinned capture, or define before if",
name
)
} else if !in_reads && !in_writes {
// Variable is neither read nor written (undefined)
format!(
"Variable '{}' is undefined. \
Hint: Define variable before return or check spelling",
name
)
} else {
// In writes but not in env (internal error)
format!(
"Variable '{}' in writes but not in env (internal error)",
name
)
};
Err(format!("[phase125/return/var_not_in_env] {}", hint))
}
}
_ => {
// Phase 123: Other expressions not supported
Err(format!(
"[phase123/return/expr_unsupported] Phase 123 only supports integer literals. Hint: Simplify to literal or wait for Phase 124"
))
}
}
}
}
}
/// Get shadow lowering status string for dev logging
///
/// ## Contract
///
/// - Returns 1-line summary: "shadow_lowered=true/false reason=..."
/// - Does not perform actual lowering (use `try_lower_if_only` for that)
pub fn get_status_string(step_tree: &StepTree) -> String {
let capability = check_if_only(step_tree);
match capability {
CapabilityCheckResult::Supported => {
format!(
"shadow_lowered=true step_tree_sig={} exits={:?} writes={:?}",
step_tree.signature_basis_string(),
step_tree.contract.exits,
step_tree.contract.writes
)
}
CapabilityCheckResult::Unsupported(reason) => {
format!(
"shadow_lowered=false reason=\"{}\" step_tree_sig={}",
reason.reason(),
step_tree.signature_basis_string()
)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mir::control_tree::step_tree::{
StepNode, StepStmtKind, StepTreeFeatures, StepTreeSignature,
};
use crate::mir::control_tree::step_tree_contract_box::StepTreeContract;
fn make_if_only_tree() -> StepTree {
StepTree {
root: StepNode::Block(vec![]),
features: StepTreeFeatures {
has_if: true,
has_loop: false,
has_break: false,
has_continue: false,
has_return: false,
max_if_depth: 1,
max_loop_depth: 0,
},
contract: StepTreeContract {
exits: Default::default(),
writes: Default::default(),
reads: Default::default(), // Phase 124
required_caps: Default::default(),
cond_sig: Default::default(),
},
signature: StepTreeSignature(0),
}
}
fn make_loop_tree() -> StepTree {
StepTree {
root: StepNode::Block(vec![]),
features: StepTreeFeatures {
has_if: false,
has_loop: true,
has_break: false,
has_continue: false,
has_return: false,
max_if_depth: 0,
max_loop_depth: 1,
},
contract: StepTreeContract {
exits: Default::default(),
writes: Default::default(),
reads: Default::default(), // Phase 124
required_caps: Default::default(),
cond_sig: Default::default(),
},
signature: StepTreeSignature(0),
}
}
#[test]
fn test_if_only_supported() {
let tree = make_if_only_tree();
let available_inputs = BTreeMap::new(); // Phase 126: empty for unit tests
let result = StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree, &available_inputs);
assert!(result.is_ok());
assert!(result.unwrap().is_some());
}
#[test]
fn test_loop_rejected() {
let tree = make_loop_tree();
let available_inputs = BTreeMap::new(); // Phase 126: empty for unit tests
let result = StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree, &available_inputs);
assert!(result.is_ok());
assert!(result.unwrap().is_none());
}
#[test]
fn test_status_string_if_only() {
let tree = make_if_only_tree();
let status = StepTreeNormalizedShadowLowererBox::get_status_string(&tree);
assert!(status.contains("shadow_lowered=true"));
assert!(status.contains("step_tree_sig="));
}
#[test]
fn test_status_string_loop() {
let tree = make_loop_tree();
let status = StepTreeNormalizedShadowLowererBox::get_status_string(&tree);
assert!(status.contains("shadow_lowered=false"));
assert!(status.contains("reason=\"contains loop"));
}
#[test]
fn test_return_integer_literal() {
use crate::ast::{ASTNode, LiteralValue, Span};
use crate::mir::control_tree::step_tree::AstNodeHandle;
// Create StepTree with "return 7"
let return_ast = Box::new(ASTNode::Literal {
value: LiteralValue::Integer(7),
span: Span::unknown(),
});
let mut tree = make_if_only_tree();
tree.root = StepNode::Stmt {
kind: StepStmtKind::Return {
value_ast: Some(AstNodeHandle(return_ast)),
},
span: Span::unknown(),
};
// Lower to JoinModule
let available_inputs = BTreeMap::new(); // Phase 126: empty for unit tests
let result = StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree, &available_inputs);
assert!(result.is_ok());
let (module, _meta) = result.unwrap().expect("Should generate JoinModule");
// Verify Const + Ret instructions
assert_eq!(module.functions.len(), 1);
let func = &module.functions.values().next().unwrap();
assert_eq!(func.body.len(), 2, "Should have Const + Ret");
// Check Const instruction
use crate::mir::join_ir::{ConstValue, JoinInst, MirLikeInst};
use crate::mir::ValueId;
if let JoinInst::Compute(MirLikeInst::Const { dst, value }) = &func.body[0] {
assert_eq!(*dst, ValueId(1));
if let ConstValue::Integer(i) = value {
assert_eq!(*i, 7);
} else {
panic!("Expected Integer const");
}
} else {
panic!("Expected Const instruction");
}
// Check Ret instruction
if let JoinInst::Ret { value } = &func.body[1] {
assert_eq!(value, &Some(ValueId(1)));
} else {
panic!("Expected Ret instruction");
}
}
#[test]
fn test_return_void() {
use crate::ast::Span;
// Create StepTree with "return" (no value)
let mut tree = make_if_only_tree();
tree.root = StepNode::Stmt {
kind: StepStmtKind::Return { value_ast: None },
span: Span::unknown(),
};
// Lower to JoinModule
let available_inputs = BTreeMap::new(); // Phase 126: empty for unit tests
let result = StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree, &available_inputs);
assert!(result.is_ok());
let (module, _meta) = result.unwrap().expect("Should generate JoinModule");
// Verify Ret(None) instruction
assert_eq!(module.functions.len(), 1);
let func = &module.functions.values().next().unwrap();
assert_eq!(func.body.len(), 1, "Should have only Ret");
// Check Ret instruction
use crate::mir::join_ir::JoinInst;
if let JoinInst::Ret { value } = &func.body[0] {
assert_eq!(value, &None);
} else {
panic!("Expected Ret instruction");
}
}
#[test]
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
fn test_return_variable_out_of_scope() {
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
// Phase 125 P4: Test Return(Variable) when variable is not in env (neither writes nor inputs)
// Expected: Ok(None) because variable is not available
use crate::ast::{ASTNode, Span};
use crate::mir::control_tree::step_tree::AstNodeHandle;
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
// Create StepTree with "return x" (variable not in env)
let return_ast = Box::new(ASTNode::Variable {
name: "x".to_string(),
span: Span::unknown(),
});
let mut tree = make_if_only_tree();
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
// Phase 125: Add x to reads (to simulate variable reference)
tree.contract.reads.insert("x".to_string());
tree.root = StepNode::Stmt {
kind: StepStmtKind::Return {
value_ast: Some(AstNodeHandle(return_ast)),
},
span: Span::unknown(),
};
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
// Phase 125 P4: Lower to JoinModule - should return Ok(None)
// because x is in reads but not in available_inputs (not in env)
let available_inputs = BTreeMap::new(); // Phase 126: empty for unit tests
let result = StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree, &available_inputs);
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
assert!(result.is_ok());
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
let option = result.unwrap();
assert!(option.is_none(), "Should return None when variable is in reads but not available as input");
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
}
#[test]
fn test_if_minimal_compare() {
use crate::ast::{ASTNode, BinaryOperator, LiteralValue, Span};
use crate::mir::control_tree::step_tree::AstNodeHandle;
// Create condition: flag == 1
let cond_ast = Box::new(ASTNode::BinaryOp {
operator: BinaryOperator::Equal,
left: Box::new(ASTNode::Variable {
name: "flag".to_string(),
span: Span::unknown(),
}),
right: Box::new(ASTNode::Literal {
value: LiteralValue::Integer(1),
span: Span::unknown(),
}),
span: Span::unknown(),
});
// Create then branch: return 2
let then_branch = Box::new(StepNode::Stmt {
kind: StepStmtKind::Return {
value_ast: Some(AstNodeHandle(Box::new(ASTNode::Literal {
value: LiteralValue::Integer(2),
span: Span::unknown(),
}))),
},
span: Span::unknown(),
});
// Create else branch: return 3
let else_branch = Some(Box::new(StepNode::Stmt {
kind: StepStmtKind::Return {
value_ast: Some(AstNodeHandle(Box::new(ASTNode::Literal {
value: LiteralValue::Integer(3),
span: Span::unknown(),
}))),
},
span: Span::unknown(),
}));
// Create If node
let mut tree = make_if_only_tree();
tree.root = StepNode::If {
cond: crate::mir::control_tree::step_tree::AstSummary::Other("test"),
cond_ast: AstNodeHandle(cond_ast),
then_branch,
else_branch,
span: Span::unknown(),
};
// Lower to JoinModule
let available_inputs = BTreeMap::new(); // Phase 126: empty for unit tests
let result = StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree, &available_inputs);
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
assert!(result.is_ok());
let (module, _meta) = result.unwrap().expect("Should generate JoinModule");
// Verify structure
assert_eq!(module.functions.len(), 1);
let func = &module.functions.values().next().unwrap();
// Should have: Const (lhs placeholder), Const (rhs), Compare, Const (return), Ret
assert!(func.body.len() >= 4, "Should have at least 4 instructions");
feat(control_tree): Phase 123 if-only compare+return lowering (Normalized, dev-only) Implements Phase 123 P3: If(cond_ast) minimal lowering with graceful degradation. **What's Implemented**: - If node lowering with minimal binary comparison (Variable op Integer) - Supported operators: ==, !=, <, <=, >, >= - Generates: Compare + Const + Ret structure - Graceful degradation: returns Ok(None) for unsupported patterns **Key Design Decisions**: 1. **Graceful Degradation**: Phase 123 limitations return `Ok(None)` instead of failing - Allows dev-only mode to coexist with legacy code - Error messages prefixed with `[phase123/...]` are caught 2. **Fail-Fast with Structured Errors**: All limitations use structured error codes - Format: `[phase123/category/specific]` 3. **Box-First Principles**: - `parse_minimal_compare`: Single responsibility parser - `verify_branch_is_return_literal`: Branch validation box - `lower_if_node`: If lowering box **Implementation**: - Added `lower_if_node`: If lowering with minimal compare - Added `parse_minimal_compare`: Binary comparison parser - Added `verify_branch_is_return_literal`: Branch validator - Updated `lower_if_only_to_normalized` return type: `Result<Option<...>, ...>` - Updated `test_return_variable_out_of_scope`: Verifies graceful degradation - Added `test_if_minimal_compare`: Verifies If lowering structure **Tests**: 8 passed (including graceful degradation test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 05:50:09 +09:00
// Verify Compare instruction exists
use crate::mir::join_ir::{JoinInst, MirLikeInst};
let has_compare = func.body.iter().any(|inst| {
matches!(
inst,
JoinInst::Compute(MirLikeInst::Compare { .. })
)
});
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 available_inputs = BTreeMap::new(); // Phase 126: empty for unit tests
let result = StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree, &available_inputs);
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");
}
}
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
#[test]
fn test_return_variable_from_inputs_stub() {
// Phase 125 P2-P4: Test Return(Variable) when variable is in inputs (reads-only)
// Note: P3 (available_inputs wiring) is not implemented yet, so this test
// demonstrates the structure but won't actually provide inputs
use crate::ast::{ASTNode, Span};
use crate::mir::control_tree::step_tree::AstNodeHandle;
// Create StepTree with "return x" where x is read-only input
let mut tree = make_if_only_tree();
// Phase 125 P2: Add x to reads (simulating outer scope variable read)
tree.contract.reads.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(),
};
// Phase 125 P2-P4: Lower to JoinModule
// Because available_inputs is empty (P3 not wired), x won't be in inputs
// So this should return Ok(None) (out of scope)
let available_inputs = BTreeMap::new(); // Phase 126: empty for unit tests
let result = StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree, &available_inputs);
refactor(control_tree): Phase 125 P2-P4 introduce EnvLayout (writes+inputs) + Return(Variable) from inputs Phase 125 P2: EnvLayout introduction - Add EnvLayout struct (writes + inputs) - from_contract() creates layout from StepTreeContract + available_inputs - SSOT: inputs = reads ∩ available_inputs (deterministic order) - No AST inference (don't capture from AST, use provided available_inputs) Phase 125 P2: Builder env mapping - lower_if_only_to_normalized: Use EnvLayout to create env map - writes: Generate ValueId (as before) - inputs: Reference ValueId from available_inputs (placeholder for P3) - Function params: writes only (inputs come from outer scope) Phase 125 P4: Return(Variable) resolution extended - lower_return_value: Check env (writes + inputs) - If found: return it (Phase 124 for writes, Phase 125 for inputs) - If not found: Fail-Fast with structured error + hint - Hint: "Pass as param, add to pinned capture, or define before if" - Phase 125 errors return Ok(None) (out of scope, graceful degradation) Unit tests: - test_return_variable_from_env: PASS (Phase 124 regression) - test_return_variable_out_of_scope: PASS (updated for Phase 125) - test_return_variable_from_inputs_stub: PASS (P3 not wired yet) - All 1160 lib tests PASS (no regression) Note: - P3 (available_inputs wiring) not implemented yet - available_inputs is empty BTreeMap (stub) - EnvLayout.inputs will be empty until P3 is wired - Structured error tags: [phase125/return/var_not_in_env] Ref: docs/development/current/main/phases/phase-125/README.md
2025-12-18 06:30:55 +09:00
assert!(result.is_ok());
let option = result.unwrap();
// Phase 125 P2: EnvLayout.inputs will be empty (no available_inputs)
// So x is not in env, and we get Ok(None)
assert!(option.is_none(), "Should return None when x is in reads but not in available_inputs (P3 not wired yet)");
}
}