feat(joinir): Phase 191 body-local init integration into Pattern2

- Integrated LoopBodyLocalInitLowerer into Pattern2 lowering
- Fixed ValueId double-allocation issue (delegate to InitLowerer)
- Added body_ast parameter to lower_loop_with_break_minimal()
- Fixed json_program_loop.rs test for body-local scope
- New test: phase191_body_local_atoi.hako (expected: 123)

Supported init expressions:
- Integer literals, variable references, binary operations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-09 03:40:25 +09:00
parent 57cf67002e
commit ba33bfc323
5 changed files with 167 additions and 17 deletions

View File

@ -154,16 +154,13 @@ impl MirBuilder {
id
};
// Phase 185-2: Collect body-local variables with safe ValueId allocation
// Phase 191: Create empty body-local environment
// LoopBodyLocalInitLowerer will populate it during init lowering
use crate::mir::join_ir::lowering::loop_body_local_env::LoopBodyLocalEnv;
let body_locals = collect_body_local_variables(_body, &mut alloc_body_local_value);
let body_local_env = LoopBodyLocalEnv::from_locals(body_locals);
let mut body_local_env = LoopBodyLocalEnv::new();
eprintln!("[pattern2/body-local] Phase 185-2: Collected {} body-local variables (offset={})",
body_local_env.len(), body_local_start_offset);
for (name, vid) in body_local_env.iter() {
eprintln!(" {}{:?}", name, vid);
}
eprintln!("[pattern2/body-local] Phase 191: Created empty body-local environment (offset={})",
body_local_start_offset);
// Create allocator for other JoinIR-local ValueIds (Trim pattern, etc.)
// Continues from where body_local_counter left off
@ -307,7 +304,8 @@ impl MirBuilder {
&env,
&carrier_info,
&carrier_updates,
Some(&body_local_env), // Phase 185-2: Pass body-local environment
_body, // Phase 191: Pass body AST for init lowering
Some(&mut body_local_env), // Phase 191: Pass mutable body-local environment
) {
Ok((module, meta)) => (module, meta),
Err(e) => {

View File

@ -129,7 +129,8 @@ use std::collections::HashMap;
/// * `break_condition` - AST node for the break condition (e.g., `i >= 2`) - Phase 170-B
/// * `carrier_info` - Phase 176-3: Carrier metadata for dynamic multi-carrier support
/// * `carrier_updates` - Phase 176-3: Update expressions for each carrier variable
/// * `body_local_env` - Phase 185-2: Optional body-local variable environment for update expressions
/// * `body_ast` - Phase 191: Loop body AST for body-local init lowering
/// * `body_local_env` - Phase 185-2: Optional mutable body-local variable environment for init expressions
pub(crate) fn lower_loop_with_break_minimal(
_scope: LoopScopeShape,
condition: &ASTNode,
@ -137,7 +138,8 @@ pub(crate) fn lower_loop_with_break_minimal(
env: &ConditionEnv,
carrier_info: &CarrierInfo,
carrier_updates: &HashMap<String, UpdateExpr>,
body_local_env: Option<&LoopBodyLocalEnv>,
body_ast: &[ASTNode],
mut body_local_env: Option<&mut LoopBodyLocalEnv>,
) -> Result<(JoinModule, JoinFragmentMeta), String> {
// Phase 170-D-impl-3: Validate that conditions only use supported variable scopes
// LoopConditionScopeBox checks that loop conditions don't reference loop-body-local variables
@ -308,6 +310,29 @@ pub(crate) fn lower_loop_with_break_minimal(
cond: Some(break_cond_value), // Phase 170-B: Use lowered condition
});
// ------------------------------------------------------------------
// Phase 191: Body-Local Variable Initialization
// ------------------------------------------------------------------
// Lower body-local variable initialization expressions to JoinIR
// This must happen BEFORE carrier updates since carrier updates may reference body-locals
if let Some(ref mut body_env) = body_local_env {
use crate::mir::join_ir::lowering::loop_body_local_init::LoopBodyLocalInitLowerer;
// Create a mutable reference to the instruction buffer
let mut init_lowerer = LoopBodyLocalInitLowerer::new(
env,
&mut loop_step_func.body,
Box::new(&mut alloc_value),
);
init_lowerer.lower_inits_for_loop(body_ast, body_env)?;
eprintln!(
"[joinir/pattern2] Phase 191: Lowered {} body-local init expressions",
body_env.len()
);
}
// ------------------------------------------------------------------
// Loop Body: Compute updated values for all carriers
// ------------------------------------------------------------------
@ -326,7 +351,7 @@ pub(crate) fn lower_loop_with_break_minimal(
})?;
// Phase 185-2: Emit carrier update with body-local support
let updated_value = if let Some(body_env) = body_local_env {
let updated_value = if let Some(ref body_env) = body_local_env {
// Use UpdateEnv for body-local variable resolution
let update_env = UpdateEnv::new(env, body_env);
emit_carrier_update_with_env(