Files
hakorune/src/mir/builder/rewrite/special.rs
nyash-codex f9d100ce01 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>
2025-11-21 06:25:17 +09:00

299 lines
12 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.

use super::super::MirBuilder;
/// Early special-case: toString/stringify → str互換を処理。
/// 戻り値: Some(result_id) なら処理済み。None なら通常経路へ委譲。
#[allow(dead_code)]
pub(crate) fn try_early_str_like(
builder: &mut MirBuilder,
object_value: super::super::ValueId,
class_name_opt: &Option<String>,
method: &str,
arity: usize,
) -> Option<Result<super::super::ValueId, String>> {
if !(method == "toString" || method == "stringify") || arity != 0 {
return None;
}
let module = match &builder.current_module {
Some(m) => m,
None => return None,
};
// Prefer class-qualified str if we can infer class; fallback to stringify for互換
if let Some(cls) = class_name_opt.clone() {
let str_name = crate::mir::builder::calls::function_lowering::generate_method_function_name(
&cls, "str", 0,
);
let compat_stringify =
crate::mir::builder::calls::function_lowering::generate_method_function_name(
&cls,
"stringify",
0,
);
let have_str = module.functions.contains_key(&str_name);
let have_compat = module.functions.contains_key(&compat_stringify);
if have_str || (!have_str && have_compat) {
let chosen = if have_str { str_name } else { compat_stringify };
// emit choose (dev-only)
let meta = serde_json::json!({
"recv_cls": cls,
"method": method,
"arity": 0,
"chosen": chosen,
"reason": if have_str { "toString-early-class-str" } else { "toString-early-class-stringify" },
"certainty": "Known",
});
super::super::observe::resolve::emit_choose(builder, meta);
// unified
let mut call_args = Vec::with_capacity(1);
call_args.push(object_value);
crate::mir::builder::ssa::local::finalize_args(builder, &mut call_args);
let dst = builder.next_value_id();
if let Err(e) = builder.emit_unified_call(
Some(dst),
crate::mir::builder::builder_calls::CallTarget::Global(chosen.clone()),
call_args,
) {
return Some(Err(e));
}
builder.annotate_call_result_from_func_name(dst, &chosen);
return Some(Ok(dst));
}
}
// Unique suffix fallback: prefer *.str/0, else *.stringify/0両方ある場合は JsonNode.str/0 を優先)
// Merge candidates from tails: ".str/0" and ".stringify/0"
let mut cands: Vec<String> = builder.method_candidates_tail(".str/0");
let mut more = builder.method_candidates_tail(".stringify/0");
cands.append(&mut more);
if cands.len() == 1 {
let fname = cands.remove(0);
let meta = serde_json::json!({
"recv_cls": class_name_opt.clone().unwrap_or_default(),
"method": method,
"arity": 0,
"chosen": fname,
"reason": "toString-early-unique",
"certainty": "Heuristic",
});
super::super::observe::resolve::emit_choose(builder, meta);
// unified
let mut call_args = Vec::with_capacity(1);
call_args.push(object_value);
crate::mir::builder::ssa::local::finalize_args(builder, &mut call_args);
let dst = builder.next_value_id();
if let Err(e) = builder.emit_unified_call(
Some(dst),
crate::mir::builder::builder_calls::CallTarget::Global(fname.clone()),
call_args,
) {
return Some(Err(e));
}
builder.annotate_call_result_from_func_name(dst, &fname);
return Some(Ok(dst));
} else if cands.len() > 1 {
if let Some(pos) = cands.iter().position(|n| n == "JsonNode.str/0") {
let fname = cands.remove(pos);
let meta = serde_json::json!({
"recv_cls": class_name_opt.clone().unwrap_or_default(),
"method": method,
"arity": 0,
"chosen": fname,
"reason": "toString-early-prefer-JsonNode",
"certainty": "Heuristic",
});
super::super::observe::resolve::emit_choose(builder, meta);
// unified
let mut call_args = Vec::with_capacity(1);
call_args.push(object_value);
crate::mir::builder::ssa::local::finalize_args(builder, &mut call_args);
let dst = builder.next_value_id();
if let Err(e) = builder.emit_unified_call(
Some(dst),
crate::mir::builder::builder_calls::CallTarget::Global(fname.clone()),
call_args,
) {
return Some(Err(e));
}
builder.annotate_call_result_from_func_name(dst, &fname);
return Some(Ok(dst));
}
}
None
}
/// Special-case for equals/1: prefer Known rewrite; otherwise allow unique-suffix fallback
/// when it is deterministic (single candidate). This centralizes equals handling.
#[allow(dead_code)]
pub(crate) fn try_special_equals(
builder: &mut MirBuilder,
object_value: super::super::ValueId,
class_name_opt: &Option<String>,
method: &str,
args: Vec<super::super::ValueId>,
) -> Option<Result<super::super::ValueId, String>> {
if method != "equals" || args.len() != 1 {
return None;
}
// First, Known rewrite if possible
if let Some(cls) = class_name_opt.as_ref() {
if let Some(res) =
super::known::try_known_rewrite(builder, object_value, cls, method, args.clone())
{
return Some(res);
}
}
// Next, try unique-suffix fallback only for equals/1
super::known::try_unique_suffix_rewrite(builder, object_value, method, args)
}
/// To-dst variant: early str-like with a requested destination
pub(crate) fn try_early_str_like_to_dst(
builder: &mut MirBuilder,
want_dst: Option<super::super::ValueId>,
object_value: super::super::ValueId,
class_name_opt: &Option<String>,
method: &str,
arity: usize,
) -> Option<Result<super::super::ValueId, String>> {
if !(method == "toString" || method == "stringify") || arity != 0 {
return None;
}
let module = match &builder.current_module {
Some(m) => m,
None => return None,
};
if let Some(cls) = class_name_opt.clone() {
let str_name = crate::mir::builder::calls::function_lowering::generate_method_function_name(
&cls, "str", 0,
);
let compat_stringify =
crate::mir::builder::calls::function_lowering::generate_method_function_name(
&cls,
"stringify",
0,
);
let have_str = module.functions.contains_key(&str_name);
let have_compat = module.functions.contains_key(&compat_stringify);
if have_str || (!have_str && have_compat) {
let chosen = if have_str { str_name } else { compat_stringify };
let meta = serde_json::json!({
"recv_cls": cls,
"method": method,
"arity": 0,
"chosen": chosen,
"reason": if have_str { "toString-early-class-str" } else { "toString-early-class-stringify" },
"certainty": "Known",
});
super::super::observe::resolve::emit_choose(builder, meta);
let _name_const =
match crate::mir::builder::name_const::make_name_const_result(builder, &chosen) {
Ok(v) => v,
Err(e) => return Some(Err(e)),
};
let mut call_args = Vec::with_capacity(1);
call_args.push(object_value);
crate::mir::builder::ssa::local::finalize_args(builder, &mut call_args);
let actual_dst = want_dst.unwrap_or_else(|| builder.next_value_id());
if let Err(e) = builder.emit_unified_call(
Some(actual_dst),
crate::mir::builder::builder_calls::CallTarget::Global(chosen.clone()),
call_args,
) {
return Some(Err(e));
}
builder.annotate_call_result_from_func_name(actual_dst, &chosen);
return Some(Ok(actual_dst));
}
}
let mut cands: Vec<String> = builder.method_candidates_tail(".str/0");
let mut more = builder.method_candidates_tail(".stringify/0");
cands.append(&mut more);
if cands.len() == 1 {
let fname = cands.remove(0);
let meta = serde_json::json!({
"recv_cls": class_name_opt.clone().unwrap_or_default(),
"method": method,
"arity": 0,
"chosen": fname,
"reason": "toString-early-unique",
"certainty": "Heuristic",
});
super::super::observe::resolve::emit_choose(builder, meta);
let _name_const =
match crate::mir::builder::name_const::make_name_const_result(builder, &fname) {
Ok(v) => v,
Err(e) => return Some(Err(e)),
};
let mut call_args = Vec::with_capacity(1);
call_args.push(object_value);
crate::mir::builder::ssa::local::finalize_args(builder, &mut call_args);
let actual_dst = want_dst.unwrap_or_else(|| builder.next_value_id());
if let Err(e) = builder.emit_unified_call(
Some(actual_dst),
crate::mir::builder::builder_calls::CallTarget::Global(fname.clone()),
call_args,
) {
return Some(Err(e));
}
builder.annotate_call_result_from_func_name(actual_dst, &fname);
return Some(Ok(actual_dst));
} else if cands.len() > 1 {
if let Some(pos) = cands.iter().position(|n| n == "JsonNode.str/0") {
let fname = cands.remove(pos);
let meta = serde_json::json!({
"recv_cls": class_name_opt.clone().unwrap_or_default(),
"method": method,
"arity": 0,
"chosen": fname,
"reason": "toString-early-prefer-JsonNode",
"certainty": "Heuristic",
});
super::super::observe::resolve::emit_choose(builder, meta);
let _name_const =
match crate::mir::builder::name_const::make_name_const_result(builder, &fname) {
Ok(v) => v,
Err(e) => return Some(Err(e)),
};
let mut call_args = Vec::with_capacity(1);
call_args.push(object_value);
crate::mir::builder::ssa::local::finalize_args(builder, &mut call_args);
let actual_dst = want_dst.unwrap_or_else(|| builder.next_value_id());
if let Err(e) = builder.emit_unified_call(
Some(actual_dst),
crate::mir::builder::builder_calls::CallTarget::Global(fname.clone()),
call_args,
) {
return Some(Err(e));
}
builder.annotate_call_result_from_func_name(actual_dst, &fname);
return Some(Ok(actual_dst));
}
}
None
}
/// To-dst variant: equals/1 consolidation with requested destination
pub(crate) fn try_special_equals_to_dst(
builder: &mut MirBuilder,
want_dst: Option<super::super::ValueId>,
object_value: super::super::ValueId,
class_name_opt: &Option<String>,
method: &str,
args: Vec<super::super::ValueId>,
) -> Option<Result<super::super::ValueId, String>> {
if method != "equals" || args.len() != 1 {
return None;
}
if let Some(cls) = class_name_opt.as_ref() {
if let Some(res) = super::known::try_known_rewrite_to_dst(
builder,
want_dst,
object_value,
cls,
method,
args.clone(),
) {
return Some(res);
}
}
super::known::try_unique_suffix_rewrite_to_dst(builder, want_dst, object_value, method, args)
}