feat(joinir): Phase 66-68 GenericTypeResolver + JoinIR First Chapter Wrap

Phase 66: P3-C ジェネリック型推論箱化
- generic_type_resolver.rs 新設 (180行)
  - is_generic_method(): ArrayBox.get/pop/first/last, MapBox.get 判定
  - resolve_from_phi(): PHI解析によるジェネリック型推論
- TypeHintPolicy::is_p3c_target() 追加
  - P1/P2/P3-A/P3-B 以外を P3-C 候補として判定

Phase 67: P3-C 実利用への一歩
- phase67_generic_type_resolver.rs テスト追加 (3テスト)
- lifecycle.rs に P3-C 経路フック追加
  - GenericTypeResolver を P3-C 対象関数で優先使用
- A/B テストで旧経路との一致確認 (11 tests PASS)

Phase 68: JoinIR First Chapter Wrap (ドキュメント整理)
- 68-1: phase-30 README.md に Section 9 追加 (JoinIR 第1章完了サマリー)
- 68-2: README.md に JoinIR status セクション追加
- 68-3: CURRENT_TASK.md スリム化 (351→132行, 62%削減)
- 68-4: PHI_BOX_INVENTORY.md に Phase 66-67 完了セクション追加

Phase 69-1: Trio 棚卸し
- phase69-1-trio-inventory.md 作成
- Trio 使用箇所の完全棚卸し完了 (削減見込み 457-707行)

🐱 JoinIR 第1章完了!4つの柱確立:
- Structure (LoopForm)
- Scope (LoopScopeShape)
- JoinIR (Select/IfMerge/Loop)
- Type Hints (P1-P3-C)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-30 08:54:18 +09:00
parent aef9374b5a
commit 58c5d8c9bc
9 changed files with 694 additions and 300 deletions

View File

@ -18,6 +18,7 @@ pub mod namingbox_static_method_id; // Phase 21.7++ Phase 1: StaticMethodId stru
pub mod nyash_abi_basic;
pub mod parser;
pub mod phase61_if_in_loop_dryrun; // Phase 61-2: If-in-loop JoinIR dry-run tests
pub mod phase67_generic_type_resolver; // Phase 67: P3-C GenericTypeResolver tests
pub mod plugin_hygiene;
pub mod policy_mutdeny;
pub mod refcell_assignment_test;

View File

@ -0,0 +1,144 @@
//! Phase 67: P3-C GenericTypeResolver 実利用テスト
//!
//! ArrayBox.get / MapBox.get などのジェネリック型メソッドの
//! 型推論が GenericTypeResolver 経由で正しく動作することを検証。
//!
//! # テスト方針
//!
//! 1. MIR を直接構築して if 文 + ArrayBox.get パターンを作成
//! 2. lifecycle.rs での型推論が正しく動作することを確認
//! 3. A/B テスト:旧経路と新経路で同じ結果になることを検証
use crate::mir::join_ir::lowering::generic_type_resolver::GenericTypeResolver;
use crate::mir::join_ir::lowering::type_hint_policy::TypeHintPolicy;
use crate::mir::MirType;
/// Phase 67-1: GenericTypeResolver の基本判定テスト
#[test]
fn phase67_generic_type_resolver_is_generic_method() {
let array_type = MirType::Box("ArrayBox".to_string());
let map_type = MirType::Box("MapBox".to_string());
// P3-C 対象メソッド(ジェネリック型)
assert!(GenericTypeResolver::is_generic_method(&array_type, "get"));
assert!(GenericTypeResolver::is_generic_method(&array_type, "pop"));
assert!(GenericTypeResolver::is_generic_method(&map_type, "get"));
// P3-A/P3-B 対象(非ジェネリック)
assert!(!GenericTypeResolver::is_generic_method(&array_type, "size"));
assert!(!GenericTypeResolver::is_generic_method(&array_type, "push"));
assert!(!GenericTypeResolver::is_generic_method(&map_type, "has"));
}
/// Phase 67-1: TypeHintPolicy と GenericTypeResolver の連携テスト
#[test]
fn phase67_type_hint_policy_p3c_integration() {
// P1/P2/P3-A/P3-B 対象関数は P3-C ではない
assert!(!TypeHintPolicy::is_p3c_target("IfSelectTest.simple/0")); // P1
assert!(!TypeHintPolicy::is_p3c_target("IfMergeTest.simple/0")); // P2
assert!(!TypeHintPolicy::is_p3c_target("read_quoted_from/1")); // P3-A
assert!(!TypeHintPolicy::is_p3c_target("NewBoxTest.array/0")); // P3-B
// 一般関数は P3-C 候補
assert!(TypeHintPolicy::is_p3c_target("ArrayProcessor.process/1"));
assert!(TypeHintPolicy::is_p3c_target("GenericTypeGetTest.array_get/0"));
// is_target と is_p3c_target は排他的
let p3c_func = "GenericTypeGetTest.array_get/0";
assert!(!TypeHintPolicy::is_target(p3c_func));
assert!(TypeHintPolicy::is_p3c_target(p3c_func));
}
/// Phase 67-3: A/B テスト準備 - 型推論経路の一致確認
///
/// GenericTypeResolver::resolve_from_phi() と
/// if_phi::infer_type_from_phi() が同じ結果を返すことを確認
#[test]
fn phase67_ab_test_resolve_from_phi_equivalence() {
use crate::mir::{
BasicBlock, BasicBlockId, ConstValue, EffectMask, FunctionSignature, MirFunction,
MirInstruction, ValueId,
};
use std::collections::BTreeMap;
// 簡単な PHI を含む MIR を構築
// Block 0 (entry): branch to Block 1 or Block 2
// Block 1 (then): v2 = 42, jump to Block 3
// Block 2 (else): v3 = 0, jump to Block 3
// Block 3 (merge): v4 = phi(v2, v3), return v4
let sig = FunctionSignature {
name: "GenericTypeGetTest.simple_phi/0".into(),
params: vec![],
return_type: MirType::Unknown, // 型推論対象
effects: EffectMask::PURE,
};
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
let entry = BasicBlockId::new(0);
let then_bb = BasicBlockId::new(1);
let else_bb = BasicBlockId::new(2);
let merge_bb = BasicBlockId::new(3);
// Block 構築
f.add_block(BasicBlock::new(then_bb));
f.add_block(BasicBlock::new(else_bb));
f.add_block(BasicBlock::new(merge_bb));
// Entry: condition + branch
let cond = f.next_value_id();
f.get_block_mut(entry)
.unwrap()
.add_instruction(MirInstruction::Const {
dst: cond,
value: ConstValue::Bool(true),
});
f.get_block_mut(entry).unwrap().terminator = Some(MirInstruction::Branch {
condition: cond,
then_bb,
else_bb,
});
// Then: v2 = 42
let v2 = f.next_value_id();
f.get_block_mut(then_bb)
.unwrap()
.add_instruction(MirInstruction::Const {
dst: v2,
value: ConstValue::Integer(42),
});
f.get_block_mut(then_bb).unwrap().terminator = Some(MirInstruction::Jump { target: merge_bb });
// Else: v3 = 0
let v3 = f.next_value_id();
f.get_block_mut(else_bb)
.unwrap()
.add_instruction(MirInstruction::Const {
dst: v3,
value: ConstValue::Integer(0),
});
f.get_block_mut(else_bb).unwrap().terminator = Some(MirInstruction::Jump { target: merge_bb });
// Merge: v4 = phi(v2 from then, v3 from else)
let v4 = f.next_value_id();
f.get_block_mut(merge_bb)
.unwrap()
.add_instruction(MirInstruction::Phi {
dst: v4,
inputs: vec![(then_bb, v2), (else_bb, v3)],
type_hint: None, // P3-C: type_hint なし
});
f.get_block_mut(merge_bb).unwrap().terminator = Some(MirInstruction::Return { value: Some(v4) });
// 型情報を設定
let mut types: BTreeMap<ValueId, MirType> = BTreeMap::new();
types.insert(v2, MirType::Integer);
types.insert(v3, MirType::Integer);
// A/B テスト: 両方の経路で同じ結果を返すことを確認
let result_a = crate::mir::phi_core::if_phi::infer_type_from_phi(&f, v4, &types);
let result_b = GenericTypeResolver::resolve_from_phi(&f, v4, &types);
assert_eq!(result_a, result_b, "A/B test: both routes should return the same type");
assert_eq!(result_a, Some(MirType::Integer), "Type should be inferred as Integer");
}