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:
nyash-codex
2025-11-21 06:25:17 +09:00
parent baf028a94f
commit f9d100ce01
366 changed files with 14322 additions and 5236 deletions

View File

@ -1,7 +1,7 @@
use super::{Effect, EffectMask, MirInstruction, ValueId};
use crate::ast::{ASTNode, CallExpr};
use crate::mir::TypeOpKind;
use crate::mir::utils::is_current_block_terminated;
use crate::mir::TypeOpKind;
impl super::MirBuilder {
// Print statement: env.console.log(value) with early TypeOp handling
@ -10,15 +10,34 @@ impl super::MirBuilder {
// Prefer wrapper for simple function-call pattern (non-breaking refactor)
if let Ok(call) = CallExpr::try_from(expression.clone()) {
if (call.name == "isType" || call.name == "asType") && call.arguments.len() == 2 {
super::utils::builder_debug_log("pattern: print(FunctionCall isType|asType) [via wrapper]");
if let Some(type_name) = super::MirBuilder::extract_string_literal(&call.arguments[1]) {
super::utils::builder_debug_log(&format!("extract_string_literal OK: {}", type_name));
super::utils::builder_debug_log(
"pattern: print(FunctionCall isType|asType) [via wrapper]",
);
if let Some(type_name) =
super::MirBuilder::extract_string_literal(&call.arguments[1])
{
super::utils::builder_debug_log(&format!(
"extract_string_literal OK: {}",
type_name
));
let val = self.build_expression(call.arguments[0].clone())?;
let ty = super::MirBuilder::parse_type_name_to_mir(&type_name);
let dst = self.next_value_id();
let op = if call.name == "isType" { TypeOpKind::Check } else { TypeOpKind::Cast };
super::utils::builder_debug_log(&format!("emit TypeOp {:?} value={} dst= {}", op, val, dst));
self.emit_instruction(MirInstruction::TypeOp { dst, op, value: val, ty })?;
let op = if call.name == "isType" {
TypeOpKind::Check
} else {
TypeOpKind::Cast
};
super::utils::builder_debug_log(&format!(
"emit TypeOp {:?} value={} dst= {}",
op, val, dst
));
self.emit_instruction(MirInstruction::TypeOp {
dst,
op,
value: val,
ty,
})?;
self.emit_instruction(MirInstruction::ExternCall {
dst: None,
iface_name: "env.console".to_string(),
@ -129,7 +148,7 @@ impl super::MirBuilder {
if use_unified {
// New unified path - treat print as global function
self.emit_unified_call(
None, // print returns nothing
None, // print returns nothing
super::builder_calls::CallTarget::Global("print".to_string()),
vec![value],
)?;
@ -155,14 +174,24 @@ impl super::MirBuilder {
let total = statements.len();
eprintln!("[DEBUG/build_block] Processing {} statements", total);
for (idx, statement) in statements.into_iter().enumerate() {
eprintln!("[DEBUG/build_block] Statement {}/{} current_block={:?} current_function={}",
idx+1, total, self.current_block,
self.current_function.as_ref().map(|f| f.signature.name.as_str()).unwrap_or("none"));
eprintln!(
"[DEBUG/build_block] Statement {}/{} current_block={:?} current_function={}",
idx + 1,
total,
self.current_block,
self.current_function
.as_ref()
.map(|f| f.signature.name.as_str())
.unwrap_or("none")
);
last_value = Some(self.build_statement(statement)?);
// If the current block was terminated by this statement (e.g., return/throw),
// do not emit any further instructions for this block.
if is_current_block_terminated(self)? {
eprintln!("[DEBUG/build_block] Block terminated after statement {}", idx+1);
eprintln!(
"[DEBUG/build_block] Block terminated after statement {}",
idx + 1
);
break;
}
}
@ -190,7 +219,6 @@ impl super::MirBuilder {
}
}
// Local declarations with optional initializers
pub(super) fn build_local_statement(
&mut self,
@ -198,7 +226,11 @@ impl super::MirBuilder {
initial_values: Vec<Option<Box<ASTNode>>>,
) -> Result<ValueId, String> {
if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() {
eprintln!("[build_local_statement] ENTRY: variables={:?}, initial_values.len()={}", variables, initial_values.len());
eprintln!(
"[build_local_statement] ENTRY: variables={:?}, initial_values.len()={}",
variables,
initial_values.len()
);
}
let mut last_value = None;
for (i, var_name) in variables.iter().enumerate() {
@ -212,12 +244,15 @@ impl super::MirBuilder {
let var_id = self.next_value_id();
if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() {
eprintln!("[build_local_statement] '{}': init_val={:?}, allocated var_id={:?}", var_name, init_val, var_id);
eprintln!(
"[build_local_statement] '{}': init_val={:?}, allocated var_id={:?}",
var_name, init_val, var_id
);
}
self.emit_instruction(crate::mir::MirInstruction::Copy {
dst: var_id,
src: init_val
src: init_val,
})?;
// Propagate metadata (type/origin) from initializer to variable
@ -228,13 +263,19 @@ impl super::MirBuilder {
// Create a concrete register for uninitialized locals (Void)
let void_id = crate::mir::builder::emission::constant::emit_void(self);
if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() {
eprintln!("[build_local_statement] '{}': uninitialized, void_id={:?}", var_name, void_id);
eprintln!(
"[build_local_statement] '{}': uninitialized, void_id={:?}",
var_name, void_id
);
}
void_id
};
if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() {
eprintln!("[build_local_statement] Inserting '{}' -> {:?} into variable_map", var_name, var_id);
eprintln!(
"[build_local_statement] Inserting '{}' -> {:?} into variable_map",
var_name, var_id
);
}
self.variable_map.insert(var_name.clone(), var_id);
// SlotRegistry にもローカル変数スロットを登録しておくよ(観測専用)
@ -267,7 +308,10 @@ impl super::MirBuilder {
// Defer: copy into slot and jump to target
if let (Some(slot), Some(target)) = (self.return_defer_slot, self.return_defer_target) {
self.return_deferred_emitted = true;
self.emit_instruction(MirInstruction::Copy { dst: slot, src: return_value })?;
self.emit_instruction(MirInstruction::Copy {
dst: slot,
src: return_value,
})?;
crate::mir::builder::metadata::propagate::propagate(self, return_value, slot);
if !self.is_current_block_terminated() {
crate::mir::builder::emission::branch::emit_jump(self, target)?;
@ -275,12 +319,16 @@ impl super::MirBuilder {
Ok(return_value)
} else {
// Fallback: no configured slot/target; emit a real return
self.emit_instruction(MirInstruction::Return { value: Some(return_value) })?;
self.emit_instruction(MirInstruction::Return {
value: Some(return_value),
})?;
Ok(return_value)
}
} else {
// Normal return
self.emit_instruction(MirInstruction::Return { value: Some(return_value) })?;
self.emit_instruction(MirInstruction::Return {
value: Some(return_value),
})?;
Ok(return_value)
}
}
@ -299,7 +347,8 @@ impl super::MirBuilder {
} = expression.clone()
{
let recv_val = self.build_expression(*object)?;
let mname_id = crate::mir::builder::emission::constant::emit_string(self, method.clone());
let mname_id =
crate::mir::builder::emission::constant::emit_string(self, method.clone());
let mut arg_vals: Vec<ValueId> = Vec::with_capacity(2 + arguments.len());
arg_vals.push(recv_val);
arg_vals.push(mname_id);