feat(joinir): Phase 188 StringAppend support in Pattern2/4

- Extended Pattern2/4 whitelist to accept StringLiteral updates
- CarrierUpdateEmitter now emits JoinIR for string append
- Selective Fail-Fast: accept safe patterns, reject complex

Changes:
- pattern2_with_break.rs: StringLiteral whitelist
- pattern4_with_continue.rs: StringLiteral whitelist
- carrier_update_emitter.rs: StringLiteral JoinIR emission

Tests:
- phase188_string_append_char.hako
- phase188_string_append_literal.hako
- 10/10 carrier_update_emitter tests PASS

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-09 01:09:54 +09:00
parent d4231f5d3a
commit a2933880ae
8 changed files with 160 additions and 32 deletions

View File

@ -57,7 +57,8 @@ pub fn can_lower(_builder: &MirBuilder, ctx: &super::router::LoopPatternContext)
return false;
}
// Phase 178: Check for string/complex carrier updates
// Phase 178/188: Check for complex carrier updates
// Phase 188: StringAppendChar/StringAppendLiteral are now allowed
// Create dummy carriers from body assignment targets for analysis
let dummy_carriers: Vec<CarrierVar> = ctx.body.iter().filter_map(|node| {
match node {
@ -78,15 +79,27 @@ pub fn can_lower(_builder: &MirBuilder, ctx: &super::router::LoopPatternContext)
let updates = LoopUpdateAnalyzer::analyze_carrier_updates(ctx.body, &dummy_carriers);
// Check if any update is string/complex
// Phase 188: Check if any update is complex (reject only UpdateRhs::Other)
// Allow: Const (numeric), Variable (numeric/string), StringLiteral
// Reject: Other (method calls, nested BinOp)
for update in updates.values() {
if let UpdateExpr::BinOp { rhs, .. } = update {
match rhs {
UpdateRhs::StringLiteral(_) | UpdateRhs::Other => {
eprintln!("[pattern2/can_lower] Phase 178: String/complex update detected, rejecting Pattern 2 (unsupported)");
UpdateRhs::Const(_) => {
// Numeric: i = i + 1 (allowed)
}
UpdateRhs::Variable(_) => {
// Phase 188: StringAppendChar: s = s + ch (allowed)
// Or numeric: sum = sum + i (allowed)
}
UpdateRhs::StringLiteral(_) => {
// Phase 188: StringAppendLiteral: s = s + "x" (allowed)
}
UpdateRhs::Other => {
// Phase 188: Complex update (method call, nested BinOp) - reject
eprintln!("[pattern2/can_lower] Phase 188: Complex update detected (UpdateRhs::Other), rejecting Pattern 2");
return false;
}
_ => {}
}
}
}

View File

@ -70,7 +70,8 @@ pub fn can_lower(_builder: &MirBuilder, ctx: &super::router::LoopPatternContext)
return false;
}
// Phase 178: Check for string/complex carrier updates
// Phase 178/188: Check for complex carrier updates
// Phase 188: StringAppendChar/StringAppendLiteral are now allowed
// Create dummy carriers from body assignment targets for analysis
let dummy_carriers: Vec<CarrierVar> = ctx.body.iter().filter_map(|node| {
match node {
@ -91,15 +92,27 @@ pub fn can_lower(_builder: &MirBuilder, ctx: &super::router::LoopPatternContext)
let updates = LoopUpdateAnalyzer::analyze_carrier_updates(ctx.body, &dummy_carriers);
// Check if any update is string/complex
// Phase 188: Check if any update is complex (reject only UpdateRhs::Other)
// Allow: Const (numeric), Variable (numeric/string), StringLiteral
// Reject: Other (method calls, nested BinOp)
for update in updates.values() {
if let UpdateExpr::BinOp { rhs, .. } = update {
match rhs {
UpdateRhs::StringLiteral(_) | UpdateRhs::Other => {
eprintln!("[pattern4/can_lower] Phase 178: String/complex update detected, rejecting Pattern 4 (unsupported)");
UpdateRhs::Const(_) => {
// Numeric: i = i + 1 (allowed)
}
UpdateRhs::Variable(_) => {
// Phase 188: StringAppendChar: s = s + ch (allowed)
// Or numeric: sum = sum + i (allowed)
}
UpdateRhs::StringLiteral(_) => {
// Phase 188: StringAppendLiteral: s = s + "x" (allowed)
}
UpdateRhs::Other => {
// Phase 188: Complex update (method call, nested BinOp) - reject
eprintln!("[pattern4/can_lower] Phase 188: Complex update detected (UpdateRhs::Other), rejecting Pattern 4");
return false;
}
_ => {}
}
}
}