feat(joinir): Phase 171-C-2 Trim pattern detection in LoopBodyCarrierPromoter
Implements the Trim pattern detection logic for carrier promotion:
- find_definition_in_body(): Iterative AST traversal to locate variable definitions
- is_substring_method_call(): Detects substring() method calls
- extract_equality_literals(): Extracts string literals from OR chains (ch == " " || ch == "\t")
- TrimPatternInfo: Captures detected pattern details for carrier promotion
This enables Pattern 5 to detect trim-style loops:
```hako
loop(start < end) {
local ch = s.substring(start, start+1)
if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" {
start = start + 1
} else {
break
}
}
```
Unit tests cover:
- Simple and nested definition detection
- substring method call detection
- Single and chained equality literal extraction
- Full Trim pattern detection with 2-4 whitespace characters
Next: Phase 171-C-3 integration with Pattern 2/4 routing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -198,6 +198,34 @@ Pattern 2 supports only loop parameters and outer-scope variables.
|
||||
|
||||
**Approach**:
|
||||
1. Detect loop-body-local variable patterns
|
||||
|
||||
---
|
||||
|
||||
## Bug Fix Note(Phase 170-D-impl-2+)
|
||||
|
||||
Phase 166 再観測中に、JsonParserBox._parse_object(s, pos) の `s`(関数パラメータ)が
|
||||
LoopBodyLocal と誤判定される致命的バグが見つかった。
|
||||
|
||||
- 原因: `is_outer_scope_variable()` が `body_locals` を参照せず、
|
||||
`pinned` / `variable_definitions` に無い変数を「LoopBodyLocal 寄り」とみなしていた
|
||||
- 影響: 本来 Pattern2/4 でサポートすべき `loop(p < s.length())` 形式のループが
|
||||
「loop-body-local 変数使用」として UnsupportedPattern エラーになっていた
|
||||
|
||||
修正方針と実装(概略):
|
||||
|
||||
- 先に `LoopScopeShape.body_locals` を確認し、ここに含まれる変数だけを LoopBodyLocal とみなす
|
||||
- `variable_definitions` にエントリがあり、header/latch 以外で定義される変数も LoopBodyLocal とみなす
|
||||
- 上記いずれにも該当しない変数(関数パラメータや外側ローカル)は OuterLocal として扱う
|
||||
|
||||
これにより:
|
||||
|
||||
- 関数パラメータ `s`, `pos` 等は正しく OuterLocal と分類され、
|
||||
JsonParser/Trim 系の「素直な while ループ」は Pattern2/4 の対象に戻る
|
||||
- 本当にループ内で導入された変数(例: `local ch = ...`)は LoopBodyLocal のまま検出され、
|
||||
今後の Pattern5+ の設計対象として切り出される
|
||||
|
||||
詳細な実装は `src/mir/loop_pattern_detection/condition_var_analyzer.rs` の
|
||||
`is_outer_scope_variable()` および付随ユニットテストに記録されている。
|
||||
2. Expand LoopConditionScope with additional heuristics
|
||||
3. Implement selective patterns (e.g., local x = ...; while(x < N))
|
||||
4. Reuse LoopConditionScope infrastructure
|
||||
@ -323,19 +351,110 @@ Finished `release` profile [optimized] target(s) in 1m 08s
|
||||
- `test_scope_header_and_latch_variable`: Carrier variable classification (COMPLETED)
|
||||
- `test_scope_priority_in_add_var`: Scope priority validation (BONUS)
|
||||
|
||||
## Bug Fix: Function Parameter Misclassification (2025-12-07)
|
||||
|
||||
### Issue
|
||||
|
||||
Function parameters (e.g., `s`, `pos` in JsonParser methods) were incorrectly classified as **LoopBodyLocal** when used in loop conditions or break guards.
|
||||
|
||||
### Root Cause
|
||||
|
||||
In `condition_var_analyzer.rs`, the `is_outer_scope_variable()` function's default case (lines 175-184) was treating unknown variables (not in `variable_definitions`) as body-local variables.
|
||||
|
||||
**Problem Logic**:
|
||||
```rust
|
||||
// OLD (buggy): Unknown variables defaulted to LoopBodyLocal
|
||||
if let Some(def_blocks) = scope.variable_definitions.get(var_name) {
|
||||
// (carrier detection...)
|
||||
return false; // body-local
|
||||
}
|
||||
// No default case → implicit false → LoopBodyLocal
|
||||
false // ❌ BUG: function parameters have no definition, so defaulted to body-local
|
||||
```
|
||||
|
||||
**Why function parameters appear "unknown"**:
|
||||
- Function parameters (`s`, `pos`) are not defined in the loop body
|
||||
- They don't appear in `variable_definitions` (which only tracks loop-internal definitions)
|
||||
- Without explicit handling, they were incorrectly treated as body-local
|
||||
|
||||
### Fix
|
||||
|
||||
**File**: `src/mir/loop_pattern_detection/condition_var_analyzer.rs` (lines 175-184)
|
||||
|
||||
```rust
|
||||
// NEW (fixed): Unknown variables default to OuterLocal (function parameters)
|
||||
if let Some(def_blocks) = scope.variable_definitions.get(var_name) {
|
||||
// (carrier detection logic...)
|
||||
return false; // body-local
|
||||
}
|
||||
|
||||
// At this point:
|
||||
// - Variable is NOT in body_locals
|
||||
// - No explicit definition info
|
||||
// This typically means "function parameter" or "outer local"
|
||||
true // ✅ FIX: Default to OuterLocal for function parameters
|
||||
```
|
||||
|
||||
**Key Change**: Default unknown variables to `OuterLocal` instead of implicitly defaulting to `LoopBodyLocal`.
|
||||
|
||||
### Impact
|
||||
|
||||
**Before Fix**:
|
||||
- ❌ JsonParser loops incorrectly rejected: "Variable 's' uses loop-body-local variables"
|
||||
- ❌ Function parameters treated as LoopBodyLocal
|
||||
- ❌ Valid Pattern 2 loops blocked by misclassification
|
||||
|
||||
**After Fix**:
|
||||
- ✅ Function parameters correctly classified as OuterLocal
|
||||
- ✅ JsonParser loops pass variable scope validation
|
||||
- ✅ LoopBodyLocal `ch` (defined with `local ch = ...`) correctly rejected
|
||||
- ⚠️ New blockers: Method calls in loops (Pattern 5+ features, not bugs)
|
||||
|
||||
### Verification
|
||||
|
||||
**Test Results**:
|
||||
|
||||
1. **Function Parameter Loop** (`/tmp/test_jsonparser_simple.hako`):
|
||||
```
|
||||
✅ [joinir/pattern2] Phase 170-D: Condition variables verified: {"pos", "s", "len"}
|
||||
⚠️ Error: MethodCall .substring() not supported (Pattern 5+ feature)
|
||||
```
|
||||
**Analysis**: Variable classification fixed, error now about method calls (separate issue)
|
||||
|
||||
2. **LoopBodyLocal in Break** (`test_trim_main_pattern.hako`):
|
||||
```
|
||||
✅ [joinir/pattern2] Phase 170-D: Condition variables verified: {"ch", "end", "start"}
|
||||
❌ [ERROR] Variable 'ch' not bound in ConditionEnv
|
||||
```
|
||||
**Analysis**: Correctly rejects `ch` (defined as `local ch = ...` inside loop)
|
||||
|
||||
**Documentation**: See [phase170-d-fix-verification.md](phase170-d-fix-verification.md) for comprehensive test results.
|
||||
|
||||
### Lessons Learned
|
||||
|
||||
**Design Principle**: When classifying variables in scope analysis:
|
||||
1. **Check explicit markers first** (`body_locals`, `pinned`)
|
||||
2. **Analyze definition locations** (`variable_definitions`)
|
||||
3. **Default to OuterLocal** for unknowns (function parameters, globals)
|
||||
|
||||
**Fail-Fast Philosophy**: The bug fix maintains fail-fast behavior while being **less strict** about unknown variables - treating them as safer (OuterLocal) rather than more restrictive (LoopBodyLocal).
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Phase 170-D-impl-4 Completion**:
|
||||
1. **Phase 170-D-impl-4 Completion** ✅:
|
||||
- Update CURRENT_TASK.md with completion markers
|
||||
- Create integration test .hako files for unsupported patterns
|
||||
- Run full regression test suite
|
||||
|
||||
2. **Documentation**:
|
||||
2. **Documentation** ✅:
|
||||
- Update loop pattern documentation index
|
||||
- Add quick reference for Phase 170-D validation
|
||||
- Bug fix verification document
|
||||
|
||||
3. **Future Work** (Phase 170-D-E):
|
||||
- Pattern 5+ for loop-body-local variable support
|
||||
- Extended scope heuristics
|
||||
- Condition simplification analysis
|
||||
|
||||
- Method call support in loop conditions
|
||||
|
||||
Reference in New Issue
Block a user