refactor(builder): Phase 3-B,C完了 - 読みやすさ革命達成!
箱理論の完全実践:Call系処理を9個の専用箱で完全分離 - Phase 3-B: EffectsAnalyzerBox(エフェクト解析専用) - Phase 3-C: CallMaterializerBox(Call前処理専用) 実装内容: 【Phase 3-B: EffectsAnalyzerBox】 1. 新規ファイル作成 - src/mir/builder/calls/effects_analyzer.rs (~155行) - compute_call_effects: Calleeから副作用マスクを計算 - is_pure_method: Pureメソッド判定 - 5つのユニットテスト ✅ 2. call_unified.rs整理 - compute_call_effects → 委譲に変更 - is_pure_method → 削除 - ~50行削減 【Phase 3-C: CallMaterializerBox】 1. 新規ファイル作成 - src/mir/builder/calls/materializer.rs (~151行) - try_global_fallback_handlers: Global関数フォールバック - materialize_receiver_in_callee: Receiver実体化 - Call前処理全般を集約 2. emit.rs整理 - 2つの大きな関数を委譲に変更 - ~115行削減 3. unified_emitter.rs更新 - CallMaterializerBox経由に変更 箱化効果(Phase 3全体): 【劇的な削減】 - emit.rs: 467行 → 164行(-303行、65%削減!) - call_unified.rs: 144行 → 98行(-46行、32%削減!) 【新規箱(責務明確・読みやすい)】 - unified_emitter.rs: 250行(統一Call発行専用) - effects_analyzer.rs: 155行(エフェクト解析専用) - materializer.rs: 151行(Call前処理専用) 【読みやすさ革命】 - ✅ 500行超えファイル根絶(最大489行まで) - ✅ 責務分離完璧(各ファイルが単一責務) - ✅ 9個の専用箱で管理(guard/resolver/emitter/effects/materializer) - ✅ テスト容易性劇的向上(独立した箱で簡単テスト) Phase 3 最終状態: - Phase 3-A: UnifiedCallEmitterBox ✅ - Phase 3-B: EffectsAnalyzerBox ✅ - Phase 3-C: CallMaterializerBox ✅ - 読みやすさ革命 ✅ 完全達成! ビルド・テスト: - cargo build --release: ✅ 成功 - effects_analyzer tests (5): ✅ all passed - 既存機能互換性: ✅ 完全保持
This commit is contained in:
@ -59,56 +59,10 @@ pub fn classify_box_kind(box_name: &str) -> crate::mir::definitions::call_unifie
|
||||
// This function is kept for reference but should not be used.
|
||||
// Use CalleeResolverBox instead for all callee resolution.
|
||||
|
||||
/// Compute effects for a call based on its callee
|
||||
// DEPRECATED: Moved to EffectsAnalyzerBox in effects_analyzer.rs
|
||||
// Use EffectsAnalyzerBox::compute_call_effects() instead.
|
||||
pub fn compute_call_effects(callee: &Callee) -> EffectMask {
|
||||
match callee {
|
||||
Callee::Global(name) => {
|
||||
match name.as_str() {
|
||||
"print" | "error" => EffectMask::IO,
|
||||
"panic" | "exit" => EffectMask::IO.add(Effect::Control),
|
||||
"gc_collect" => EffectMask::IO.add(Effect::Alloc),
|
||||
_ => EffectMask::IO,
|
||||
}
|
||||
},
|
||||
|
||||
Callee::Method { method, box_name, .. } => {
|
||||
match method.as_str() {
|
||||
"birth" => EffectMask::PURE.add(Effect::Alloc),
|
||||
"get" | "length" | "size" => EffectMask::READ,
|
||||
"set" | "push" | "pop" => EffectMask::READ.add(Effect::WriteHeap),
|
||||
_ => {
|
||||
// Check if it's a known pure method
|
||||
if is_pure_method(box_name, method) {
|
||||
EffectMask::PURE
|
||||
} else {
|
||||
EffectMask::READ
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Callee::Constructor { .. } => EffectMask::PURE.add(Effect::Alloc),
|
||||
|
||||
Callee::Closure { .. } => EffectMask::PURE.add(Effect::Alloc),
|
||||
|
||||
Callee::Extern(name) => {
|
||||
let (iface, method) = extern_calls::parse_extern_name(name);
|
||||
extern_calls::compute_extern_effects(&iface, &method)
|
||||
},
|
||||
|
||||
Callee::Value(_) => EffectMask::IO, // Conservative for dynamic calls
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a method is known to be pure (no side effects)
|
||||
fn is_pure_method(box_name: &str, method: &str) -> bool {
|
||||
match (box_name, method) {
|
||||
("StringBox", m) => matches!(m, "upper" | "lower" | "trim" | "length"),
|
||||
("IntegerBox", m) => matches!(m, "abs" | "toString"),
|
||||
("FloatBox", m) => matches!(m, "round" | "floor" | "ceil"),
|
||||
("BoolBox", "not") => true,
|
||||
_ => false,
|
||||
}
|
||||
super::effects_analyzer::EffectsAnalyzerBox::compute_call_effects(callee)
|
||||
}
|
||||
|
||||
/// Create CallFlags based on callee type
|
||||
|
||||
156
src/mir/builder/calls/effects_analyzer.rs
Normal file
156
src/mir/builder/calls/effects_analyzer.rs
Normal file
@ -0,0 +1,156 @@
|
||||
/*!
|
||||
* EffectsAnalyzerBox - エフェクト解析専用箱
|
||||
*
|
||||
* 箱理論の実践:
|
||||
* - 箱にする: エフェクト解析ロジックを1箱に集約
|
||||
* - 境界を作る: Pure/IO/Alloc/Control等の効果分類を一元管理
|
||||
* - 状態レス: すべて静的解析(実行時状態不要)
|
||||
*
|
||||
* 責務:
|
||||
* - compute_call_effects: Calleeから副作用マスクを計算
|
||||
* - is_pure_method: メソッドがPure(副作用なし)か判定
|
||||
* - 既知の関数・メソッドのエフェクト知識を集約
|
||||
*/
|
||||
|
||||
use crate::mir::definitions::call_unified::Callee;
|
||||
use crate::mir::builder::{Effect, EffectMask};
|
||||
use super::extern_calls;
|
||||
|
||||
/// エフェクト解析専用箱
|
||||
///
|
||||
/// 箱理論:
|
||||
/// - 単一責務: Calleeのエフェクト解析のみ
|
||||
/// - 状態レス: すべて静的関数(Callee情報のみで判定)
|
||||
/// - 知識集約: 既知の関数・メソッドのエフェクト知識を一元管理
|
||||
pub struct EffectsAnalyzerBox;
|
||||
|
||||
impl EffectsAnalyzerBox {
|
||||
/// Compute effects for a call based on its callee
|
||||
///
|
||||
/// エフェクト分類:
|
||||
/// - PURE: 副作用なし(純粋計算)
|
||||
/// - READ: ヒープ読み取りのみ
|
||||
/// - IO: 入出力あり
|
||||
/// - Alloc: メモリ確保
|
||||
/// - Control: 制御フロー変更(panic/exit)
|
||||
/// - WriteHeap: ヒープ書き込み
|
||||
pub fn compute_call_effects(callee: &Callee) -> EffectMask {
|
||||
match callee {
|
||||
Callee::Global(name) => {
|
||||
match name.as_str() {
|
||||
"print" | "error" => EffectMask::IO,
|
||||
"panic" | "exit" => EffectMask::IO.add(Effect::Control),
|
||||
"gc_collect" => EffectMask::IO.add(Effect::Alloc),
|
||||
_ => EffectMask::IO,
|
||||
}
|
||||
},
|
||||
|
||||
Callee::Method { method, box_name, .. } => {
|
||||
match method.as_str() {
|
||||
"birth" => EffectMask::PURE.add(Effect::Alloc),
|
||||
"get" | "length" | "size" => EffectMask::READ,
|
||||
"set" | "push" | "pop" => EffectMask::READ.add(Effect::WriteHeap),
|
||||
_ => {
|
||||
// Check if it's a known pure method
|
||||
if Self::is_pure_method(box_name, method) {
|
||||
EffectMask::PURE
|
||||
} else {
|
||||
EffectMask::READ
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Callee::Constructor { .. } => EffectMask::PURE.add(Effect::Alloc),
|
||||
|
||||
Callee::Closure { .. } => EffectMask::PURE.add(Effect::Alloc),
|
||||
|
||||
Callee::Extern(name) => {
|
||||
let (iface, method) = extern_calls::parse_extern_name(name);
|
||||
extern_calls::compute_extern_effects(&iface, &method)
|
||||
},
|
||||
|
||||
Callee::Value(_) => EffectMask::IO, // Conservative for dynamic calls
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a method is known to be pure (no side effects)
|
||||
///
|
||||
/// Pure メソッドの条件:
|
||||
/// - 副作用なし(ヒープ変更なし、I/Oなし)
|
||||
/// - 同じ入力に対して同じ出力を返す
|
||||
/// - プログラムの状態を変更しない
|
||||
///
|
||||
/// 既知のPureメソッド:
|
||||
/// - StringBox: upper, lower, trim, length
|
||||
/// - IntegerBox: abs, toString
|
||||
/// - FloatBox: round, floor, ceil
|
||||
/// - BoolBox: not
|
||||
pub fn is_pure_method(box_name: &str, method: &str) -> bool {
|
||||
match (box_name, method) {
|
||||
("StringBox", m) => matches!(m, "upper" | "lower" | "trim" | "length"),
|
||||
("IntegerBox", m) => matches!(m, "abs" | "toString"),
|
||||
("FloatBox", m) => matches!(m, "round" | "floor" | "ceil"),
|
||||
("BoolBox", "not") => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mir::ValueId;
|
||||
use crate::mir::definitions::call_unified::{CalleeBoxKind, TypeCertainty};
|
||||
|
||||
#[test]
|
||||
fn test_compute_effects_global() {
|
||||
let callee = Callee::Global("print".to_string());
|
||||
let effects = EffectsAnalyzerBox::compute_call_effects(&callee);
|
||||
assert_eq!(effects, EffectMask::IO);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compute_effects_method_pure() {
|
||||
let callee = Callee::Method {
|
||||
box_name: "StringBox".to_string(),
|
||||
method: "upper".to_string(),
|
||||
receiver: Some(ValueId::new(1)),
|
||||
certainty: TypeCertainty::Known,
|
||||
box_kind: CalleeBoxKind::RuntimeData,
|
||||
};
|
||||
let effects = EffectsAnalyzerBox::compute_call_effects(&callee);
|
||||
assert_eq!(effects, EffectMask::PURE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compute_effects_method_read() {
|
||||
let callee = Callee::Method {
|
||||
box_name: "ArrayBox".to_string(),
|
||||
method: "get".to_string(),
|
||||
receiver: Some(ValueId::new(1)),
|
||||
certainty: TypeCertainty::Known,
|
||||
box_kind: CalleeBoxKind::RuntimeData,
|
||||
};
|
||||
let effects = EffectsAnalyzerBox::compute_call_effects(&callee);
|
||||
assert_eq!(effects, EffectMask::READ);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compute_effects_constructor() {
|
||||
let callee = Callee::Constructor {
|
||||
box_type: "StringBox".to_string(),
|
||||
};
|
||||
let effects = EffectsAnalyzerBox::compute_call_effects(&callee);
|
||||
// Constructor should have PURE + Alloc
|
||||
assert_eq!(effects, EffectMask::PURE.add(crate::mir::builder::Effect::Alloc));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_pure_method() {
|
||||
assert!(EffectsAnalyzerBox::is_pure_method("StringBox", "upper"));
|
||||
assert!(EffectsAnalyzerBox::is_pure_method("IntegerBox", "abs"));
|
||||
assert!(EffectsAnalyzerBox::is_pure_method("BoolBox", "not"));
|
||||
assert!(!EffectsAnalyzerBox::is_pure_method("ArrayBox", "push"));
|
||||
}
|
||||
}
|
||||
@ -138,119 +138,22 @@ impl MirBuilder {
|
||||
// Private helper methods (small functions)
|
||||
// ========================================
|
||||
|
||||
/// Try fallback handlers for global functions
|
||||
/// Try fallback handlers for global functions (delegates to CallMaterializerBox)
|
||||
pub(super) fn try_global_fallback_handlers(
|
||||
&mut self,
|
||||
dst: Option<ValueId>,
|
||||
name: &str,
|
||||
args: &[ValueId],
|
||||
) -> Result<Option<()>, String> {
|
||||
// 0) Dev-only safety: treat condition_fn as always-true predicate when missing
|
||||
if name == "condition_fn" {
|
||||
let dstv = dst.unwrap_or_else(|| self.next_value_id());
|
||||
// Emit integer constant via ConstantEmissionBox
|
||||
let one = crate::mir::builder::emission::constant::emit_integer(self, 1);
|
||||
if dst.is_none() {
|
||||
// If a destination was not provided, copy into the allocated dstv
|
||||
self.emit_instruction(MirInstruction::Copy { dst: dstv, src: one })?;
|
||||
crate::mir::builder::metadata::propagate::propagate(self, one, dstv);
|
||||
} else {
|
||||
// If caller provided dst, ensure the computed value lands there
|
||||
self.emit_instruction(MirInstruction::Copy { dst: dstv, src: one })?;
|
||||
crate::mir::builder::metadata::propagate::propagate(self, one, dstv);
|
||||
}
|
||||
return Ok(Some(()));
|
||||
}
|
||||
|
||||
// 1) Direct module function fallback: call by name if present
|
||||
if let Some(ref module) = self.current_module {
|
||||
if module.functions.contains_key(name) {
|
||||
let dstv = dst.unwrap_or_else(|| self.next_value_id());
|
||||
let name_const = crate::mir::builder::name_const::make_name_const_result(self, name)?;
|
||||
self.emit_instruction(MirInstruction::Call {
|
||||
dst: Some(dstv),
|
||||
func: name_const,
|
||||
callee: Some(Callee::Global(name.to_string())),
|
||||
args: args.to_vec(),
|
||||
effects: EffectMask::IO,
|
||||
})?;
|
||||
self.annotate_call_result_from_func_name(dstv, name);
|
||||
return Ok(Some(()));
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Unique static-method fallback: name+arity → Box.name/Arity
|
||||
if let Some(cands) = self.static_method_index.get(name) {
|
||||
let mut matches: Vec<(String, usize)> = cands
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|(_, ar)| *ar == args.len())
|
||||
.collect();
|
||||
if matches.len() == 1 {
|
||||
let (bx, _arity) = matches.remove(0);
|
||||
let func_name = format!("{}.{}{}", bx, name, format!("/{}", args.len()));
|
||||
// Emit legacy call directly to preserve behavior
|
||||
let dstv = dst.unwrap_or_else(|| self.next_value_id());
|
||||
let name_const = crate::mir::builder::name_const::make_name_const_result(self, &func_name)?;
|
||||
self.emit_instruction(MirInstruction::Call {
|
||||
dst: Some(dstv),
|
||||
func: name_const,
|
||||
callee: Some(Callee::Global(func_name.clone())),
|
||||
args: args.to_vec(),
|
||||
effects: EffectMask::IO,
|
||||
})?;
|
||||
// annotate
|
||||
self.annotate_call_result_from_func_name(dstv, func_name);
|
||||
return Ok(Some(()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
super::materializer::CallMaterializerBox::try_global_fallback_handlers(self, dst, name, args)
|
||||
}
|
||||
|
||||
/// Ensure receiver is materialized in Callee::Method (pub for UnifiedCallEmitterBox)
|
||||
/// Ensure receiver is materialized in Callee::Method (delegates to CallMaterializerBox)
|
||||
pub(super) fn materialize_receiver_in_callee(
|
||||
&mut self,
|
||||
callee: Callee,
|
||||
) -> Result<Callee, String> {
|
||||
match callee {
|
||||
Callee::Method { box_name, method, receiver: Some(r), certainty, box_kind } => {
|
||||
if std::env::var("NYASH_BUILDER_TRACE_RECV").ok().as_deref() == Some("1") {
|
||||
let current_fn = self
|
||||
.current_function
|
||||
.as_ref()
|
||||
.map(|f| f.signature.name.clone())
|
||||
.unwrap_or_else(|| "<none>".to_string());
|
||||
let bb = self.current_block;
|
||||
let names: Vec<String> = self
|
||||
.variable_map
|
||||
.iter()
|
||||
.filter(|(_, &vid)| vid == r)
|
||||
.map(|(k, _)| k.clone())
|
||||
.collect();
|
||||
// CRITICAL DEBUG: Show type information sources
|
||||
let origin = self.value_origin_newbox.get(&r).cloned();
|
||||
let vtype = self.value_types.get(&r).cloned();
|
||||
eprintln!(
|
||||
"[builder/recv-trace] fn={} bb={:?} method={}.{} recv=%{} aliases={:?}",
|
||||
current_fn,
|
||||
bb,
|
||||
box_name.clone(),
|
||||
method,
|
||||
r.0,
|
||||
names
|
||||
);
|
||||
eprintln!(
|
||||
"[builder/recv-trace] value_origin_newbox: {:?}, value_types: {:?}",
|
||||
origin, vtype
|
||||
);
|
||||
}
|
||||
// Prefer pinning to a slot so start_new_block can propagate it across entries.
|
||||
let r_pinned = self.pin_to_slot(r, "@recv").unwrap_or(r);
|
||||
Ok(Callee::Method { box_name, method, receiver: Some(r_pinned), certainty, box_kind })
|
||||
}
|
||||
other => Ok(other),
|
||||
}
|
||||
super::materializer::CallMaterializerBox::materialize_receiver_in_callee(self, callee)
|
||||
}
|
||||
|
||||
// ✅ 箱化完了:
|
||||
|
||||
151
src/mir/builder/calls/materializer.rs
Normal file
151
src/mir/builder/calls/materializer.rs
Normal file
@ -0,0 +1,151 @@
|
||||
/*!
|
||||
* CallMaterializerBox - Call前処理・準備専用箱
|
||||
*
|
||||
* 箱理論の実践:
|
||||
* - 箱にする: Call発行前の前処理を1箱に集約
|
||||
* - 境界を作る: フォールバック処理・receiver実体化を分離
|
||||
* - 状態最小: MirBuilderを引数として受け取る(所有しない)
|
||||
*
|
||||
* 責務:
|
||||
* - try_global_fallback_handlers: Global関数のフォールバック処理
|
||||
* - materialize_receiver_in_callee: Receiverの実体化(pinning)
|
||||
* - Call発行前の準備処理全般
|
||||
*/
|
||||
|
||||
use crate::mir::builder::{MirBuilder, ValueId, MirInstruction, EffectMask};
|
||||
use crate::mir::definitions::call_unified::Callee;
|
||||
|
||||
/// Call前処理・準備専用箱
|
||||
///
|
||||
/// 箱理論:
|
||||
/// - 単一責務: Call発行前の前処理のみ
|
||||
/// - 状態レス: MirBuilderを引数で受け取る設計
|
||||
/// - サポート役: 本体のCall発行をサポートする役割
|
||||
pub struct CallMaterializerBox;
|
||||
|
||||
impl CallMaterializerBox {
|
||||
/// Try fallback handlers for global functions
|
||||
///
|
||||
/// フォールバック処理の優先順位:
|
||||
/// 1. Dev-only safety: condition_fn → always-true predicate
|
||||
/// 2. Direct module function: module内の関数を直接呼び出し
|
||||
/// 3. Unique static-method: name+arity → Box.name/Arity へ変換
|
||||
pub fn try_global_fallback_handlers(
|
||||
builder: &mut MirBuilder,
|
||||
dst: Option<ValueId>,
|
||||
name: &str,
|
||||
args: &[ValueId],
|
||||
) -> Result<Option<()>, String> {
|
||||
// 0) Dev-only safety: treat condition_fn as always-true predicate when missing
|
||||
if name == "condition_fn" {
|
||||
let dstv = dst.unwrap_or_else(|| builder.next_value_id());
|
||||
// Emit integer constant via ConstantEmissionBox
|
||||
let one = crate::mir::builder::emission::constant::emit_integer(builder, 1);
|
||||
if dst.is_none() {
|
||||
// If a destination was not provided, copy into the allocated dstv
|
||||
builder.emit_instruction(MirInstruction::Copy { dst: dstv, src: one })?;
|
||||
crate::mir::builder::metadata::propagate::propagate(builder, one, dstv);
|
||||
} else {
|
||||
// If caller provided dst, ensure the computed value lands there
|
||||
builder.emit_instruction(MirInstruction::Copy { dst: dstv, src: one })?;
|
||||
crate::mir::builder::metadata::propagate::propagate(builder, one, dstv);
|
||||
}
|
||||
return Ok(Some(()));
|
||||
}
|
||||
|
||||
// 1) Direct module function fallback: call by name if present
|
||||
if let Some(ref module) = builder.current_module {
|
||||
if module.functions.contains_key(name) {
|
||||
let dstv = dst.unwrap_or_else(|| builder.next_value_id());
|
||||
let name_const = crate::mir::builder::name_const::make_name_const_result(builder, name)?;
|
||||
builder.emit_instruction(MirInstruction::Call {
|
||||
dst: Some(dstv),
|
||||
func: name_const,
|
||||
callee: Some(Callee::Global(name.to_string())),
|
||||
args: args.to_vec(),
|
||||
effects: EffectMask::IO,
|
||||
})?;
|
||||
builder.annotate_call_result_from_func_name(dstv, name);
|
||||
return Ok(Some(()));
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Unique static-method fallback: name+arity → Box.name/Arity
|
||||
if let Some(cands) = builder.static_method_index.get(name) {
|
||||
let mut matches: Vec<(String, usize)> = cands
|
||||
.iter()
|
||||
.cloned()
|
||||
.filter(|(_, ar)| *ar == args.len())
|
||||
.collect();
|
||||
if matches.len() == 1 {
|
||||
let (bx, _arity) = matches.remove(0);
|
||||
let func_name = format!("{}.{}{}", bx, name, format!("/{}", args.len()));
|
||||
// Emit legacy call directly to preserve behavior
|
||||
let dstv = dst.unwrap_or_else(|| builder.next_value_id());
|
||||
let name_const = crate::mir::builder::name_const::make_name_const_result(builder, &func_name)?;
|
||||
builder.emit_instruction(MirInstruction::Call {
|
||||
dst: Some(dstv),
|
||||
func: name_const,
|
||||
callee: Some(Callee::Global(func_name.clone())),
|
||||
args: args.to_vec(),
|
||||
effects: EffectMask::IO,
|
||||
})?;
|
||||
// annotate
|
||||
builder.annotate_call_result_from_func_name(dstv, func_name);
|
||||
return Ok(Some(()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Ensure receiver is materialized in Callee::Method
|
||||
///
|
||||
/// Receiver実体化の目的:
|
||||
/// - receiverをスロットにpinningして、start_new_blockで伝播可能に
|
||||
/// - SSA不変条件の保持(receiverが常に定義済みであることを保証)
|
||||
/// - デバッグトレース出力(NYASH_BUILDER_TRACE_RECV=1)
|
||||
pub fn materialize_receiver_in_callee(
|
||||
builder: &mut MirBuilder,
|
||||
callee: Callee,
|
||||
) -> Result<Callee, String> {
|
||||
match callee {
|
||||
Callee::Method { box_name, method, receiver: Some(r), certainty, box_kind } => {
|
||||
if std::env::var("NYASH_BUILDER_TRACE_RECV").ok().as_deref() == Some("1") {
|
||||
let current_fn = builder
|
||||
.current_function
|
||||
.as_ref()
|
||||
.map(|f| f.signature.name.clone())
|
||||
.unwrap_or_else(|| "<none>".to_string());
|
||||
let bb = builder.current_block;
|
||||
let names: Vec<String> = builder
|
||||
.variable_map
|
||||
.iter()
|
||||
.filter(|(_, &vid)| vid == r)
|
||||
.map(|(k, _)| k.clone())
|
||||
.collect();
|
||||
// CRITICAL DEBUG: Show type information sources
|
||||
let origin = builder.value_origin_newbox.get(&r).cloned();
|
||||
let vtype = builder.value_types.get(&r).cloned();
|
||||
eprintln!(
|
||||
"[builder/recv-trace] fn={} bb={:?} method={}.{} recv=%{} aliases={:?}",
|
||||
current_fn,
|
||||
bb,
|
||||
box_name.clone(),
|
||||
method,
|
||||
r.0,
|
||||
names
|
||||
);
|
||||
eprintln!(
|
||||
"[builder/recv-trace] value_origin_newbox: {:?}, value_types: {:?}",
|
||||
origin, vtype
|
||||
);
|
||||
}
|
||||
// Prefer pinning to a slot so start_new_block can propagate it across entries.
|
||||
let r_pinned = builder.pin_to_slot(r, "@recv").unwrap_or(r);
|
||||
Ok(Callee::Method { box_name, method, receiver: Some(r_pinned), certainty, box_kind })
|
||||
}
|
||||
other => Ok(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -19,11 +19,13 @@ pub mod special_handlers;
|
||||
// New refactored modules (Box Theory Phase 1 & 2 & 25.1d & Phase 3)
|
||||
pub mod lowering;
|
||||
pub mod utils;
|
||||
pub mod emit; // Phase 2: Call emission
|
||||
pub mod build; // Phase 2: Call building
|
||||
pub mod guard; // Phase 25.1d: Structural guard (static/runtime box separation)
|
||||
pub mod resolver; // Phase 25.1d: Callee resolution (CallTarget → Callee)
|
||||
pub mod unified_emitter; // Phase 3-A: Unified call emitter (統一Call発行専用箱)
|
||||
pub mod emit; // Phase 2: Call emission
|
||||
pub mod build; // Phase 2: Call building
|
||||
pub mod guard; // Phase 25.1d: Structural guard (static/runtime box separation)
|
||||
pub mod resolver; // Phase 25.1d: Callee resolution (CallTarget → Callee)
|
||||
pub mod unified_emitter; // Phase 3-A: Unified call emitter (統一Call発行専用箱)
|
||||
pub mod effects_analyzer; // Phase 3-B: Effects analyzer (エフェクト解析専用箱)
|
||||
pub mod materializer; // Phase 3-C: Call materializer (Call前処理・準備専用箱)
|
||||
|
||||
// Re-export public interfaces
|
||||
pub use call_target::CallTarget;
|
||||
|
||||
@ -111,8 +111,8 @@ impl UnifiedCallEmitterBox {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
if let CallTarget::Global(ref name) = target {
|
||||
// Try fallback handlers
|
||||
if let Some(result) = builder.try_global_fallback_handlers(dst, name, &args)? {
|
||||
// Try fallback handlers (via CallMaterializerBox)
|
||||
if let Some(result) = super::materializer::CallMaterializerBox::try_global_fallback_handlers(builder, dst, name, &args)? {
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
@ -120,8 +120,8 @@ impl UnifiedCallEmitterBox {
|
||||
}
|
||||
};
|
||||
|
||||
// Safety: ensure receiver is materialized even after callee conversion
|
||||
callee = builder.materialize_receiver_in_callee(callee)?;
|
||||
// Safety: ensure receiver is materialized even after callee conversion (via CallMaterializerBox)
|
||||
callee = super::materializer::CallMaterializerBox::materialize_receiver_in_callee(builder, callee)?;
|
||||
|
||||
// Structural guard: prevent static compiler boxes from being called with runtime receivers
|
||||
// 箱理論: CalleeGuardBox による構造的分離
|
||||
|
||||
Reference in New Issue
Block a user