Files
hakorune/src/mir/builder/calls/lowering.rs
nyash-codex 32a91e31ac feat(joinir): Phase 200-B/C/D capture analysis + Phase 201-A reserved_value_ids infra
Phase 200-B: FunctionScopeCaptureAnalyzer implementation
- analyze_captured_vars_v2() with structural loop matching
- CapturedEnv for immutable function-scope variables
- ParamRole::Condition for condition-only variables

Phase 200-C: ConditionEnvBuilder extension
- build_with_captures() integrates CapturedEnv into ConditionEnv
- fn_body propagation through LoopPatternContext to Pattern 2

Phase 200-D: E2E verification
- capture detection working for base, limit, n etc.
- Test files: phase200d_capture_minimal.hako, phase200d_capture_in_condition.hako

Phase 201-A: MirBuilder reserved_value_ids infrastructure
- reserved_value_ids: HashSet<ValueId> field in MirBuilder
- next_value_id() skips reserved IDs
- merge/mod.rs sets/clears reserved IDs around JoinIR merge

Phase 201: JoinValueSpace design document
- Param/Local/PHI disjoint regions design
- API: alloc_param(), alloc_local(), reserve_phi()
- Migration plan for Pattern 1-4 lowerers

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 18:32:03 +09:00

477 lines
19 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 🎯 箱理論: 関数lowering処理
//!
//! 責務:
//! - static/instance method を MIR function に lowering
//! - BoxCompilationContext による完全独立化
//! - パラメータ・型情報の適切な管理
use super::function_lowering;
use crate::ast::ASTNode;
use crate::mir::builder::{MirBuilder, MirInstruction, MirType};
use crate::mir::region::function_slot_registry::FunctionSlotRegistry;
use crate::mir::{MirValueKind, ValueId}; // Phase 26-A-3: ValueId型安全化
use std::collections::BTreeMap; // Phase 25.1: 決定性確保
/// 🎯 箱理論: Lowering Context準備と復元
struct LoweringContext {
context_active: bool,
saved_var_map: Option<BTreeMap<String, super::super::ValueId>>, // Phase 25.1: BTreeMap化
saved_static_ctx: Option<String>,
saved_function: Option<super::super::MirFunction>,
saved_block: Option<super::super::BasicBlockId>,
saved_slot_registry: Option<FunctionSlotRegistry>,
}
impl MirBuilder {
/// 🎯 箱理論: Step 1 - Lowering Context準備
fn prepare_lowering_context(&mut self, func_name: &str) -> LoweringContext {
// Static box context設定
let saved_static_ctx = self.current_static_box.clone();
if let Some(pos) = func_name.find('.') {
let box_name = &func_name[..pos];
if !box_name.is_empty() {
self.current_static_box = Some(box_name.to_string());
}
}
// BoxCompilationContext vs saved_var_map モード判定
let context_active = self.compilation_context.is_some();
let saved_var_map = if !context_active {
Some(std::mem::take(&mut self.variable_map))
} else {
None
};
// 関数スコープ SlotRegistry は元の関数側から退避しておくよ。
let saved_slot_registry = self.current_slot_registry.take();
// BoxCompilationContext mode: clear()で完全独立化
if context_active {
self.variable_map.clear();
self.value_origin_newbox.clear();
// value_types も static box 単位で独立させる。
// これにより、前の static box で使用された ValueId に紐づく型情報が
// 次の box にリークして誤った box_name 推論(例: Stage1UsingResolverBox
// を引き起こすことを防ぐ。
self.value_types.clear();
}
LoweringContext {
context_active,
saved_var_map,
saved_static_ctx,
saved_function: None,
saved_block: None,
saved_slot_registry,
}
}
/// 🎯 箱理論: Step 2 - 関数スケルトン作成
fn create_function_skeleton(
&mut self,
func_name: String,
params: &[String],
body: &[ASTNode],
ctx: &mut LoweringContext,
) -> Result<(), String> {
let signature =
function_lowering::prepare_static_method_signature(func_name.clone(), params, body);
let entry = self.block_gen.next();
let function = self.new_function_with_metadata(signature, entry);
// 現在の関数・ブロックを保存
ctx.saved_function = self.current_function.take();
ctx.saved_block = self.current_block.take();
eprintln!(
"[DEBUG/create_function_skeleton] Creating function: {}",
func_name
);
eprintln!("[DEBUG/create_function_skeleton] Entry block: {:?}", entry);
// 新しい関数に切り替え
self.current_function = Some(function);
self.current_block = Some(entry);
// 新しい関数スコープ用の SlotRegistry を準備するよ(観測専用)
self.current_slot_registry = Some(FunctionSlotRegistry::new());
self.ensure_block_exists(entry)?;
// Region 観測レイヤ: static 関数用の FunctionRegion を積むよ。
crate::mir::region::observer::observe_function_region(self);
Ok(())
}
/// 🎯 箱理論: Step 3 - パラメータ設定
fn setup_function_params(&mut self, params: &[String]) {
self.function_param_names.clear();
// SlotRegistry 更新は borrow 競合を避けるため、まずローカルに集約してから反映するよ。
let mut slot_regs: Vec<(String, Option<MirType>)> = Vec::new();
// Phase 26-A-3: パラメータ型情報も後で一括登録(借用競合回避)
let mut param_kinds: Vec<(ValueId, u32)> = Vec::new();
if let Some(ref mut f) = self.current_function {
// 📦 Hotfix 5: Use pre-populated params from MirFunction::new()
// Static methods have implicit receiver at params[0], so actual parameters start at offset
let receiver_offset = if f.params.is_empty() {
0
} else {
// If params already populated (by Hotfix 4+5), use them
if f.params.len() > params.len() {
1
} else {
0
}
};
let param_types = f.signature.params.clone();
for (idx, p) in params.iter().enumerate() {
let param_idx = receiver_offset + idx;
let pid = if param_idx < f.params.len() {
// Use pre-allocated ValueId from MirFunction::new()
f.params[param_idx]
} else {
// Allocate new ValueId (fallback for non-static methods)
let new_pid = f.next_value_id();
f.params.push(new_pid);
new_pid
};
self.variable_map.insert(p.clone(), pid);
self.function_param_names.insert(p.clone());
// Phase 26-A-3: パラメータ型情報を収集(後で一括登録)
// param_idx: receiver offset を考慮した実際のパラメータインデックス
param_kinds.push((pid, param_idx as u32));
let ty = param_types.get(param_idx).cloned();
slot_regs.push((p.clone(), ty));
}
}
// Phase 26-A-3: パラメータ型情報を一括登録GUARD Bug Prevention
for (pid, param_idx) in param_kinds {
self.register_value_kind(pid, MirValueKind::Parameter(param_idx));
}
if let Some(reg) = self.current_slot_registry.as_mut() {
for (name, ty) in slot_regs {
reg.ensure_slot(&name, ty);
}
}
}
/// 🎯 箱理論: Step 4 - 本体lowering
fn lower_function_body(&mut self, body: Vec<ASTNode>) -> Result<(), String> {
eprintln!("[DEBUG/lower_function_body] body.len() = {}", body.len());
let program_ast = function_lowering::wrap_in_program(body);
eprintln!("[DEBUG/lower_function_body] About to call build_expression");
let _last = self.build_expression(program_ast)?;
eprintln!("[DEBUG/lower_function_body] build_expression completed");
Ok(())
}
/// 🎯 箱理論: Step 5 - 関数finalize
fn finalize_function(&mut self, returns_value: bool) -> Result<(), String> {
// Void return追加必要な場合
if !returns_value {
if let Some(ref mut f) = self.current_function {
if let Some(block) = f.get_block(self.current_block.unwrap()) {
if !block.is_terminated() {
let void_val = crate::mir::builder::emission::constant::emit_void(self);
self.emit_instruction(MirInstruction::Return {
value: Some(void_val),
})?;
}
}
}
}
// 型推論
if let Some(ref mut f) = self.current_function {
if returns_value && matches!(f.signature.return_type, MirType::Void | MirType::Unknown)
{
let mut inferred: Option<MirType> = None;
'search: for (_bid, bb) in f.blocks.iter() {
for inst in bb.instructions.iter() {
if let MirInstruction::Return { value: Some(v) } = inst {
if let Some(mt) = self.value_types.get(v).cloned() {
inferred = Some(mt);
break 'search;
}
}
}
if let Some(MirInstruction::Return { value: Some(v) }) = &bb.terminator {
if let Some(mt) = self.value_types.get(v).cloned() {
inferred = Some(mt);
break;
}
}
}
if let Some(mt) = inferred {
f.signature.return_type = mt;
}
}
}
// Moduleに追加
let finalized = self.current_function.take().unwrap();
if let Some(ref mut module) = self.current_module {
module.add_function(finalized);
}
Ok(())
}
/// 🎯 箱理論: Step 6 - Context復元
fn restore_lowering_context(&mut self, ctx: LoweringContext) {
// 関数・ブロック復元
self.current_function = ctx.saved_function;
self.current_block = ctx.saved_block;
// モード別にcontext復元
if ctx.context_active {
// BoxCompilationContext mode: clear のみ(次回も完全独立)
self.variable_map.clear();
self.value_origin_newbox.clear();
// static box ごとに型情報も独立させる(前 box の型メタデータを引きずらない)
self.value_types.clear();
} else if let Some(saved) = ctx.saved_var_map {
// Legacy mode: Main.main 側の variable_map を元に戻す
self.variable_map = saved;
}
// Static box context復元
self.current_static_box = ctx.saved_static_ctx;
// 関数スコープ SlotRegistry も元の関数に戻すよ。
self.current_slot_registry = ctx.saved_slot_registry;
}
/// 🎯 箱理論: Step 2b - 関数スケルトン作成instance method版
fn create_method_skeleton(
&mut self,
func_name: String,
box_name: &str,
params: &[String],
body: &[ASTNode],
ctx: &mut LoweringContext,
) -> Result<(), String> {
let signature =
function_lowering::prepare_method_signature(func_name, box_name, params, body);
let entry = self.block_gen.next();
let function = self.new_function_with_metadata(signature, entry);
// 現在の関数・ブロックを保存
ctx.saved_function = self.current_function.take();
ctx.saved_block = self.current_block.take();
// 新しい関数に切り替え
self.current_function = Some(function);
self.current_block = Some(entry);
// instance method 用の関数スコープ SlotRegistry もここで用意するよ。
self.current_slot_registry = Some(FunctionSlotRegistry::new());
self.ensure_block_exists(entry)?;
// Region 観測レイヤ: instance method 用の FunctionRegion も積んでおくよ。
crate::mir::region::observer::observe_function_region(self);
Ok(())
}
/// 🎯 箱理論: Step 3b - パラメータ設定instance method版: me + params
fn setup_method_params(&mut self, box_name: &str, params: &[String]) {
// SlotRegistry 更新はローカルバッファに集約してから反映するよ。
let mut slot_regs: Vec<(String, Option<MirType>)> = Vec::new();
if let Some(ref mut f) = self.current_function {
// 📦 Hotfix 6 改訂版:
// MirFunction::new() が既に 0..N の ValueId を params 用に予約しているので、
// ここではそれを「上書き使用」するだけにして、push で二重定義しないようにするよ。
//
// params レイアウト:
// index 0: me (box<MyBox>)
// index 1..: 通常パラメータ
if f.params.is_empty() {
// 安全弁: 何らかの理由で pre-populate されていない場合は従来どおり new する
let me_id = ValueId(0);
f.params.push(me_id);
for i in 0..params.len() {
f.params.push(ValueId((i + 1) as u32));
}
}
// me
let me_id = f.params[0];
self.variable_map.insert("me".to_string(), me_id);
self.value_origin_newbox.insert(me_id, box_name.to_string());
slot_regs.push(("me".to_string(), None));
// 通常パラメータ
for (idx, p) in params.iter().enumerate() {
let param_idx = idx + 1;
if param_idx < f.params.len() {
let pid = f.params[param_idx];
self.variable_map.insert(p.clone(), pid);
slot_regs.push((p.clone(), None));
} else {
// 念のため足りない場合は新規に確保(互換用)
let pid = f.next_value_id();
f.params.push(pid);
self.variable_map.insert(p.clone(), pid);
slot_regs.push((p.clone(), None));
}
}
}
if let Some(reg) = self.current_slot_registry.as_mut() {
for (name, ty) in slot_regs {
reg.ensure_slot(&name, ty);
}
}
}
/// 🎯 箱理論: Step 4b - 本体loweringinstance method版: cf_block
fn lower_method_body(&mut self, body: Vec<ASTNode>) -> Result<(), String> {
let _last = self.cf_block(body)?;
Ok(())
}
/// 🎯 箱理論: 統合エントリーポイント - static method lowering
pub(in crate::mir::builder) fn lower_static_method_as_function(
&mut self,
func_name: String,
params: Vec<String>,
body: Vec<ASTNode>,
) -> Result<(), String> {
// Phase 200-C: Store fn_body for capture analysis
eprintln!("[lower_static_method_as_function] Storing fn_body with {} nodes for '{}'", body.len(), func_name);
self.fn_body_ast = Some(body.clone());
// Step 1: Context準備
let mut ctx = self.prepare_lowering_context(&func_name);
// Step 2: 関数スケルトン作成
self.create_function_skeleton(func_name, &params, &body, &mut ctx)?;
// Step 3: パラメータ設定
self.setup_function_params(&params);
// Step 4: 本体lowering
self.lower_function_body(body)?;
// Step 5: 関数finalize
let returns_value = if let Some(ref f) = self.current_function {
!matches!(f.signature.return_type, MirType::Void)
} else {
false
};
self.finalize_function(returns_value)?;
// FunctionRegion を 1 段ポップして元の関数コンテキストに戻るよ。
crate::mir::region::observer::pop_function_region(self);
// Step 6: Context復元
self.restore_lowering_context(ctx);
// Phase 200-C: Clear fn_body_ast after function lowering
self.fn_body_ast = None;
Ok(())
}
/// 🎯 箱理論: 統合エントリーポイント - instance method lowering
pub(in crate::mir::builder) fn lower_method_as_function(
&mut self,
func_name: String,
box_name: String,
params: Vec<String>,
body: Vec<ASTNode>,
) -> Result<(), String> {
// Phase 200-C: Store fn_body for capture analysis
self.fn_body_ast = Some(body.clone());
// Step 1: Context準備instance methodでは不要だがAPI統一のため
let mut ctx = LoweringContext {
context_active: false,
saved_var_map: Some(std::mem::take(&mut self.variable_map)),
saved_static_ctx: None,
saved_function: None,
saved_block: None,
saved_slot_registry: self.current_slot_registry.take(),
};
// Step 2b: 関数スケルトン作成method版
self.create_method_skeleton(func_name, &box_name, &params, &body, &mut ctx)?;
// Step 3b: パラメータ設定me + params
self.setup_method_params(&box_name, &params);
// Step 4b: 本体loweringcf_block版
self.lower_method_body(body)?;
// Step 5: 関数finalize
let returns_value = if let Some(ref f) = self.current_function {
!matches!(f.signature.return_type, MirType::Void)
} else {
false
};
// Void return追加必要な場合
if !returns_value && !self.is_current_block_terminated() {
let void_val = crate::mir::builder::emission::constant::emit_void(self);
self.emit_instruction(MirInstruction::Return {
value: Some(void_val),
})?;
}
// 型推論Step 5の一部として
if let Some(ref mut f) = self.current_function {
if returns_value && matches!(f.signature.return_type, MirType::Void | MirType::Unknown)
{
let mut inferred: Option<MirType> = None;
'search: for (_bid, bb) in f.blocks.iter() {
for inst in bb.instructions.iter() {
if let MirInstruction::Return { value: Some(v) } = inst {
if let Some(mt) = self.value_types.get(v).cloned() {
inferred = Some(mt);
break 'search;
}
}
}
if let Some(MirInstruction::Return { value: Some(v) }) = &bb.terminator {
if let Some(mt) = self.value_types.get(v).cloned() {
inferred = Some(mt);
break;
}
}
}
if let Some(mt) = inferred {
f.signature.return_type = mt;
}
}
}
// Moduleに追加
let finalized_function = self.current_function.take().unwrap();
if let Some(ref mut module) = self.current_module {
module.add_function(finalized_function);
}
// FunctionRegion を 1 段ポップして元の関数コンテキストに戻るよ。
crate::mir::region::observer::pop_function_region(self);
// Step 6: Context復元simple version
self.current_function = ctx.saved_function;
self.current_block = ctx.saved_block;
if let Some(saved) = ctx.saved_var_map {
self.variable_map = saved;
}
self.current_slot_registry = ctx.saved_slot_registry;
// Phase 200-C: Clear fn_body_ast after function lowering
self.fn_body_ast = None;
Ok(())
}
}