feat(joinir): Phase 224-D - ConditionAlias for promoted variable resolution

- Add ConditionAlias type to CarrierInfo (old_name → carrier_name)
- Record aliases in DigitPosPromoter and TrimPatternInfo
- Resolve aliases in Pattern2 ConditionEnv building
- digit_pos now correctly resolves to is_digit_pos carrier

Fixes "Variable 'digit_pos' not bound in ConditionEnv" error.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-10 18:45:04 +09:00
parent 8e3b55ddec
commit 4e00edcea5
8 changed files with 174 additions and 58 deletions

View File

@ -1,7 +1,7 @@
# Phase 224: A-4 DigitPos Promoter - Implementation Summary
**Date**: 2025-12-10
**Status**: Core Implementation Complete, Integration Requires Additional Work
**Status**: Core Implementation CompletePhase 224-D まで反映済み、init MethodCall は別 Phase
**Branch**: main
**Commits**: TBD
@ -14,8 +14,9 @@ Phase 224 successfully implemented the **DigitPosPromoter** Box for A-4 pattern
**Complete**: DigitPosPromoter implementation with full unit test coverage (6/6 tests passing)
**Complete**: Integration into LoopBodyCondPromoter orchestrator
**Complete**: Two-tier promotion strategy (A-3 Trim → A-4 DigitPos fallback)
**Verified**: Promotion detection working correctly in Pattern2 pipeline
⚠️ **Partial**: Full E2E flow blocked by lowerer integration issue
**Verified**: Promotion detection working correctly in Pattern2/4 pipeline
**Complete** (Phase 224-D): ConditionEnv alias bridge`digit_pos``is_digit_pos`)実装
⚠️ **Partial**: Full E2E flowは body-local init の MethodCall 制約で一部ブロック中
---
@ -61,7 +62,7 @@ Step 2: Try A-4 DigitPos promotion (DigitPosPromoter)
Step 3: Fail-Fast with clear error message
```
**Logs Verify Success**:
**Logs Verify Success(昇格フェーズ)**:
```
[cond_promoter] A-3 Trim promotion failed: No promotable Trim pattern detected
[cond_promoter] Trying A-4 DigitPos promotion...
@ -74,10 +75,10 @@ Step 3: Fail-Fast with clear error message
## Current Limitation: Lowerer Integration Gap
### Problem Statement
### Problem Statement(当初) / Phase 224-D での一部解消
**Symptom**: E2E test fails despite successful promotion
**Root Cause**: `lower_loop_with_break_minimal` performs independent LoopBodyLocal check
**Symptom224 実装直後)**: E2E test fails despite successful promotion
**Root Cause**: `lower_loop_with_break_minimal` performs independent LoopBodyLocal check
**Result**: Promoted variables are detected as "unsupported" by the lowerer
### Error Flow
@ -108,29 +109,32 @@ But for A-4 DigitPos (Phase 223.5), we:
- Merge carrier into CarrierInfo ✅
- **BUT**: Break condition AST still contains `digit_pos`
### Root Cause Analysis
### Root Cause AnalysisPhase 224 時点)
The break condition is an **AST node** containing:
```nyash
if digit_pos < 0 { break }
```
After promotion:
After promotion224 時点):
- CarrierInfo knows about `is_digit_pos` carrier ✅
- LoopBodyCondPromoter recorded the promotion ✅
- **But**: AST node still says `digit_pos`, not `is_digit_pos`
- **But**: AST node still says `digit_pos`, not `is_digit_pos` → ConditionEnv から `digit_pos` が見えない
When lower_loop_with_break_minimal analyzes the condition:
```rust
let cond_scope = LoopConditionScopeBox::analyze(&conditions);
if cond_scope.has_loop_body_local() {
// ERROR: Still sees "digit_pos" in AST!
}
```
Phase 224-D では AST を直接書き換えるのではなく、
**ConditionAliasold_name → carrier_nameを CarrierInfo/ConditionEnv に導入する**ことで
`digit_pos` という名前で条件式から参照された場合も、内部的には `is_digit_pos` carrier を読む」
というブリッジを追加している。
これにより:
- LoopBodyLocal 昇格後に `digit_pos < 0` のような条件があっても、
ConditionEnvBuilder が ConditionAlias を介して `is_digit_pos` の ValueId に解決できるようになった。
- 「LoopBodyLocal が条件にあることによる notbound エラー」は解消され、
**現時点の Blocker は bodylocal init MethodCallsubstring など)の lowering 制約だけ**になった。
---
## Solution Options (Phase 224-continuation)
## Solution Options (Phase 224-continuation 時点の整理)
### Option A: AST Rewriting (Comprehensive)
@ -146,30 +150,26 @@ if cond_scope.has_loop_body_local() {
**Cons**: AST rewriting is complex, error-prone
**Effort**: ~2-3 hours
### Option B: Promoted Variable Tracking (Surgical)
### Option B: Promoted Variable Tracking + ConditionAlias採用済み
**Approach**: Add metadata to track promoted variables, exclude from LoopBodyLocal check
**Approach(決定案)**:
LoopBodyLocal を carrier に昇格した事実を **CarrierInfopromoted_loopbodylocals + ConditionAlias**
メタデータとして記録し、ConditionEnvBuilder 側で「元の変数名 → carrier 名」のエイリアスを解決する。
**Implementation**:
1. Add `promoted_loopbodylocals: Vec<String>` to CarrierInfo
2. In Phase 223.5, record `promoted_var` in CarrierInfo
3. Modify lower_loop_with_break_minimal signature:
```rust
fn lower_loop_with_break_minimal(
...,
promoted_vars: &[String], // NEW
) -> Result<...>
```
4. In LoopConditionScopeBox::analyze(), filter out promoted_vars:
```rust
if cond_scope.has_loop_body_local_except(promoted_vars) {
// Only error if non-promoted LoopBodyLocal exists
}
```
実装Phase 224-cont / 224-D:
1. `CarrierInfo` `promoted_loopbodylocals: Vec<String>` `condition_aliases: Vec<ConditionAlias>` を追加。
2. LoopBodyCondPromoterTrim/DigitPos の両方)で昇格成功時に
`promoted_loopbodylocals.push("digit_pos")`
`condition_aliases.push(ConditionAlias { old_name: "digit_pos", carrier_name: "is_digit_pos" })` を記録。
3. Pattern2/4 lowerer は ConditionEnvBuilder v2 を呼ぶ際に `&carrier_info.condition_aliases` を渡す。
4. ConditionEnvBuilder は `var_name == "digit_pos"` のような未解決変数を見つけた場合、
ConditionAlias を使って `carrier_name == "is_digit_pos"` に解決し、その ValueId を Condition 役の Param としてバインド。
**Pros**: Minimal changes, surgical fix
**Cons**: Adds parameter to lowerer API
**Effort**: ~1-2 hours
効果:
- LoopBodyLocal 条件パターンA-3 Trim/A-4 DigitPosは、
**AST 書き換えなしで「条件式から見える名前」と「carrier 実体」を橋渡しできる**
- Pattern2/4 や LoopConditionScopeBox は「昇格済み LoopBodyLocal」とそれ以外を区別できるようになり、
不要な FailFast を避けつつ、未昇格の LoopBodyLocal には引き続き厳格に対応できる。
### Option C: DigitPosLoopHelper Metadata (Consistent)

View File

@ -341,7 +341,8 @@ Local Region (1000+):
- **Two-tier promotion**: Step1 で A-3 Trim 試行 → 失敗なら Step2 で A-4 DigitPos 試行 → 両方失敗で Fail-Fast。
- **DigitPosPromoter 統合**: cascading indexOf パターンsubstring → indexOf → comparisonの昇格をサポート。
- **Unit test 完全成功**: 6/6 PASSpromoter 自体は完璧動作)。
- **Lowerer Integration Gap**: lower_loop_with_break_minimal が昇格済み変数を認識せず、独立チェックでエラー検出Phase 224-continuation で対応予定)
- **Phase 224-D**: ConditionAlias/CarrierInfo との連携により、昇格済み LoopBodyLocal 名(`digit_pos` 等)を ConditionEnv から見えるようにブリッジ
- **残りの制約**: body-local init の MethodCall`substring` 等)の lowering は Phase 193/224-B/C のスコープ外で、今後の Phase で対応。
- 設計原則:
- **Thin coordinator**: 専門 PromoterLoopBodyCarrierPromoter / DigitPosPromoterに昇格ロジックを委譲。
- **Pattern-agnostic**: Pattern2 (break) / Pattern4 (continue) の統一入口として機能。