chore: Phase 25.1 完了 - LoopForm v2/Stage1 CLI/環境変数削減 + Phase 26-D からの変更
Phase 25.1 完了成果: - ✅ LoopForm v2 テスト・ドキュメント・コメント完備 - 4ケース(A/B/C/D)完全テストカバレッジ - 最小再現ケース作成(SSAバグ調査用) - SSOT文書作成(loopform_ssot.md) - 全ソースに [LoopForm] コメントタグ追加 - ✅ Stage-1 CLI デバッグ環境構築 - stage1_cli.hako 実装 - stage1_bridge.rs ブリッジ実装 - デバッグツール作成(stage1_debug.sh/stage1_minimal.sh) - アーキテクチャ改善提案文書 - ✅ 環境変数削減計画策定 - 25変数の完全調査・分類 - 6段階削減ロードマップ(25→5、80%削減) - 即時削除可能変数特定(NYASH_CONFIG/NYASH_DEBUG) Phase 26-D からの累積変更: - PHI実装改善(ExitPhiBuilder/HeaderPhiBuilder等) - MIRビルダーリファクタリング - 型伝播・最適化パス改善 - その他約300ファイルの累積変更 🎯 技術的成果: - SSAバグ根本原因特定(条件分岐内loop変数変更) - Region+next_iパターン適用完了(UsingCollectorBox等) - LoopFormパターン文書化・テスト化完了 - セルフホスティング基盤強化 Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: ChatGPT <noreply@openai.com> Co-Authored-By: Task Assistant <task@anthropic.com>
This commit is contained in:
@ -9,50 +9,50 @@ use super::{
|
||||
BasicBlock, BasicBlockId, BasicBlockIdGenerator, CompareOp, ConstValue, Effect, EffectMask,
|
||||
FunctionSignature, MirFunction, MirInstruction, MirModule, MirType, ValueId, ValueIdGenerator,
|
||||
};
|
||||
use crate::mir::region::function_slot_registry::FunctionSlotRegistry;
|
||||
use crate::mir::region::RegionId;
|
||||
use crate::ast::{ASTNode, LiteralValue};
|
||||
use crate::mir::builder::builder_calls::CallTarget;
|
||||
use crate::mir::region::function_slot_registry::FunctionSlotRegistry;
|
||||
use crate::mir::region::RegionId;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
mod calls; // Call system modules (refactored from builder_calls)
|
||||
mod builder_calls;
|
||||
mod call_resolution; // ChatGPT5 Pro: Type-safe call resolution utilities
|
||||
mod calls; // Call system modules (refactored from builder_calls)
|
||||
mod context; // BoxCompilationContext - 箱理論による静的Boxコンパイル時のコンテキスト分離
|
||||
mod method_call_handlers; // Method call handler separation (Phase 3)
|
||||
mod decls; // declarations lowering split
|
||||
mod exprs; // expression lowering split
|
||||
mod exprs_call; // call(expr)
|
||||
// include lowering removed (using is handled in runner)
|
||||
mod exprs_call;
|
||||
mod method_call_handlers; // Method call handler separation (Phase 3) // call(expr)
|
||||
// include lowering removed (using is handled in runner)
|
||||
mod control_flow; // thin wrappers to centralize control-flow entrypoints
|
||||
mod exprs_lambda; // lambda lowering
|
||||
mod exprs_peek; // peek expression
|
||||
mod exprs_qmark; // ?-propagate
|
||||
mod fields; // field access/assignment lowering split
|
||||
mod if_form;
|
||||
mod lifecycle;
|
||||
pub(crate) mod loops;
|
||||
mod ops;
|
||||
mod phi;
|
||||
mod phi_merge; // Phase 25.1q: Unified PHI merge helper
|
||||
mod if_form;
|
||||
mod control_flow; // thin wrappers to centralize control-flow entrypoints
|
||||
mod lifecycle; // prepare/lower_root/finalize split
|
||||
// legacy large-match remains inline for now (planned extraction)
|
||||
mod plugin_sigs; // plugin signature loader
|
||||
mod stmts;
|
||||
mod utils;
|
||||
mod vars; // variables/scope helpers // small loop helpers (header/exit context)
|
||||
mod origin; // P0: origin inference(me/Known)と PHI 伝播(軽量)
|
||||
mod observe; // P0: dev-only observability helpers(ssa/resolve)
|
||||
mod rewrite; // P1: Known rewrite & special consolidation
|
||||
mod ssa; // LocalSSA helpers (in-block materialization)
|
||||
mod schedule; // BlockScheduleBox(物理順序: PHI→materialize→body)
|
||||
mod receiver; // ReceiverMaterializationBox(Method recv の pin+LocalSSA 集約)
|
||||
mod metadata; // MetadataPropagationBox(type/originの伝播)
|
||||
mod emission; // emission::*(Const/Compare/Branch の薄い発行箱)
|
||||
mod types; // types::annotation / inference(型注釈/推論の箱: 推論は後段)
|
||||
mod router; // RouterPolicyBox(Unified vs BoxCall)
|
||||
mod phi_merge; // Phase 25.1q: Unified PHI merge helper // prepare/lower_root/finalize split
|
||||
// legacy large-match remains inline for now (planned extraction)
|
||||
mod emission; // emission::*(Const/Compare/Branch の薄い発行箱)
|
||||
mod emit_guard; // EmitGuardBox(emit直前の最終関所)
|
||||
mod metadata; // MetadataPropagationBox(type/originの伝播)
|
||||
mod name_const; // NameConstBox(関数名Const生成)
|
||||
pub(crate) mod type_registry; // TypeRegistryBox(型情報管理の一元化)
|
||||
mod observe; // P0: dev-only observability helpers(ssa/resolve)
|
||||
mod origin; // P0: origin inference(me/Known)と PHI 伝播(軽量)
|
||||
mod plugin_sigs; // plugin signature loader
|
||||
mod receiver; // ReceiverMaterializationBox(Method recv の pin+LocalSSA 集約)
|
||||
mod rewrite; // P1: Known rewrite & special consolidation
|
||||
mod router; // RouterPolicyBox(Unified vs BoxCall)
|
||||
mod schedule; // BlockScheduleBox(物理順序: PHI→materialize→body)
|
||||
mod ssa; // LocalSSA helpers (in-block materialization)
|
||||
mod stmts;
|
||||
pub(crate) mod type_registry;
|
||||
mod types; // types::annotation / inference(型注釈/推論の箱: 推論は後段)
|
||||
mod utils;
|
||||
mod vars; // variables/scope helpers // small loop helpers (header/exit context) // TypeRegistryBox(型情報管理の一元化)
|
||||
|
||||
// Unified member property kinds for computed/once/birth_once
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
@ -62,7 +62,6 @@ pub(crate) enum PropertyKind {
|
||||
BirthOnce,
|
||||
}
|
||||
|
||||
|
||||
/// MIR builder for converting AST to SSA form
|
||||
pub struct MirBuilder {
|
||||
/// Current module being built
|
||||
@ -152,7 +151,6 @@ pub struct MirBuilder {
|
||||
pub(super) current_region_stack: Vec<RegionId>,
|
||||
|
||||
// include guards removed
|
||||
|
||||
/// Loop context stacks for lowering break/continue inside nested control flow
|
||||
/// Top of stack corresponds to the innermost active loop
|
||||
pub(super) loop_header_stack: Vec<BasicBlockId>,
|
||||
@ -288,19 +286,31 @@ impl MirBuilder {
|
||||
}
|
||||
|
||||
/// Push/pop helpers for If merge context (best-effort; optional usage)
|
||||
pub(super) fn push_if_merge(&mut self, bb: BasicBlockId) { self.if_merge_stack.push(bb); }
|
||||
pub(super) fn pop_if_merge(&mut self) { let _ = self.if_merge_stack.pop(); }
|
||||
pub(super) fn push_if_merge(&mut self, bb: BasicBlockId) {
|
||||
self.if_merge_stack.push(bb);
|
||||
}
|
||||
pub(super) fn pop_if_merge(&mut self) {
|
||||
let _ = self.if_merge_stack.pop();
|
||||
}
|
||||
|
||||
/// Suppress entry pin copy for the next start_new_block (used for merge blocks).
|
||||
pub(super) fn suppress_next_entry_pin_copy(&mut self) { self.suppress_pin_entry_copy_next = true; }
|
||||
pub(super) fn suppress_next_entry_pin_copy(&mut self) {
|
||||
self.suppress_pin_entry_copy_next = true;
|
||||
}
|
||||
|
||||
// ---- Hint helpers (no-op by default) ----
|
||||
#[inline]
|
||||
pub(crate) fn hint_scope_enter(&mut self, id: u32) { self.hint_sink.scope_enter(id); }
|
||||
pub(crate) fn hint_scope_enter(&mut self, id: u32) {
|
||||
self.hint_sink.scope_enter(id);
|
||||
}
|
||||
#[inline]
|
||||
pub(crate) fn hint_scope_leave(&mut self, id: u32) { self.hint_sink.scope_leave(id); }
|
||||
pub(crate) fn hint_scope_leave(&mut self, id: u32) {
|
||||
self.hint_sink.scope_leave(id);
|
||||
}
|
||||
#[inline]
|
||||
pub(crate) fn hint_join_result<S: Into<String>>(&mut self, var: S) { self.hint_sink.join_result(var.into()); }
|
||||
pub(crate) fn hint_join_result<S: Into<String>>(&mut self, var: S) {
|
||||
self.hint_sink.join_result(var.into());
|
||||
}
|
||||
|
||||
// ----------------------
|
||||
// Debug scope helpers (region_id for DebugHub events)
|
||||
@ -332,10 +342,7 @@ impl MirBuilder {
|
||||
// ----------------------
|
||||
#[inline]
|
||||
pub(super) fn compile_trace_enabled() -> bool {
|
||||
std::env::var("NYASH_MIR_COMPILE_TRACE")
|
||||
.ok()
|
||||
.as_deref()
|
||||
== Some("1")
|
||||
std::env::var("NYASH_MIR_COMPILE_TRACE").ok().as_deref() == Some("1")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -395,7 +402,6 @@ impl MirBuilder {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
|
||||
/// Build a complete MIR module from AST
|
||||
pub fn build_module(&mut self, ast: ASTNode) -> Result<MirModule, String> {
|
||||
self.prepare_module()?;
|
||||
@ -403,7 +409,6 @@ impl MirBuilder {
|
||||
self.finalize_module(result_value)
|
||||
}
|
||||
|
||||
|
||||
/// Build an expression and return its value ID
|
||||
pub(super) fn build_expression(&mut self, ast: ASTNode) -> Result<ValueId, String> {
|
||||
// Delegated to exprs.rs to keep this file lean
|
||||
@ -412,11 +417,17 @@ impl MirBuilder {
|
||||
self.recursion_depth += 1;
|
||||
if self.recursion_depth > MAX_RECURSION_DEPTH {
|
||||
eprintln!("\n[FATAL] ============================================");
|
||||
eprintln!("[FATAL] Recursion depth exceeded {} in build_expression", MAX_RECURSION_DEPTH);
|
||||
eprintln!(
|
||||
"[FATAL] Recursion depth exceeded {} in build_expression",
|
||||
MAX_RECURSION_DEPTH
|
||||
);
|
||||
eprintln!("[FATAL] Current depth: {}", self.recursion_depth);
|
||||
eprintln!("[FATAL] AST node type: {:?}", std::mem::discriminant(&ast));
|
||||
eprintln!("[FATAL] ============================================\n");
|
||||
return Err(format!("Recursion depth exceeded: {} (possible infinite loop)", self.recursion_depth));
|
||||
return Err(format!(
|
||||
"Recursion depth exceeded: {} (possible infinite loop)",
|
||||
self.recursion_depth
|
||||
));
|
||||
}
|
||||
|
||||
let result = self.build_expression_impl(ast);
|
||||
@ -424,7 +435,6 @@ impl MirBuilder {
|
||||
result
|
||||
}
|
||||
|
||||
|
||||
/// Build a literal value
|
||||
pub(super) fn build_literal(&mut self, literal: LiteralValue) -> Result<ValueId, String> {
|
||||
// Determine type without moving literal
|
||||
@ -438,9 +448,13 @@ impl MirBuilder {
|
||||
|
||||
// Emit via ConstantEmissionBox(仕様不変の統一ルート)
|
||||
let dst = match literal {
|
||||
LiteralValue::Integer(n) => crate::mir::builder::emission::constant::emit_integer(self, n),
|
||||
LiteralValue::Integer(n) => {
|
||||
crate::mir::builder::emission::constant::emit_integer(self, n)
|
||||
}
|
||||
LiteralValue::Float(f) => crate::mir::builder::emission::constant::emit_float(self, f),
|
||||
LiteralValue::String(s) => crate::mir::builder::emission::constant::emit_string(self, s),
|
||||
LiteralValue::String(s) => {
|
||||
crate::mir::builder::emission::constant::emit_string(self, s)
|
||||
}
|
||||
LiteralValue::Bool(b) => crate::mir::builder::emission::constant::emit_bool(self, b),
|
||||
LiteralValue::Null => crate::mir::builder::emission::constant::emit_null(self),
|
||||
LiteralValue::Void => crate::mir::builder::emission::constant::emit_void(self),
|
||||
@ -453,7 +467,6 @@ impl MirBuilder {
|
||||
Ok(dst)
|
||||
}
|
||||
|
||||
|
||||
/// Build variable access
|
||||
pub(super) fn build_variable_access(&mut self, name: String) -> Result<ValueId, String> {
|
||||
// Step 5-5-G: __pin$ variables should NEVER be accessed from variable_map
|
||||
@ -478,7 +491,8 @@ impl MirBuilder {
|
||||
msg.push_str("\nHint: 'local' is a Stage-3 keyword. Enable NYASH_PARSER_STAGE3=1 (and HAKO_PARSER_STAGE3=1 for Stage-B).");
|
||||
msg.push_str("\nFor AotPrep verification, use tools/hakorune_emit_mir.sh which sets these automatically.");
|
||||
} else if (name == "flow" || name == "try" || name == "catch" || name == "throw")
|
||||
&& !crate::config::env::parser_stage3() {
|
||||
&& !crate::config::env::parser_stage3()
|
||||
{
|
||||
msg.push_str(&format!("\nHint: '{}' is a Stage-3 keyword. Enable NYASH_PARSER_STAGE3=1 (and HAKO_PARSER_STAGE3=1 for Stage-B).", name));
|
||||
}
|
||||
|
||||
@ -486,7 +500,9 @@ impl MirBuilder {
|
||||
if !suggest.is_empty() {
|
||||
msg.push_str("\nHint: symbol appears in using module(s): ");
|
||||
msg.push_str(&suggest.join(", "));
|
||||
msg.push_str("\nConsider adding 'using <module> [as Alias]' or check nyash.toml [using].");
|
||||
msg.push_str(
|
||||
"\nConsider adding 'using <module> [as Alias]' or check nyash.toml [using].",
|
||||
);
|
||||
}
|
||||
Err(msg)
|
||||
}
|
||||
@ -527,8 +543,6 @@ impl MirBuilder {
|
||||
Ok(value_id)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Emit an instruction to the current basic block
|
||||
pub(super) fn emit_instruction(&mut self, instruction: MirInstruction) -> Result<(), String> {
|
||||
let block_id = self.current_block.ok_or("No current basic block")?;
|
||||
@ -551,9 +565,23 @@ impl MirBuilder {
|
||||
// CRITICAL: Final receiver materialization for MethodCall
|
||||
// This ensures the receiver has an in-block definition in the same block as the Call.
|
||||
// Must happen BEFORE function mutable borrow to avoid borrowck conflicts.
|
||||
if let MirInstruction::Call { callee: Some(callee), dst, args, effects, .. } = &instruction {
|
||||
if let MirInstruction::Call {
|
||||
callee: Some(callee),
|
||||
dst,
|
||||
args,
|
||||
effects,
|
||||
..
|
||||
} = &instruction
|
||||
{
|
||||
use crate::mir::definitions::call_unified::Callee;
|
||||
if let Callee::Method { box_name, method, receiver: Some(r), certainty, box_kind } = callee.clone() {
|
||||
if let Callee::Method {
|
||||
box_name,
|
||||
method,
|
||||
receiver: Some(r),
|
||||
certainty,
|
||||
box_kind,
|
||||
} = callee.clone()
|
||||
{
|
||||
// LocalSSA: ensure receiver has a Copy in current_block
|
||||
let r_local = crate::mir::builder::ssa::local::recv(self, r);
|
||||
|
||||
@ -579,7 +607,9 @@ impl MirBuilder {
|
||||
// Pre-capture branch/jump targets for predecessor update after we finish
|
||||
// mutably borrowing the current block.
|
||||
let (then_t, else_t, jump_t) = match &instruction {
|
||||
MirInstruction::Branch { then_bb, else_bb, .. } => (Some(*then_bb), Some(*else_bb), None),
|
||||
MirInstruction::Branch {
|
||||
then_bb, else_bb, ..
|
||||
} => (Some(*then_bb), Some(*else_bb), None),
|
||||
MirInstruction::Jump { target } => (None, None, Some(*target)),
|
||||
_ => (None, None, None),
|
||||
};
|
||||
@ -607,7 +637,13 @@ impl MirBuilder {
|
||||
return Err("builder invariant violated: MirInstruction::Call.callee must be Some (unified call)".into());
|
||||
} else if std::env::var("NYASH_LOCAL_SSA_TRACE").ok().as_deref() == Some("1") {
|
||||
use crate::mir::definitions::call_unified::Callee;
|
||||
if let Some(Callee::Method { box_name, method, receiver: Some(r), .. }) = callee {
|
||||
if let Some(Callee::Method {
|
||||
box_name,
|
||||
method,
|
||||
receiver: Some(r),
|
||||
..
|
||||
}) = callee
|
||||
{
|
||||
eprintln!(
|
||||
"[emit-inst] fn={} bb={:?} Call {}.{} recv=%{}",
|
||||
current_fn_name,
|
||||
@ -617,9 +653,16 @@ impl MirBuilder {
|
||||
r.0
|
||||
);
|
||||
}
|
||||
} else if std::env::var("NYASH_BUILDER_TRACE_RECV").ok().as_deref() == Some("1") {
|
||||
} else if std::env::var("NYASH_BUILDER_TRACE_RECV").ok().as_deref() == Some("1")
|
||||
{
|
||||
use crate::mir::definitions::call_unified::Callee;
|
||||
if let Some(Callee::Method { box_name, method, receiver: Some(r), .. }) = callee {
|
||||
if let Some(Callee::Method {
|
||||
box_name,
|
||||
method,
|
||||
receiver: Some(r),
|
||||
..
|
||||
}) = callee
|
||||
{
|
||||
let names: Vec<String> = self
|
||||
.variable_map
|
||||
.iter()
|
||||
@ -688,18 +731,24 @@ impl MirBuilder {
|
||||
}
|
||||
block.add_instruction(instruction);
|
||||
// Drop the mutable borrow of `block` before updating other blocks
|
||||
}
|
||||
}
|
||||
// Update predecessor sets for branch/jump immediately so that
|
||||
// debug_verify_phi_inputs can observe a consistent CFG without
|
||||
// requiring a full function.update_cfg() pass.
|
||||
if let Some(t) = then_t {
|
||||
if let Some(succ) = function.get_block_mut(t) { succ.add_predecessor(block_id); }
|
||||
if let Some(succ) = function.get_block_mut(t) {
|
||||
succ.add_predecessor(block_id);
|
||||
}
|
||||
}
|
||||
if let Some(t) = else_t {
|
||||
if let Some(succ) = function.get_block_mut(t) { succ.add_predecessor(block_id); }
|
||||
if let Some(succ) = function.get_block_mut(t) {
|
||||
succ.add_predecessor(block_id);
|
||||
}
|
||||
}
|
||||
if let Some(t) = jump_t {
|
||||
if let Some(succ) = function.get_block_mut(t) { succ.add_predecessor(block_id); }
|
||||
if let Some(succ) = function.get_block_mut(t) {
|
||||
succ.add_predecessor(block_id);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
@ -726,7 +775,10 @@ impl MirBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(format!("PHI instruction {} not found in block {}", phi_id, block))
|
||||
Err(format!(
|
||||
"PHI instruction {} not found in block {}",
|
||||
phi_id, block
|
||||
))
|
||||
} else {
|
||||
Err(format!("Block {} not found", block))
|
||||
}
|
||||
@ -739,7 +791,6 @@ impl MirBuilder {
|
||||
|
||||
// フェーズM: insert_edge_copy()メソッド削除(no_phi_mode撤廃により不要)
|
||||
|
||||
|
||||
/// Build new expression: new ClassName(arguments)
|
||||
pub(super) fn build_new_expression(
|
||||
&mut self,
|
||||
@ -825,14 +876,15 @@ impl MirBuilder {
|
||||
// 代替: 既存互換として BoxCall("birth")(プラグイン/ビルトインの初期化に対応)
|
||||
if class != "StringBox" {
|
||||
let arity = arg_values.len();
|
||||
let lowered = crate::mir::builder::calls::function_lowering::generate_method_function_name(
|
||||
&class,
|
||||
"birth",
|
||||
arity,
|
||||
);
|
||||
let lowered =
|
||||
crate::mir::builder::calls::function_lowering::generate_method_function_name(
|
||||
&class, "birth", arity,
|
||||
);
|
||||
let use_lowered = if let Some(ref module) = self.current_module {
|
||||
module.functions.contains_key(&lowered)
|
||||
} else { false };
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if use_lowered {
|
||||
// Call Global("Class.birth/Arity") with argv = [me, args...]
|
||||
let mut argv: Vec<ValueId> = Vec::with_capacity(1 + arity);
|
||||
@ -847,7 +899,10 @@ impl MirBuilder {
|
||||
let is_user_box = self.user_defined_boxes.contains(&class);
|
||||
// Dev safety: allow disabling birth() injection for builtins to avoid
|
||||
// unified-call method dispatch issues while migrating. Off by default unless explicitly enabled.
|
||||
let allow_builtin_birth = std::env::var("NYASH_DEV_BIRTH_INJECT_BUILTINS").ok().as_deref() == Some("1");
|
||||
let allow_builtin_birth = std::env::var("NYASH_DEV_BIRTH_INJECT_BUILTINS")
|
||||
.ok()
|
||||
.as_deref()
|
||||
== Some("1");
|
||||
if !is_user_box && allow_builtin_birth {
|
||||
let birt_mid = resolve_slot_by_type_name(&class, "birth");
|
||||
self.emit_box_or_plugin_call(
|
||||
@ -865,7 +920,6 @@ impl MirBuilder {
|
||||
Ok(dst)
|
||||
}
|
||||
|
||||
|
||||
/// Check if the current basic block is terminated
|
||||
fn is_current_block_terminated(&self) -> bool {
|
||||
if let (Some(block_id), Some(ref function)) = (self.current_block, &self.current_function) {
|
||||
@ -919,7 +973,6 @@ impl MirBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Default for MirBuilder {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
|
||||
Reference in New Issue
Block a user