refactor(joinir): Phase 286 コード品質改善 - ヘルパー共通化 + static box フィルタ

## 1. lower_*_ast ヘルパー共通化
- `lower_value_ast()` に MethodCall 対応追加
- Pattern8 normalizer も共有ヘルパーを使用
- Pattern1/8/9 で一貫した lowering ロジック

## 2. PLAN_EXTRACTORS ドキュメント追加
- `WithPostLoop` variant: 将来拡張用として残存理由を明記
- 現在は常に `&[]` を渡すが、post-loop segment analysis 用に保持

## 3. Legacy Pattern8 残存 + static box フィルタ
- Plan extractor は pure 関数(builder にアクセス不可)
- router 側で static box フィルタリングを実装
- static box コンテキストは legacy Pattern8 へ fallback
- legacy 残存理由をドキュメント化

## 検証
- Quick: 154 PASS, 0 FAILED
- Pattern8 integration: exit 7

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-26 03:35:02 +09:00
parent 832d018046
commit 21daf1b7dd
3 changed files with 85 additions and 6 deletions

View File

@ -1,7 +1,26 @@
//! Pattern 8: Boolean Predicate Scan (is_integer/is_valid form)
//! Pattern 8: Boolean Predicate Scan (is_integer/is_valid form) - LEGACY LINE
//!
//! Phase 259 P0: Dedicated pattern for boolean predicate validation loops
//!
//! ## Legacy Status (Phase 286 P3)
//!
//! **RETAINED FOR STATIC BOX CONTEXTS**
//!
//! - **Plan line** (Phase 286 P2.4): Handles regular loops via extract_pattern8_plan()
//! - **Legacy line** (this file): Handles static box loops ONLY
//!
//! ### Why Legacy is Still Needed:
//!
//! 1. **Static box filtering**: Plan extractors are pure functions without builder access
//! - Plan extractors cannot check `builder.comp_ctx.current_static_box`
//! - Legacy `can_lower()` rejects static box contexts (see static box check below)
//! 2. **ReceiverNormalizeBox coordination**: Static box `this.method()` calls
//! are normalized by ReceiverNormalizeBox, not Pattern8
//! 3. **Fail-Fast**: Plan line succeeds → legacy unreachable. Plan line fails → fallback to legacy
//!
//! **Deletion Condition**: Legacy can be removed when Plan extraction router
//! adds static box filtering OR when ReceiverNormalizeBox handles all static box loops.
//!
//! ## Pattern Structure
//!
//! ```nyash

View File

@ -178,6 +178,10 @@ enum PlanExtractorVariant {
WithFnBody(fn(&ASTNode, &[ASTNode], Option<&[ASTNode]>) -> Result<Option<crate::mir::builder::control_flow::plan::DomainPlan>, String>),
/// Extractor with post_loop_code: (condition, body, post_loop_code) - Pattern7
///
/// NOTE (Phase 286): Currently always called with &[] for post_loop_code.
/// This variant is kept for future extension (post-loop segment analysis).
/// The _post_loop_code parameter in Pattern7 extractor is intentionally unused.
WithPostLoop(fn(&ASTNode, &[ASTNode], &[ASTNode]) -> Result<Option<crate::mir::builder::control_flow::plan::DomainPlan>, String>),
}
@ -243,8 +247,22 @@ fn try_plan_extractors(
}
};
// If extraction succeeded, try lowering
// If extraction succeeded, check if we can lower it
if let Some(domain_plan) = plan_opt {
// Phase 286 P3: Pattern8 static box filtering
// Plan extractors are pure (no builder access), so we filter here
// Static box loops with `me.method()` should be handled by ReceiverNormalizeBox, not Pattern8
if entry.name.contains("Pattern8") && builder.comp_ctx.current_static_box.is_some() {
if ctx.debug {
trace::trace().debug(
"route/plan",
&format!("{} extracted but rejected: static box context (fallback to legacy)", entry.name),
);
}
// Skip this pattern, try next extractor
continue;
}
let log_msg = format!("route=plan strategy=extract pattern={}", entry.name);
trace::trace().pattern("route", &log_msg, true);