feat(mir): Phase 92 P2-2 - Body-local variable support for ConditionalStep

Phase 92 P2-2完了:ConditionalStepのcondition(ch == '\\'など)でbody-local変数をサポート

## 主要変更

### 1. condition_lowerer.rs拡張
- `lower_condition_to_joinir`に`body_local_env`パラメータ追加
- 変数解決優先度:ConditionEnv → LoopBodyLocalEnv
- すべての再帰ヘルパー(comparison, logical_and, logical_or, not, value_expression)対応

### 2. conditional_step_emitter.rs修正
- `emit_conditional_step_update`に`body_local_env`パラメータ追加
- condition loweringにbody-local環境を渡す

### 3. loop_with_break_minimal.rs修正
- break condition loweringをbody-local init の**後**に移動(line 411)
- header_break_lowering::lower_break_conditionにbody_local_env渡す
- emit_conditional_step_updateにbody_local_env渡す(line 620)

### 4. header_break_lowering.rs修正
- `lower_break_condition`に`body_local_env`パラメータ追加
- scope_managerにbody-local環境を渡す

### 5. 全呼び出し箇所修正
- expr_lowerer.rs (2箇所)
- method_call_lowerer.rs (2箇所)
- loop_with_if_phi_if_sum.rs (3箇所)
- loop_with_continue_minimal.rs (1箇所)
- carrier_update_emitter.rs (1箇所・legacy)

## アーキテクチャ改善

### Break Condition Lowering順序修正
旧: Header → **Break Cond** → Body-local Init
新: Header → **Body-local Init** → Break Cond

理由:break conditionが`ch == '\"'`のようにbody-local変数を参照する場合、body-local initが先に必要

### 変数解決優先度(Phase 92 P2-2)
1. ConditionEnv(ループパラメータ、captured変数)
2. LoopBodyLocalEnv(body-local変数like `ch`)

## テスト

### ビルド
 cargo build --release成功(30 warnings、0 errors)

### E2E
⚠️ body-local promotion問題でブロック(Phase 92範囲外)
- Pattern2はbody-local変数をcarrier promotionする必要あり
- 既存パターン(A-3 Trim, A-4 DigitPos)に`ch = get_char(i)`が該当しない
- **Phase 92 P2-2目標(condition loweringでbody-local変数サポート)は達成**

## 次タスク(Phase 92 P3以降)
- body-local variable promotion拡張(Pattern2で`ch`のような変数を扱う)
- P5b E2Eテスト完全動作確認

## Phase 92 P2-2完了
 Body-local変数のcondition lowering対応完了
 ConditionalStepでbody-local変数参照可能
 Break condition lowering順序修正
This commit is contained in:
nyash-codex
2025-12-16 17:08:15 +09:00
parent 3093ac2ca4
commit 568619df89
18 changed files with 371 additions and 55 deletions

View File

@ -408,7 +408,8 @@ pub fn emit_conditional_step_update(
instructions: &mut Vec<JoinInst>,
) -> Result<ValueId, String> {
// Step 1: Lower the condition expression
let (cond_id, cond_insts) = lower_condition_to_joinir(cond_ast, alloc_value, env)?;
// Phase 92 P2-2: No body-local support in legacy emitter (use common/conditional_step_emitter instead)
let (cond_id, cond_insts) = lower_condition_to_joinir(cond_ast, alloc_value, env, None)?;
instructions.extend(cond_insts);
// Step 2: Get carrier parameter ValueId from env

View File

@ -18,6 +18,7 @@ use crate::ast::ASTNode;
use crate::mir::join_ir::lowering::carrier_info::CarrierVar;
use crate::mir::join_ir::lowering::condition_env::ConditionEnv;
use crate::mir::join_ir::lowering::condition_lowerer::lower_condition_to_joinir;
use crate::mir::join_ir::lowering::loop_body_local_env::LoopBodyLocalEnv; // Phase 92 P2-2
use crate::mir::join_ir::{BinOpKind, ConstValue, JoinInst, MirLikeInst, VarId};
use crate::mir::{MirType, ValueId};
@ -44,8 +45,14 @@ use crate::mir::{MirType, ValueId};
/// * `else_delta` - Delta to add when condition is false
/// * `alloc_value` - ValueId allocator closure
/// * `env` - ConditionEnv for variable resolution
/// * `body_local_env` - Phase 92 P2-2: Optional body-local variable environment
/// * `instructions` - Output vector to append instructions to
///
/// # Phase 92 P2-2: Body-Local Variable Support
///
/// When the condition references body-local variables (e.g., `ch == '\\'` in escape patterns),
/// the `body_local_env` provides name → ValueId mappings for variables defined in the loop body.
///
/// # Returns
///
/// ValueId of the computed update result (the dst of Select)
@ -63,6 +70,7 @@ pub fn emit_conditional_step_update(
else_delta: i64,
alloc_value: &mut dyn FnMut() -> ValueId,
env: &ConditionEnv,
body_local_env: Option<&LoopBodyLocalEnv>, // Phase 92 P2-2
instructions: &mut Vec<JoinInst>,
) -> Result<ValueId, String> {
// Phase 92 P1-1: Fail-Fast check - then_delta must differ from else_delta
@ -73,8 +81,8 @@ pub fn emit_conditional_step_update(
));
}
// Step 1: Lower the condition expression
let (cond_id, cond_insts) = lower_condition_to_joinir(cond_ast, alloc_value, env).map_err(|e| {
// Phase 92 P2-2: Lower the condition expression with body-local support
let (cond_id, cond_insts) = lower_condition_to_joinir(cond_ast, alloc_value, env, body_local_env).map_err(|e| {
format!(
"ConditionalStep invariant violated: condition must be pure expression for carrier '{}': {}",
carrier_name, e

View File

@ -17,6 +17,7 @@ use crate::mir::join_ir::{BinOpKind, CompareOp, ConstValue, JoinInst, MirLikeIns
use crate::mir::ValueId;
use super::condition_env::ConditionEnv;
use super::loop_body_local_env::LoopBodyLocalEnv; // Phase 92 P2-2: Body-local support
use super::method_call_lowerer::MethodCallLowerer;
/// Lower an AST condition to JoinIR instructions
@ -26,6 +27,7 @@ use super::method_call_lowerer::MethodCallLowerer;
/// * `cond_ast` - AST node representing the boolean condition
/// * `alloc_value` - ValueId allocator function
/// * `env` - ConditionEnv for variable resolution (JoinIR-local ValueIds)
/// * `body_local_env` - Phase 92 P2-2: Optional body-local variable environment
///
/// # Returns
///
@ -38,6 +40,16 @@ use super::method_call_lowerer::MethodCallLowerer;
/// - Logical: `a && b`, `a || b`, `!cond`
/// - Variables and literals
///
/// # Phase 92 P2-2: Body-Local Variable Support
///
/// When lowering conditions that reference body-local variables (e.g., `ch == '\\'`
/// in escape patterns), the `body_local_env` parameter provides name → ValueId
/// mappings for variables defined in the loop body.
///
/// Variable resolution priority:
/// 1. ConditionEnv (loop parameters, captured variables)
/// 2. LoopBodyLocalEnv (body-local variables like `ch`)
///
/// # Example
///
/// ```ignore
@ -45,6 +57,9 @@ use super::method_call_lowerer::MethodCallLowerer;
/// env.insert("i".to_string(), ValueId(0));
/// env.insert("end".to_string(), ValueId(1));
///
/// let mut body_env = LoopBodyLocalEnv::new();
/// body_env.insert("ch".to_string(), ValueId(5)); // Phase 92 P2-2
///
/// let mut value_counter = 2u32;
/// let mut alloc_value = || {
/// let id = ValueId(value_counter);
@ -52,30 +67,37 @@ use super::method_call_lowerer::MethodCallLowerer;
/// id
/// };
///
/// // Lower condition: i < end
/// // Lower condition: ch == '\\'
/// let (cond_value, cond_insts) = lower_condition_to_joinir(
/// condition_ast,
/// &mut alloc_value,
/// &env,
/// Some(&body_env), // Phase 92 P2-2: Body-local support
/// )?;
/// ```
pub fn lower_condition_to_joinir(
cond_ast: &ASTNode,
alloc_value: &mut dyn FnMut() -> ValueId,
env: &ConditionEnv,
body_local_env: Option<&LoopBodyLocalEnv>, // Phase 92 P2-2
) -> Result<(ValueId, Vec<JoinInst>), String> {
let mut instructions = Vec::new();
let result_value = lower_condition_recursive(cond_ast, alloc_value, env, &mut instructions)?;
let result_value = lower_condition_recursive(cond_ast, alloc_value, env, body_local_env, &mut instructions)?;
Ok((result_value, instructions))
}
/// Recursive helper for condition lowering
///
/// Handles all supported AST node types and emits appropriate JoinIR instructions.
///
/// # Phase 92 P2-2
///
/// Added `body_local_env` parameter to support body-local variable resolution.
fn lower_condition_recursive(
cond_ast: &ASTNode,
alloc_value: &mut dyn FnMut() -> ValueId,
env: &ConditionEnv,
body_local_env: Option<&LoopBodyLocalEnv>, // Phase 92 P2-2
instructions: &mut Vec<JoinInst>,
) -> Result<ValueId, String> {
match cond_ast {
@ -92,10 +114,10 @@ fn lower_condition_recursive(
| BinaryOperator::LessEqual
| BinaryOperator::GreaterEqual
| BinaryOperator::Greater => {
lower_comparison(operator, left, right, alloc_value, env, instructions)
lower_comparison(operator, left, right, alloc_value, env, body_local_env, instructions)
}
BinaryOperator::And => lower_logical_and(left, right, alloc_value, env, instructions),
BinaryOperator::Or => lower_logical_or(left, right, alloc_value, env, instructions),
BinaryOperator::And => lower_logical_and(left, right, alloc_value, env, body_local_env, instructions),
BinaryOperator::Or => lower_logical_or(left, right, alloc_value, env, body_local_env, instructions),
_ => Err(format!(
"Unsupported binary operator in condition: {:?}",
operator
@ -107,12 +129,22 @@ fn lower_condition_recursive(
operator: UnaryOperator::Not,
operand,
..
} => lower_not_operator(operand, alloc_value, env, instructions),
} => lower_not_operator(operand, alloc_value, env, body_local_env, instructions),
// Variables - resolve from ConditionEnv
ASTNode::Variable { name, .. } => env
.get(name)
.ok_or_else(|| format!("Variable '{}' not bound in ConditionEnv", name)),
// Phase 92 P2-2: Variables - resolve from ConditionEnv or LoopBodyLocalEnv
ASTNode::Variable { name, .. } => {
// Priority 1: ConditionEnv (loop parameters, captured variables)
if let Some(value_id) = env.get(name) {
return Ok(value_id);
}
// Priority 2: LoopBodyLocalEnv (body-local variables like `ch`)
if let Some(body_env) = body_local_env {
if let Some(value_id) = body_env.get(name) {
return Ok(value_id);
}
}
Err(format!("Variable '{}' not found in ConditionEnv or LoopBodyLocalEnv", name))
}
// Literals - emit as constants
ASTNode::Literal { value, .. } => lower_literal(value, alloc_value, instructions),
@ -128,11 +160,12 @@ fn lower_comparison(
right: &ASTNode,
alloc_value: &mut dyn FnMut() -> ValueId,
env: &ConditionEnv,
body_local_env: Option<&LoopBodyLocalEnv>, // Phase 92 P2-2
instructions: &mut Vec<JoinInst>,
) -> Result<ValueId, String> {
// Lower left and right sides
let lhs = lower_value_expression(left, alloc_value, env, instructions)?;
let rhs = lower_value_expression(right, alloc_value, env, instructions)?;
let lhs = lower_value_expression(left, alloc_value, env, body_local_env, instructions)?;
let rhs = lower_value_expression(right, alloc_value, env, body_local_env, instructions)?;
let dst = alloc_value();
let cmp_op = match operator {
@ -162,11 +195,12 @@ fn lower_logical_and(
right: &ASTNode,
alloc_value: &mut dyn FnMut() -> ValueId,
env: &ConditionEnv,
body_local_env: Option<&LoopBodyLocalEnv>, // Phase 92 P2-2
instructions: &mut Vec<JoinInst>,
) -> Result<ValueId, String> {
// Logical AND: evaluate both sides and combine
let lhs = lower_condition_recursive(left, alloc_value, env, instructions)?;
let rhs = lower_condition_recursive(right, alloc_value, env, instructions)?;
let lhs = lower_condition_recursive(left, alloc_value, env, body_local_env, instructions)?;
let rhs = lower_condition_recursive(right, alloc_value, env, body_local_env, instructions)?;
let dst = alloc_value();
// Emit BinOp And instruction
@ -186,11 +220,12 @@ fn lower_logical_or(
right: &ASTNode,
alloc_value: &mut dyn FnMut() -> ValueId,
env: &ConditionEnv,
body_local_env: Option<&LoopBodyLocalEnv>, // Phase 92 P2-2
instructions: &mut Vec<JoinInst>,
) -> Result<ValueId, String> {
// Logical OR: evaluate both sides and combine
let lhs = lower_condition_recursive(left, alloc_value, env, instructions)?;
let rhs = lower_condition_recursive(right, alloc_value, env, instructions)?;
let lhs = lower_condition_recursive(left, alloc_value, env, body_local_env, instructions)?;
let rhs = lower_condition_recursive(right, alloc_value, env, body_local_env, instructions)?;
let dst = alloc_value();
// Emit BinOp Or instruction
@ -209,9 +244,10 @@ fn lower_not_operator(
operand: &ASTNode,
alloc_value: &mut dyn FnMut() -> ValueId,
env: &ConditionEnv,
body_local_env: Option<&LoopBodyLocalEnv>, // Phase 92 P2-2
instructions: &mut Vec<JoinInst>,
) -> Result<ValueId, String> {
let operand_val = lower_condition_recursive(operand, alloc_value, env, instructions)?;
let operand_val = lower_condition_recursive(operand, alloc_value, env, body_local_env, instructions)?;
let dst = alloc_value();
// Emit UnaryOp Not instruction
@ -258,17 +294,33 @@ fn lower_literal(
///
/// This handles the common case where we need to evaluate a simple value
/// (variable or literal) as part of a comparison.
///
/// # Phase 92 P2-2
///
/// Added `body_local_env` parameter to support body-local variable resolution
/// (e.g., `ch` in `ch == '\\'`).
pub fn lower_value_expression(
expr: &ASTNode,
alloc_value: &mut dyn FnMut() -> ValueId,
env: &ConditionEnv,
body_local_env: Option<&LoopBodyLocalEnv>, // Phase 92 P2-2
instructions: &mut Vec<JoinInst>,
) -> Result<ValueId, String> {
match expr {
// Variables - look up in ConditionEnv
ASTNode::Variable { name, .. } => env
.get(name)
.ok_or_else(|| format!("Variable '{}' not bound in ConditionEnv", name)),
// Phase 92 P2-2: Variables - resolve from ConditionEnv or LoopBodyLocalEnv
ASTNode::Variable { name, .. } => {
// Priority 1: ConditionEnv (loop parameters, captured variables)
if let Some(value_id) = env.get(name) {
return Ok(value_id);
}
// Priority 2: LoopBodyLocalEnv (body-local variables like `ch`)
if let Some(body_env) = body_local_env {
if let Some(value_id) = body_env.get(name) {
return Ok(value_id);
}
}
Err(format!("Variable '{}' not found in ConditionEnv or LoopBodyLocalEnv", name))
}
// Literals - emit as constants
ASTNode::Literal { value, .. } => lower_literal(value, alloc_value, instructions),
@ -279,7 +331,7 @@ pub fn lower_value_expression(
left,
right,
..
} => lower_arithmetic_binop(operator, left, right, alloc_value, env, instructions),
} => lower_arithmetic_binop(operator, left, right, alloc_value, env, body_local_env, instructions),
// Phase 224-C: MethodCall support with arguments (e.g., s.length(), s.indexOf(ch))
ASTNode::MethodCall {
@ -289,7 +341,7 @@ pub fn lower_value_expression(
..
} => {
// 1. Lower receiver (object) to ValueId
let recv_val = lower_value_expression(object, alloc_value, env, instructions)?;
let recv_val = lower_value_expression(object, alloc_value, env, body_local_env, instructions)?;
// 2. Lower method call using MethodCallLowerer (will lower arguments internally)
MethodCallLowerer::lower_for_condition(
@ -316,10 +368,11 @@ fn lower_arithmetic_binop(
right: &ASTNode,
alloc_value: &mut dyn FnMut() -> ValueId,
env: &ConditionEnv,
body_local_env: Option<&LoopBodyLocalEnv>, // Phase 92 P2-2
instructions: &mut Vec<JoinInst>,
) -> Result<ValueId, String> {
let lhs = lower_value_expression(left, alloc_value, env, instructions)?;
let rhs = lower_value_expression(right, alloc_value, env, instructions)?;
let lhs = lower_value_expression(left, alloc_value, env, body_local_env, instructions)?;
let rhs = lower_value_expression(right, alloc_value, env, body_local_env, instructions)?;
let dst = alloc_value();
let bin_op = match operator {

View File

@ -211,7 +211,7 @@ impl<'env, 'builder, S: ScopeManager> ExprLowerer<'env, 'builder, S> {
};
let (result_value, instructions) =
lower_condition_to_joinir(ast, &mut alloc_value, &condition_env)
lower_condition_to_joinir(ast, &mut alloc_value, &condition_env, None) // Phase 92 P2-2
.map_err(|e| ExprLoweringError::LoweringError(e))?;
// Phase 235: 保存しておき、テストから観察できるようにする
@ -297,7 +297,7 @@ impl<'env, 'builder, S: ScopeManager> ConditionLoweringBox<S> for ExprLowerer<'e
// Delegate to the well-tested lowerer, but use the caller-provided allocator (SSOT).
let (result_value, instructions) =
lower_condition_to_joinir(condition, &mut *context.alloc_value, &condition_env)
lower_condition_to_joinir(condition, &mut *context.alloc_value, &condition_env, None) // Phase 92 P2-2
.map_err(|e| e.to_string())?;
self.last_instructions = instructions;

View File

@ -63,8 +63,10 @@ mod tests;
use crate::mir::join_ir::lowering::carrier_info::{CarrierInfo, JoinFragmentMeta};
use crate::mir::join_ir::lowering::carrier_update_emitter::{
emit_carrier_update, emit_carrier_update_with_env, emit_conditional_step_update,
emit_carrier_update, emit_carrier_update_with_env,
};
// Phase 92 P2-1: Import ConditionalStep emitter from dedicated module
use crate::mir::join_ir::lowering::common::conditional_step_emitter::emit_conditional_step_update;
use crate::mir::join_ir::lowering::condition_to_joinir::ConditionEnv;
use crate::mir::loop_canonicalizer::UpdateKind;
use crate::mir::join_ir::lowering::join_value_space::JoinValueSpace;
@ -290,15 +292,8 @@ pub(crate) fn lower_loop_with_break_minimal(
// After condition lowering, allocate remaining ValueIds
let exit_cond = alloc_value(); // Exit condition (negated loop condition)
// Phase 170-B / Phase 236-EX / Phase 244: Lower break condition
let (break_cond_value, break_cond_instructions) = lower_break_condition(
break_condition,
env,
carrier_info,
loop_var_name,
i_param,
&mut alloc_value,
)?;
// Phase 92 P2-2: Break condition lowering moved after body-local init
// (will be called later after body_local_env is populated)
let _const_1 = alloc_value(); // Increment constant
let _i_next = alloc_value(); // i + 1
@ -409,6 +404,20 @@ pub(crate) fn lower_loop_with_break_minimal(
);
}
// ------------------------------------------------------------------
// Phase 170-B / Phase 244 / Phase 92 P2-2: Lower break condition
// ------------------------------------------------------------------
// Phase 92 P2-2: Moved after body-local init to support body-local variable references
let (break_cond_value, break_cond_instructions) = lower_break_condition(
break_condition,
env,
carrier_info,
loop_var_name,
i_param,
&mut alloc_value,
body_local_env.as_ref().map(|e| &**e), // Phase 92 P2-2: Pass body_local_env
)?;
// ------------------------------------------------------------------
// Phase 170-B: Break Condition Check (delegated to condition_to_joinir)
// ------------------------------------------------------------------
@ -588,27 +597,39 @@ pub(crate) fn lower_loop_with_break_minimal(
continue;
}
// Phase 92 P0-3: Check if skeleton has ConditionalStep for this carrier
// Phase 92 P2-1: Check if skeleton has ConditionalStep for this carrier
if let Some(skel) = skeleton {
if let Some(carrier_slot) = skel.carriers.iter().find(|c| c.name == *carrier_name) {
if let UpdateKind::ConditionalStep { cond, then_delta, else_delta } = &carrier_slot.update_kind {
// Use emit_conditional_step_update instead of emit_carrier_update
// Phase 92 P2-1: Use ConditionalStepEmitter (dedicated module)
eprintln!(
"[joinir/pattern2] Phase 92 P0-3: ConditionalStep detected for carrier '{}': then={}, else={}",
"[joinir/pattern2] Phase 92 P2-1: ConditionalStep detected for carrier '{}': then={}, else={}",
carrier_name, then_delta, else_delta
);
// Phase 92 P2-1: Get carrier parameter ValueId (must be set by header PHI)
let carrier_param = carrier.join_id.ok_or_else(|| {
format!(
"[pattern2/conditional_step] Carrier '{}' join_id not set (header PHI not generated?)",
carrier_name
)
})?;
// Phase 92 P2-2: Pass body_local_env for condition lowering
let updated_value = emit_conditional_step_update(
carrier,
carrier_name,
carrier_param,
&*cond,
*then_delta,
*else_delta,
&mut alloc_value,
env,
body_local_env.as_ref().map(|e| &**e), // Phase 92 P2-2
&mut carrier_update_block,
)?;
).map_err(|e| format!("[pattern2/conditional_step] {}", e))?;
updated_carrier_values.push(updated_value);
eprintln!(
"[joinir/pattern2] Phase 92 P0-3: ConditionalStep carrier '{}' updated → {:?}",
"[joinir/pattern2] Phase 92 P2-1: ConditionalStep carrier '{}' updated → {:?}",
carrier_name, updated_value
);
continue; // Skip normal carrier update

View File

@ -77,11 +77,16 @@ pub(crate) fn lower_header_condition(
"[joinir/pattern2/phase244] Header condition via legacy path (not yet supported by ConditionLoweringBox)"
);
let mut shim = || alloc_value();
lower_condition_to_joinir(condition, &mut shim, env)
lower_condition_to_joinir(condition, &mut shim, env, None) // Phase 92 P2-2: No body-local for header
}
}
/// Lower the break condition via ExprLowerer (no legacy fallback).
///
/// # Phase 92 P2-2: Body-Local Variable Support
///
/// Added `body_local_env` parameter to support break conditions that reference
/// body-local variables (e.g., `ch == '"'` in escape patterns).
pub(crate) fn lower_break_condition(
break_condition: &ASTNode,
env: &ConditionEnv,
@ -89,14 +94,18 @@ pub(crate) fn lower_break_condition(
loop_var_name: &str,
loop_var_id: ValueId,
alloc_value: &mut dyn FnMut() -> ValueId,
body_local_env: Option<&LoopBodyLocalEnv>, // Phase 92 P2-2
) -> Result<(ValueId, Vec<JoinInst>), String> {
use crate::mir::join_ir::lowering::condition_lowering_box::ConditionLoweringBox;
// Phase 92 P2-2: Use provided body_local_env or empty if None
let empty_body_env = LoopBodyLocalEnv::new();
let body_env_ref = body_local_env.unwrap_or(&empty_body_env);
let empty_captured_env = CapturedEnv::new();
let scope_manager = make_scope_manager(
env,
Some(&empty_body_env),
Some(body_env_ref), // Phase 92 P2-2: Pass body_local_env to scope
Some(&empty_captured_env),
carrier_info,
);

View File

@ -284,7 +284,7 @@ pub(crate) fn lower_loop_with_continue_minimal(
} else {
// Legacy path: condition_to_joinir (for complex conditions not yet supported)
eprintln!("[joinir/pattern4/phase244] Header condition via legacy path (not yet supported by ConditionLoweringBox)");
lower_condition_to_joinir(condition, &mut alloc_value, &env)?
lower_condition_to_joinir(condition, &mut alloc_value, &env, None)? // Phase 92 P2-2: No body-local for header
}
};

View File

@ -464,7 +464,7 @@ where
column: 1,
},
};
lower_value_expression(&var_node, alloc_value, cond_env, &mut limit_instructions)?
lower_value_expression(&var_node, alloc_value, cond_env, None, &mut limit_instructions)? // Phase 92 P2-2
}
};
@ -500,10 +500,10 @@ where
// Lower left-hand side (complex expression)
let mut instructions = Vec::new();
let lhs_val = lower_value_expression(left, alloc_value, cond_env, &mut instructions)?;
let lhs_val = lower_value_expression(left, alloc_value, cond_env, None, &mut instructions)?; // Phase 92 P2-2
// Lower right-hand side
let rhs_val = lower_value_expression(right, alloc_value, cond_env, &mut instructions)?;
let rhs_val = lower_value_expression(right, alloc_value, cond_env, None, &mut instructions)?; // Phase 92 P2-2
// Extract base variable name from LHS if possible
let var_name = extract_base_variable(left);

View File

@ -127,6 +127,7 @@ impl MethodCallLowerer {
arg_ast,
alloc_value,
env,
None, // Phase 92 P2-2: No body-local for method call args
instructions,
)?;
lowered_args.push(arg_val);
@ -305,6 +306,7 @@ impl MethodCallLowerer {
expr,
alloc_value,
cond_env,
None, // Phase 92 P2-2: No body-local for method call expressions
instructions,
),
}