Files
hakorune/src/mir/builder/calls/lowering.rs
nyash-codex cc1a0946b0 feat(joinir/dev): build Normalized if-only module with structure verification (no behavior change)
Phase 122 P2-P3: Dev-only wiring + structure verification
- Wire Phase 122 emission into existing Phase 121 dev path
- Add verify_normalized_structure() for module validation
- Check: phase, function count, entry point, env args count
- Strict mode: fail-fast on structure mismatch
- No behavior change to existing execution path
2025-12-18 04:52:09 +09:00

599 lines
24 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.comp_ctx.current_static_box.clone();
if let Some(pos) = func_name.find('.') {
let box_name = &func_name[..pos];
if !box_name.is_empty() {
self.comp_ctx.current_static_box = Some(box_name.to_string());
}
}
// BoxCompilationContext vs saved_var_map モード判定
let context_active = self.comp_ctx.compilation_context.is_some();
let saved_var_map = if !context_active {
Some(std::mem::take(&mut self.variable_ctx.variable_map))
} else {
None
};
// 関数スコープ SlotRegistry は元の関数側から退避しておくよ。
let saved_slot_registry = self.comp_ctx.current_slot_registry.take();
// BoxCompilationContext mode: clear()で完全独立化
if context_active {
self.variable_ctx.variable_map.clear();
self.type_ctx.value_origin_newbox.clear();
// value_types も static box 単位で独立させる。
// これにより、前の static box で使用された ValueId に紐づく型情報が
// 次の box にリークして誤った box_name 推論(例: Stage1UsingResolverBox
// を引き起こすことを防ぐ。
self.type_ctx.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.next_block_id();
let function = self.new_function_with_metadata(signature, entry);
// Phase 136 Step 3/7: Save from scope_ctx (SSOT)
ctx.saved_function = self.scope_ctx.current_function.take();
ctx.saved_block = self.current_block.take();
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
trace.emit_if(
"debug",
"create_function_skeleton",
&format!("Creating function: {}", func_name),
trace.is_enabled(),
);
trace.emit_if(
"debug",
"create_function_skeleton",
&format!("Entry block: {:?}", entry),
trace.is_enabled(),
);
// Phase 136 Step 3/7: Use scope_ctx as SSOT
self.scope_ctx.current_function = Some(function);
self.current_block = Some(entry);
// 新しい関数スコープ用の SlotRegistry を準備するよ(観測専用)
self.comp_ctx.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 - パラメータ設定
#[allow(deprecated)]
fn setup_function_params(&mut self, params: &[String]) {
// Phase 136 Step 3/7: Clear scope_ctx (SSOT)
self.scope_ctx.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.scope_ctx.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_ctx.variable_map.insert(p.clone(), pid);
// Phase 136 Step 3/7: Insert into scope_ctx (SSOT)
self.scope_ctx.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.comp_ctx.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> {
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
// Phase 112: StepTree capability guard (strict-only)
let strict = crate::config::env::joinir_dev::strict_enabled();
let dev = crate::config::env::joinir_dev_enabled();
if strict || dev {
let tree = crate::mir::control_tree::StepTreeBuilderBox::build_from_block(&body);
if dev {
trace.dev("control_tree/step_tree", &tree.to_compact_string());
}
// Phase 112: Guard check (strict mode only)
let func_name = self
.scope_ctx
.current_function
.as_ref()
.map(|f| f.signature.name.clone())
.unwrap_or_else(|| "<unknown>".to_string());
crate::mir::builder::control_flow::joinir::control_tree_capability_guard::check(
&tree, &func_name, strict, dev,
)?;
// Phase 121/122: StepTree→Normalized shadow lowering (dev-only)
if dev {
use crate::mir::control_tree::normalized_shadow::StepTreeNormalizedShadowLowererBox;
use crate::mir::control_tree::normalized_shadow::parity;
// Try shadow lowering (if-only scope)
let shadow_result = StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree);
match shadow_result {
Ok(Some((module, _meta))) => {
// Phase 122: Verify Normalized JoinModule structure
let expected_env_fields = tree.contract.writes.len();
let verify_result = parity::verify_normalized_structure(&module, expected_env_fields);
if !verify_result.ok {
let msg = format!(
"phase122/emit: structure verification failed for {}: {}",
func_name,
verify_result.hint.unwrap_or_else(|| "<no hint>".to_string())
);
if strict {
return Err(format!(
"Phase122 Normalized structure verification failed (strict mode): {}",
msg
));
}
trace.dev("phase122/emit/error", &msg);
} else {
// Shadow lowering succeeded + structure verified
let status = format!(
"module_emitted=true funcs={} env_fields={} step_tree_sig={}",
module.functions.len(),
expected_env_fields,
tree.signature_basis_string()
);
trace.dev("phase122/emit", &status);
}
}
Ok(None) => {
// Out of scope (e.g., contains loops)
let status = StepTreeNormalizedShadowLowererBox::get_status_string(&tree);
trace.dev("phase121/shadow", &status);
}
Err(err) => {
// Should be supported but failed (internal error)
let msg = format!(
"phase121/shadow: internal error for {}: {}",
func_name, err
);
if strict {
return Err(format!(
"Phase121 shadow lowering failed (strict mode): {}\nHint: if-only pattern should be supported but conversion failed",
err
));
}
trace.dev("phase121/shadow/error", &msg);
}
}
}
}
trace.emit_if(
"debug",
"lower_function_body",
&format!("body.len() = {}", body.len()),
trace.is_enabled(),
);
let program_ast = function_lowering::wrap_in_program(body);
trace.emit_if(
"debug",
"lower_function_body",
"About to call build_expression",
trace.is_enabled(),
);
let _last = self.build_expression(program_ast)?;
trace.emit_if(
"debug",
"lower_function_body",
"build_expression completed",
trace.is_enabled(),
);
Ok(())
}
/// 🎯 箱理論: Step 5 - 関数finalize
#[allow(deprecated)]
fn finalize_function(&mut self, returns_value: bool) -> Result<(), String> {
// Void return追加必要な場合
if !returns_value {
if let Some(ref mut f) = self.scope_ctx.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.scope_ctx.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.type_ctx.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.type_ctx.value_types.get(v).cloned() {
inferred = Some(mt);
break;
}
}
}
if let Some(mt) = inferred {
f.signature.return_type = mt;
}
}
}
// Moduleに追加
// Phase 136 Step 3/7: Take from scope_ctx (SSOT)
let finalized = self.scope_ctx.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) {
// Phase 136 Step 3/7: Restore to scope_ctx (SSOT)
self.scope_ctx.current_function = ctx.saved_function;
self.current_block = ctx.saved_block;
// モード別にcontext復元
if ctx.context_active {
// BoxCompilationContext mode: clear のみ(次回も完全独立)
self.variable_ctx.variable_map.clear();
self.type_ctx.value_origin_newbox.clear();
// static box ごとに型情報も独立させる(前 box の型メタデータを引きずらない)
self.type_ctx.value_types.clear();
} else if let Some(saved) = ctx.saved_var_map {
// Legacy mode: Main.main 側の variable_map を元に戻す
self.variable_ctx.variable_map = saved;
}
// Static box context復元
self.comp_ctx.current_static_box = ctx.saved_static_ctx;
// 関数スコープ SlotRegistry も元の関数に戻すよ。
self.comp_ctx.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.next_block_id();
let function = self.new_function_with_metadata(signature, entry);
// Phase 136 Step 3/7: Save from scope_ctx (SSOT)
ctx.saved_function = self.scope_ctx.current_function.take();
ctx.saved_block = self.current_block.take();
// Phase 136 Step 3/7: Use scope_ctx as SSOT
self.scope_ctx.current_function = Some(function);
self.current_block = Some(entry);
// instance method 用の関数スコープ SlotRegistry もここで用意するよ。
self.comp_ctx.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.scope_ctx.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_ctx
.variable_map
.insert("me".to_string(), me_id);
self.type_ctx
.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_ctx.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_ctx.variable_map.insert(p.clone(), pid);
slot_regs.push((p.clone(), None));
}
}
}
if let Some(reg) = self.comp_ctx.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.comp_ctx.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.scope_ctx.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.comp_ctx.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.comp_ctx.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_ctx.variable_map)),
saved_static_ctx: None,
saved_function: None,
saved_block: None,
saved_slot_registry: self.comp_ctx.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.scope_ctx.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.scope_ctx.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.type_ctx.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.type_ctx.value_types.get(v).cloned() {
inferred = Some(mt);
break;
}
}
}
if let Some(mt) = inferred {
f.signature.return_type = mt;
}
}
}
// Moduleに追加
let finalized_function = self.scope_ctx.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);
// Phase 136 Step 3/7: Restore to scope_ctx (SSOT)
self.scope_ctx.current_function = ctx.saved_function;
self.current_block = ctx.saved_block;
if let Some(saved) = ctx.saved_var_map {
self.variable_ctx.variable_map = saved;
}
self.comp_ctx.current_slot_registry = ctx.saved_slot_registry;
// Phase 200-C: Clear fn_body_ast after function lowering
self.comp_ctx.fn_body_ast = None;
Ok(())
}
}