2025-11-21 06:25:17 +09:00
|
|
|
|
use super::{
|
2025-11-24 14:17:02 +09:00
|
|
|
|
BasicBlockId, EffectMask, FunctionSignature, MirInstruction, MirModule, MirType, ValueId,
|
2025-11-21 06:25:17 +09:00
|
|
|
|
};
|
2025-09-17 10:58:12 +09:00
|
|
|
|
use crate::ast::ASTNode;
|
2025-12-01 11:10:46 +09:00
|
|
|
|
use crate::config;
|
2025-09-17 10:58:12 +09:00
|
|
|
|
|
|
|
|
|
|
// Lifecycle routines extracted from builder.rs
|
2025-11-18 06:39:45 +09:00
|
|
|
|
fn has_main_static(ast: &ASTNode) -> bool {
|
|
|
|
|
|
use crate::ast::ASTNode as N;
|
|
|
|
|
|
if let N::Program { statements, .. } = ast {
|
|
|
|
|
|
for st in statements {
|
2025-11-21 06:25:17 +09:00
|
|
|
|
if let N::BoxDeclaration {
|
|
|
|
|
|
name,
|
|
|
|
|
|
methods,
|
|
|
|
|
|
is_static,
|
|
|
|
|
|
..
|
|
|
|
|
|
} = st
|
|
|
|
|
|
{
|
2025-11-18 06:39:45 +09:00
|
|
|
|
if *is_static && name == "Main" {
|
|
|
|
|
|
if let Some(m) = methods.get("main") {
|
|
|
|
|
|
if let N::FunctionDeclaration { .. } = m {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-30 06:37:34 +09:00
|
|
|
|
// Phase 65.5: 型ヒントポリシーを箱化モジュールから使用
|
|
|
|
|
|
//
|
|
|
|
|
|
// 60 行削減!get_phi_type_hint() と is_type_hint_target() を
|
|
|
|
|
|
// type_hint_policy モジュールに移動。
|
|
|
|
|
|
//
|
|
|
|
|
|
// 箱化の利点:
|
|
|
|
|
|
// - ✅ 単一責務:ポリシー判定のみ
|
|
|
|
|
|
// - ✅ テスト可能:各 Phase 独立テスト
|
|
|
|
|
|
// - ✅ 拡張容易:Phase 66+ で P3-C 追加が簡単
|
|
|
|
|
|
use crate::mir::join_ir::lowering::type_hint_policy::TypeHintPolicy;
|
2025-11-30 08:54:18 +09:00
|
|
|
|
// Phase 67: P3-C ジェネリック型推論箱
|
|
|
|
|
|
use crate::mir::join_ir::lowering::generic_type_resolver::GenericTypeResolver;
|
2025-12-02 18:09:04 +09:00
|
|
|
|
// Phase 83: P3-D 既知メソッド戻り値型推論箱
|
|
|
|
|
|
use crate::mir::join_ir::lowering::method_return_hint::MethodReturnHintBox;
|
2025-12-02 19:37:01 +09:00
|
|
|
|
// Phase 84-2: Copy命令型伝播箱(ChatGPT Pro設計)
|
|
|
|
|
|
use crate::mir::phi_core::copy_type_propagator::CopyTypePropagator;
|
2025-12-02 19:54:38 +09:00
|
|
|
|
// Phase 84-3: PHI + Copy グラフ型推論箱(ChatGPT Pro設計)
|
|
|
|
|
|
use crate::mir::phi_core::phi_type_resolver::PhiTypeResolver;
|
2025-11-30 05:20:31 +09:00
|
|
|
|
|
2025-12-02 15:39:19 +09:00
|
|
|
|
// Phase 82: dev ガード用ヘルパー - Case 分類ロジック統一化
|
|
|
|
|
|
//
|
|
|
|
|
|
// infer_type_from_phi_with_hint() の 2 つの callsite で重複していた
|
|
|
|
|
|
// Case 判定ロジックを DRY 化。
|
|
|
|
|
|
//
|
|
|
|
|
|
// Case 分類:
|
|
|
|
|
|
// - Case A: hint 付き(GenericTypeResolver 不要)
|
|
|
|
|
|
// - Case B: P1/P2/P3-A/B で hint 失敗(理論上不可)
|
|
|
|
|
|
// - Case D: P3-C で GenericTypeResolver 失敗(PHI 走査フォールバック)
|
|
|
|
|
|
//
|
|
|
|
|
|
// Note: dev フラグで制御されるので、#[cfg] は不要(環境変数で制御)
|
|
|
|
|
|
fn classify_phi_fallback_case(hint: Option<&MirType>, function_name: &str) -> &'static str {
|
|
|
|
|
|
if hint.is_some() {
|
|
|
|
|
|
"Case A (hint付き)"
|
|
|
|
|
|
} else if TypeHintPolicy::is_target(function_name) {
|
|
|
|
|
|
"Case B (P1/P2/P3-A/B hint失敗)"
|
|
|
|
|
|
} else {
|
|
|
|
|
|
"Case D (P3-C GenericTypeResolver失敗)"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-17 10:58:12 +09:00
|
|
|
|
impl super::MirBuilder {
|
2025-09-26 03:30:59 +09:00
|
|
|
|
/// Unified declaration indexing (Phase A): collect symbols before lowering
|
|
|
|
|
|
/// - user_defined_boxes: non-static Box names (for NewBox birth() skip)
|
|
|
|
|
|
/// - static_method_index: name -> [(BoxName, arity)] (for bare-call fallback)
|
|
|
|
|
|
fn index_declarations(&mut self, node: &ASTNode) {
|
2025-09-25 10:23:14 +09:00
|
|
|
|
match node {
|
|
|
|
|
|
ASTNode::Program { statements, .. } => {
|
|
|
|
|
|
for st in statements {
|
2025-09-26 03:30:59 +09:00
|
|
|
|
self.index_declarations(st);
|
2025-09-25 10:23:14 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-21 06:25:17 +09:00
|
|
|
|
ASTNode::BoxDeclaration {
|
|
|
|
|
|
name,
|
|
|
|
|
|
methods,
|
|
|
|
|
|
is_static,
|
|
|
|
|
|
..
|
|
|
|
|
|
} => {
|
2025-09-26 03:30:59 +09:00
|
|
|
|
if !*is_static {
|
|
|
|
|
|
self.user_defined_boxes.insert(name.clone());
|
|
|
|
|
|
} else {
|
2025-09-25 10:23:14 +09:00
|
|
|
|
for (mname, mast) in methods {
|
|
|
|
|
|
if let ASTNode::FunctionDeclaration { params, .. } = mast {
|
|
|
|
|
|
self.static_method_index
|
|
|
|
|
|
.entry(mname.clone())
|
|
|
|
|
|
.or_insert_with(Vec::new)
|
|
|
|
|
|
.push((name.clone(), params.len()));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => {}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-17 10:58:12 +09:00
|
|
|
|
pub(super) fn prepare_module(&mut self) -> Result<(), String> {
|
2025-11-24 14:17:02 +09:00
|
|
|
|
let mut module = MirModule::new("main".to_string());
|
|
|
|
|
|
module.metadata.source_file = self.current_source_file();
|
2025-09-17 10:58:12 +09:00
|
|
|
|
let main_signature = FunctionSignature {
|
|
|
|
|
|
name: "main".to_string(),
|
|
|
|
|
|
params: vec![],
|
|
|
|
|
|
return_type: MirType::Void,
|
|
|
|
|
|
effects: EffectMask::PURE,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let entry_block = self.block_gen.next();
|
2025-11-24 14:17:02 +09:00
|
|
|
|
let mut main_function = self.new_function_with_metadata(main_signature, entry_block);
|
2025-09-17 10:58:12 +09:00
|
|
|
|
main_function.metadata.is_entry_point = true;
|
|
|
|
|
|
|
|
|
|
|
|
self.current_module = Some(module);
|
|
|
|
|
|
self.current_function = Some(main_function);
|
|
|
|
|
|
self.current_block = Some(entry_block);
|
|
|
|
|
|
|
2025-11-19 03:28:58 +09:00
|
|
|
|
// 関数スコープの SlotRegistry を初期化するよ(観測専用)。
|
|
|
|
|
|
// main 関数用のスロット登録箱として使う想定だよ。
|
|
|
|
|
|
self.current_slot_registry =
|
|
|
|
|
|
Some(crate::mir::region::function_slot_registry::FunctionSlotRegistry::new());
|
|
|
|
|
|
|
|
|
|
|
|
// Region 観測レイヤ: main 関数の FunctionRegion を 1 つ作っておくよ。
|
|
|
|
|
|
crate::mir::region::observer::observe_function_region(self);
|
|
|
|
|
|
|
2025-09-20 05:44:57 +09:00
|
|
|
|
// Hint: scope enter at function entry (id=0 for main)
|
|
|
|
|
|
self.hint_scope_enter(0);
|
|
|
|
|
|
|
2025-09-17 10:58:12 +09:00
|
|
|
|
if std::env::var("NYASH_BUILDER_SAFEPOINT_ENTRY")
|
|
|
|
|
|
.ok()
|
|
|
|
|
|
.as_deref()
|
|
|
|
|
|
== Some("1")
|
|
|
|
|
|
{
|
|
|
|
|
|
self.emit_instruction(MirInstruction::Safepoint)?;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub(super) fn lower_root(&mut self, ast: ASTNode) -> Result<ValueId, String> {
|
2025-09-25 10:23:14 +09:00
|
|
|
|
// Pre-index static methods to enable safe fallback for bare calls in using-prepended code
|
|
|
|
|
|
let snapshot = ast.clone();
|
2025-09-26 03:30:59 +09:00
|
|
|
|
// Phase A: collect declarations in one pass (symbols available to lowering)
|
|
|
|
|
|
self.index_declarations(&snapshot);
|
2025-11-18 06:39:45 +09:00
|
|
|
|
|
|
|
|
|
|
// Decide root mode (App vs Script) once per module based on presence of static box Main.main
|
|
|
|
|
|
// true => App mode (Main.main is entry)
|
|
|
|
|
|
// false => Script/Test mode (top-level Program runs sequentially)
|
|
|
|
|
|
let is_app_mode = self
|
|
|
|
|
|
.root_is_app_mode
|
|
|
|
|
|
.unwrap_or_else(|| has_main_static(&snapshot));
|
|
|
|
|
|
self.root_is_app_mode = Some(is_app_mode);
|
|
|
|
|
|
|
2025-09-26 03:30:59 +09:00
|
|
|
|
// Phase B: top-level program lowering with declaration-first pass
|
|
|
|
|
|
match ast {
|
|
|
|
|
|
ASTNode::Program { statements, .. } => {
|
|
|
|
|
|
use crate::ast::ASTNode as N;
|
|
|
|
|
|
// First pass: lower declarations (static boxes except Main, and instance boxes)
|
2025-11-21 06:25:17 +09:00
|
|
|
|
let mut main_static: Option<(String, std::collections::HashMap<String, ASTNode>)> =
|
|
|
|
|
|
None;
|
2025-09-26 03:30:59 +09:00
|
|
|
|
for st in &statements {
|
|
|
|
|
|
if let N::BoxDeclaration {
|
|
|
|
|
|
name,
|
|
|
|
|
|
methods,
|
|
|
|
|
|
is_static,
|
|
|
|
|
|
fields,
|
|
|
|
|
|
constructors,
|
|
|
|
|
|
weak_fields,
|
|
|
|
|
|
..
|
|
|
|
|
|
} = st
|
|
|
|
|
|
{
|
|
|
|
|
|
if *is_static {
|
|
|
|
|
|
if name == "Main" {
|
|
|
|
|
|
main_static = Some((name.clone(), methods.clone()));
|
|
|
|
|
|
} else {
|
2025-11-18 06:39:45 +09:00
|
|
|
|
// Script/Test モードでは static box の lowering は exprs.rs 側に任せる
|
|
|
|
|
|
if is_app_mode {
|
|
|
|
|
|
// Dev: trace which static box is being lowered (env-gated)
|
|
|
|
|
|
self.trace_compile(format!("lower static box {}", name));
|
|
|
|
|
|
// 🎯 箱理論: 各static boxに専用のコンパイルコンテキストを作成
|
|
|
|
|
|
// これにより、using文や前のboxからのメタデータ汚染を構造的に防止
|
|
|
|
|
|
// スコープを抜けると自動的にコンテキストが破棄される
|
|
|
|
|
|
{
|
|
|
|
|
|
let ctx = super::context::BoxCompilationContext::new();
|
|
|
|
|
|
self.compilation_context = Some(ctx);
|
2025-11-17 11:28:18 +09:00
|
|
|
|
|
2025-11-18 06:39:45 +09:00
|
|
|
|
// Lower all static methods into standalone functions: BoxName.method/Arity
|
|
|
|
|
|
for (mname, mast) in methods.iter() {
|
2025-11-21 06:25:17 +09:00
|
|
|
|
if let N::FunctionDeclaration { params, body, .. } =
|
|
|
|
|
|
mast
|
|
|
|
|
|
{
|
|
|
|
|
|
let func_name = format!(
|
|
|
|
|
|
"{}.{}{}",
|
|
|
|
|
|
name,
|
|
|
|
|
|
mname,
|
|
|
|
|
|
format!("/{}", params.len())
|
|
|
|
|
|
);
|
|
|
|
|
|
self.lower_static_method_as_function(
|
|
|
|
|
|
func_name,
|
|
|
|
|
|
params.clone(),
|
|
|
|
|
|
body.clone(),
|
|
|
|
|
|
)?;
|
2025-11-18 06:39:45 +09:00
|
|
|
|
self.static_method_index
|
|
|
|
|
|
.entry(mname.clone())
|
|
|
|
|
|
.or_insert_with(Vec::new)
|
|
|
|
|
|
.push((name.clone(), params.len()));
|
|
|
|
|
|
}
|
2025-11-17 19:53:44 +09:00
|
|
|
|
}
|
2025-09-26 03:30:59 +09:00
|
|
|
|
}
|
2025-11-17 11:28:18 +09:00
|
|
|
|
|
2025-11-18 06:39:45 +09:00
|
|
|
|
// 🎯 箱理論: コンテキストをクリア(スコープ終了で自動破棄)
|
|
|
|
|
|
// これにより、次のstatic boxは汚染されていない状態から開始される
|
|
|
|
|
|
self.compilation_context = None;
|
|
|
|
|
|
}
|
2025-09-26 03:30:59 +09:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Instance box: register type and lower instance methods/ctors as functions
|
|
|
|
|
|
self.user_defined_boxes.insert(name.clone());
|
|
|
|
|
|
self.build_box_declaration(
|
|
|
|
|
|
name.clone(),
|
|
|
|
|
|
methods.clone(),
|
|
|
|
|
|
fields.clone(),
|
|
|
|
|
|
weak_fields.clone(),
|
|
|
|
|
|
)?;
|
|
|
|
|
|
for (ctor_key, ctor_ast) in constructors.iter() {
|
|
|
|
|
|
if let N::FunctionDeclaration { params, body, .. } = ctor_ast {
|
2025-09-27 08:45:25 +09:00
|
|
|
|
// Keep constructor function name as "Box.birth/N" where ctor_key already encodes arity.
|
|
|
|
|
|
// ctor_key format comes from parser as "birth/<arity>".
|
2025-09-26 03:30:59 +09:00
|
|
|
|
let func_name = format!("{}.{}", name, ctor_key);
|
|
|
|
|
|
self.lower_method_as_function(
|
|
|
|
|
|
func_name,
|
|
|
|
|
|
name.clone(),
|
|
|
|
|
|
params.clone(),
|
|
|
|
|
|
body.clone(),
|
|
|
|
|
|
)?;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
for (mname, mast) in methods.iter() {
|
2025-11-21 06:25:17 +09:00
|
|
|
|
if let N::FunctionDeclaration {
|
|
|
|
|
|
params,
|
|
|
|
|
|
body,
|
|
|
|
|
|
is_static,
|
|
|
|
|
|
..
|
|
|
|
|
|
} = mast
|
|
|
|
|
|
{
|
2025-09-26 03:30:59 +09:00
|
|
|
|
if !*is_static {
|
2025-11-21 06:25:17 +09:00
|
|
|
|
let func_name = format!(
|
|
|
|
|
|
"{}.{}{}",
|
|
|
|
|
|
name,
|
|
|
|
|
|
mname,
|
|
|
|
|
|
format!("/{}", params.len())
|
|
|
|
|
|
);
|
2025-09-26 03:30:59 +09:00
|
|
|
|
self.lower_method_as_function(
|
|
|
|
|
|
func_name,
|
|
|
|
|
|
name.clone(),
|
|
|
|
|
|
params.clone(),
|
|
|
|
|
|
body.clone(),
|
|
|
|
|
|
)?;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 06:39:45 +09:00
|
|
|
|
// Second pass: mode-dependent entry lowering
|
|
|
|
|
|
if is_app_mode {
|
|
|
|
|
|
// App モード: Main.main をエントリとして扱う
|
|
|
|
|
|
if let Some((box_name, methods)) = main_static {
|
|
|
|
|
|
self.build_static_main_box(box_name, methods)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 理論上は起こりにくいが、安全のため Script モードと同じフォールバックにする
|
|
|
|
|
|
self.cf_block(statements)
|
|
|
|
|
|
}
|
2025-09-26 03:30:59 +09:00
|
|
|
|
} else {
|
2025-11-18 06:39:45 +09:00
|
|
|
|
// Script/Test モード: トップレベル Program をそのまま順次実行
|
2025-09-26 03:30:59 +09:00
|
|
|
|
self.cf_block(statements)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
other => self.build_expression(other),
|
|
|
|
|
|
}
|
2025-09-17 10:58:12 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-21 06:25:17 +09:00
|
|
|
|
pub(super) fn finalize_module(&mut self, result_value: ValueId) -> Result<MirModule, String> {
|
2025-09-20 05:44:57 +09:00
|
|
|
|
// Hint: scope leave at function end (id=0 for main)
|
|
|
|
|
|
self.hint_scope_leave(0);
|
2025-09-17 10:58:12 +09:00
|
|
|
|
if let Some(block_id) = self.current_block {
|
|
|
|
|
|
if let Some(ref mut function) = self.current_function {
|
|
|
|
|
|
if let Some(block) = function.get_block_mut(block_id) {
|
|
|
|
|
|
if !block.is_terminated() {
|
|
|
|
|
|
block.add_instruction(MirInstruction::Return {
|
|
|
|
|
|
value: Some(result_value),
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(mt) = self.value_types.get(&result_value).cloned() {
|
|
|
|
|
|
function.signature.return_type = mt;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let mut module = self.current_module.take().unwrap();
|
|
|
|
|
|
let mut function = self.current_function.take().unwrap();
|
|
|
|
|
|
function.metadata.value_types = self.value_types.clone();
|
2025-12-02 19:37:01 +09:00
|
|
|
|
// Phase 84-2: Copy命令型伝播(return型推論の前に実行)
|
|
|
|
|
|
//
|
|
|
|
|
|
// Loop exit や If merge の edge copy で発生する型欠如を解消する。
|
|
|
|
|
|
// Copy チェーン: v1 → v2 → v3 で v1 の型が既知なら v2, v3 にも伝播。
|
|
|
|
|
|
CopyTypePropagator::propagate(&function, &mut self.value_types);
|
|
|
|
|
|
|
2025-12-02 16:00:50 +09:00
|
|
|
|
// Phase 82-5: lifecycle.rs バグ修正 - terminator の Return のみをチェック
|
|
|
|
|
|
// 問題: instructions を先に走査すると、中間値(const void 等)を誤って推論対象にしてしまう
|
|
|
|
|
|
// 解決: terminator の Return のみをチェックし、実際の戻り値を正しく推論する
|
2025-09-17 10:58:12 +09:00
|
|
|
|
if matches!(
|
|
|
|
|
|
function.signature.return_type,
|
|
|
|
|
|
super::MirType::Void | super::MirType::Unknown
|
|
|
|
|
|
) {
|
|
|
|
|
|
let mut inferred: Option<super::MirType> = None;
|
2025-12-02 16:00:50 +09:00
|
|
|
|
for (_bid, bb) in function.blocks.iter() {
|
|
|
|
|
|
// Phase 82-5: instructions 走査を削除、terminator の Return のみをチェック
|
2025-09-17 10:58:12 +09:00
|
|
|
|
if let Some(super::MirInstruction::Return { value: Some(v) }) = &bb.terminator {
|
|
|
|
|
|
if let Some(mt) = self.value_types.get(v).cloned() {
|
|
|
|
|
|
inferred = Some(mt);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2025-11-30 06:37:34 +09:00
|
|
|
|
// Phase 65.5: TypeHintPolicy 使用(箱化モジュール)
|
2025-11-30 08:54:18 +09:00
|
|
|
|
// Phase 67: P3-C 経路を GenericTypeResolver に委譲
|
2025-11-30 06:37:34 +09:00
|
|
|
|
let hint = if TypeHintPolicy::is_target(&function.signature.name) {
|
|
|
|
|
|
TypeHintPolicy::extract_phi_type_hint(&function, *v)
|
2025-11-30 04:45:11 +09:00
|
|
|
|
} else {
|
|
|
|
|
|
None
|
|
|
|
|
|
};
|
2025-12-02 18:09:04 +09:00
|
|
|
|
// Phase 83: P3-D 既知メソッド戻り値型推論(P3-C より先に試行)
|
|
|
|
|
|
//
|
|
|
|
|
|
// P3-D は「既知メソッドの戻り値型」を直接推論する。
|
|
|
|
|
|
// BoxCall の method 名から TypeAnnotationBox と同じマッピングで型を取得。
|
|
|
|
|
|
if hint.is_none() {
|
|
|
|
|
|
if let Some(mt) =
|
|
|
|
|
|
MethodReturnHintBox::resolve_for_return(&function, *v, &self.value_types)
|
|
|
|
|
|
{
|
|
|
|
|
|
if std::env::var("NYASH_P3D_DEBUG").is_ok() {
|
|
|
|
|
|
eprintln!(
|
|
|
|
|
|
"[lifecycle/p3d] {} type inferred via MethodReturnHintBox: {:?}",
|
|
|
|
|
|
function.signature.name, mt
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
inferred = Some(mt);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-02 19:54:38 +09:00
|
|
|
|
// Phase 84-3: P4 PHI + Copy グラフ型推論(P3-C より先に試行)
|
|
|
|
|
|
//
|
|
|
|
|
|
// PHI + Copy の小グラフを DFS 探索し、1 種類の型に収束する場合のみ返す。
|
|
|
|
|
|
// これにより Loop edge copy / If merge 後の型推論が解決できる。
|
|
|
|
|
|
if hint.is_none() {
|
|
|
|
|
|
let phi_resolver = PhiTypeResolver::new(&function, &self.value_types);
|
|
|
|
|
|
if let Some(mt) = phi_resolver.resolve(*v) {
|
|
|
|
|
|
if std::env::var("NYASH_P4_DEBUG").is_ok() {
|
|
|
|
|
|
eprintln!(
|
|
|
|
|
|
"[lifecycle/p4] {} type inferred via PhiTypeResolver: {:?}",
|
|
|
|
|
|
function.signature.name, mt
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
inferred = Some(mt);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-30 08:54:18 +09:00
|
|
|
|
// Phase 67: P3-C 対象なら GenericTypeResolver を優先使用
|
|
|
|
|
|
if hint.is_none() && TypeHintPolicy::is_p3c_target(&function.signature.name) {
|
2025-12-01 11:10:46 +09:00
|
|
|
|
if let Some(mt) =
|
|
|
|
|
|
GenericTypeResolver::resolve_from_phi(&function, *v, &self.value_types)
|
|
|
|
|
|
{
|
2025-11-30 08:54:18 +09:00
|
|
|
|
if std::env::var("NYASH_P3C_DEBUG").is_ok() {
|
|
|
|
|
|
eprintln!(
|
|
|
|
|
|
"[lifecycle/p3c] {} type inferred via GenericTypeResolver: {:?}",
|
|
|
|
|
|
function.signature.name, mt
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
inferred = Some(mt);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-02 21:09:15 +09:00
|
|
|
|
// Phase 84-5: if_phi.rs 完全削除後の安全ガード
|
|
|
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
|
|
{
|
2025-12-02 15:18:41 +09:00
|
|
|
|
panic!(
|
2025-12-02 21:09:15 +09:00
|
|
|
|
"[phase84-5] Type inference failed for {:?} in function {}\n\
|
|
|
|
|
|
This should not happen after Phase 84-4 completion.\n\
|
|
|
|
|
|
Please check: PhiTypeResolver, BoxCall type registration, CopyTypePropagator",
|
|
|
|
|
|
v, function.signature.name
|
2025-12-02 15:18:41 +09:00
|
|
|
|
);
|
|
|
|
|
|
}
|
2025-12-02 21:09:15 +09:00
|
|
|
|
|
|
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
|
|
|
|
{
|
|
|
|
|
|
eprintln!(
|
|
|
|
|
|
"[phase84-5/warning] Type inference failed for {:?} in {}, using Unknown fallback",
|
|
|
|
|
|
v, function.signature.name
|
|
|
|
|
|
);
|
|
|
|
|
|
inferred = Some(MirType::Unknown);
|
2025-09-17 10:58:12 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(mt) = inferred {
|
|
|
|
|
|
function.signature.return_type = mt;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-28 01:33:58 +09:00
|
|
|
|
// Dev-only verify: NewBox → birth() invariant (warn if missing)
|
2025-12-01 11:10:46 +09:00
|
|
|
|
// Stage‑B 用トグル: NYASH_STAGEB_DEV_VERIFY=0 のときは StageBDriverBox だけ警告をスキップする。
|
2025-09-28 01:33:58 +09:00
|
|
|
|
if crate::config::env::using_is_dev() {
|
2025-12-01 11:10:46 +09:00
|
|
|
|
let stageb_dev_verify_on = config::env::stageb_dev_verify_enabled();
|
2025-09-28 01:33:58 +09:00
|
|
|
|
let mut warn_count = 0usize;
|
|
|
|
|
|
for (_bid, bb) in function.blocks.iter() {
|
|
|
|
|
|
let insns = &bb.instructions;
|
|
|
|
|
|
let mut idx = 0usize;
|
|
|
|
|
|
while idx < insns.len() {
|
2025-11-21 06:25:17 +09:00
|
|
|
|
if let MirInstruction::NewBox {
|
|
|
|
|
|
dst,
|
|
|
|
|
|
box_type,
|
|
|
|
|
|
args,
|
|
|
|
|
|
} = &insns[idx]
|
|
|
|
|
|
{
|
2025-12-02 12:36:28 +09:00
|
|
|
|
// Phase 71-SSA 71-11.2: StageBDriverBox is a static box → skip birth warning unconditionally
|
|
|
|
|
|
// Static boxes don't follow NewBox→birth pattern by design
|
|
|
|
|
|
if box_type == "StageBDriverBox" {
|
2025-12-01 11:10:46 +09:00
|
|
|
|
idx += 1;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2025-09-28 01:33:58 +09:00
|
|
|
|
// Skip StringBox (literal optimization path)
|
|
|
|
|
|
if box_type != "StringBox" {
|
|
|
|
|
|
let expect_tail = format!("{}.birth/{}", box_type, args.len());
|
|
|
|
|
|
// Look ahead up to 3 instructions for either BoxCall("birth") on dst or Global(expect_tail)
|
|
|
|
|
|
let mut ok = false;
|
|
|
|
|
|
let mut j = idx + 1;
|
|
|
|
|
|
let mut last_const_name: Option<String> = None;
|
|
|
|
|
|
while j < insns.len() && j <= idx + 3 {
|
|
|
|
|
|
match &insns[j] {
|
2025-11-21 06:25:17 +09:00
|
|
|
|
MirInstruction::BoxCall {
|
|
|
|
|
|
box_val, method, ..
|
|
|
|
|
|
} => {
|
|
|
|
|
|
if method == "birth" && box_val == dst {
|
|
|
|
|
|
ok = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2025-09-28 01:33:58 +09:00
|
|
|
|
}
|
|
|
|
|
|
MirInstruction::Const { value, .. } => {
|
2025-11-21 06:25:17 +09:00
|
|
|
|
if let super::ConstValue::String(s) = value {
|
|
|
|
|
|
last_const_name = Some(s.clone());
|
|
|
|
|
|
}
|
2025-09-28 01:33:58 +09:00
|
|
|
|
}
|
2025-11-18 18:56:35 +09:00
|
|
|
|
MirInstruction::Call { func: _, .. } => {
|
2025-09-28 01:33:58 +09:00
|
|
|
|
// If immediately preceded by matching Const String, accept
|
|
|
|
|
|
if let Some(prev) = last_const_name.as_ref() {
|
2025-11-21 06:25:17 +09:00
|
|
|
|
if prev == &expect_tail {
|
|
|
|
|
|
ok = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2025-09-28 01:33:58 +09:00
|
|
|
|
}
|
|
|
|
|
|
// Heuristic: in some forms, builder may reuse a shared const; best-effort only
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => {}
|
|
|
|
|
|
}
|
|
|
|
|
|
j += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
eprintln!("[warn] dev verify: NewBox {} at v{} not followed by birth() call (expect {})", box_type, dst, expect_tail);
|
|
|
|
|
|
warn_count += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
idx += 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if warn_count > 0 {
|
2025-11-21 06:25:17 +09:00
|
|
|
|
eprintln!(
|
|
|
|
|
|
"[warn] dev verify: NewBox→birth invariant warnings: {}",
|
|
|
|
|
|
warn_count
|
|
|
|
|
|
);
|
2025-09-28 01:33:58 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-17 10:58:12 +09:00
|
|
|
|
module.add_function(function);
|
|
|
|
|
|
|
2025-09-28 12:19:49 +09:00
|
|
|
|
// Dev stub: provide condition_fn when missing to satisfy predicate calls in JSON lexers
|
|
|
|
|
|
// Returns integer 1 (truthy) and accepts one argument (unused).
|
2025-11-20 06:38:43 +09:00
|
|
|
|
//
|
|
|
|
|
|
// NOTE:
|
|
|
|
|
|
// - MirFunction::new() はシグネチャの params に応じて
|
|
|
|
|
|
// [ValueId(0)..ValueId(param_count-1)] を事前に予約する。
|
|
|
|
|
|
// - ここでは追加の next_value_id()/params.push() は行わず、
|
|
|
|
|
|
// 予約済みのパラメータ集合をそのまま使う。
|
2025-09-28 12:19:49 +09:00
|
|
|
|
if module.functions.get("condition_fn").is_none() {
|
2025-11-18 18:56:35 +09:00
|
|
|
|
let sig = FunctionSignature {
|
2025-09-28 12:19:49 +09:00
|
|
|
|
name: "condition_fn".to_string(),
|
|
|
|
|
|
params: vec![MirType::Integer], // accept one i64-like arg
|
|
|
|
|
|
return_type: MirType::Integer,
|
|
|
|
|
|
effects: EffectMask::PURE,
|
|
|
|
|
|
};
|
|
|
|
|
|
let entry = BasicBlockId::new(0);
|
2025-11-24 14:17:02 +09:00
|
|
|
|
let mut f = self.new_function_with_metadata(sig, entry);
|
2025-09-28 20:38:09 +09:00
|
|
|
|
// body: const 1; return it(FunctionEmissionBox を使用)
|
|
|
|
|
|
let one = crate::mir::function_emission::emit_const_integer(&mut f, entry, 1);
|
|
|
|
|
|
crate::mir::function_emission::emit_return_value(&mut f, entry, one);
|
2025-09-28 12:19:49 +09:00
|
|
|
|
module.add_function(f);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-19 03:28:58 +09:00
|
|
|
|
// main 関数スコープの Region スタックをポップするよ。
|
|
|
|
|
|
crate::mir::region::observer::pop_function_region(self);
|
|
|
|
|
|
|
|
|
|
|
|
// main 関数スコープの SlotRegistry を解放するよ。
|
|
|
|
|
|
self.current_slot_registry = None;
|
|
|
|
|
|
|
2025-09-17 10:58:12 +09:00
|
|
|
|
Ok(module)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|