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:
@ -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;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,15 +124,22 @@ pub fn emit_carrier_update_with_env(
|
||||
)
|
||||
})?
|
||||
}
|
||||
// Phase 178: String updates detected but not lowered to JoinIR yet
|
||||
// The Rust MIR path handles string concatenation
|
||||
// For JoinIR: just pass through the carrier param (no JoinIR update)
|
||||
UpdateRhs::StringLiteral(_) | UpdateRhs::Other => {
|
||||
eprintln!(
|
||||
"[joinir/pattern2] Phase 178: Carrier '{}' has string/complex update - skipping JoinIR emit, using param passthrough",
|
||||
// Phase 188: String updates now emit JoinIR BinOp
|
||||
// StringAppendLiteral: s = s + "literal"
|
||||
UpdateRhs::StringLiteral(s) => {
|
||||
let const_id = alloc_value();
|
||||
instructions.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: const_id,
|
||||
value: ConstValue::String(s.clone()),
|
||||
}));
|
||||
const_id
|
||||
}
|
||||
// Phase 178/188: Complex updates (method calls) still rejected
|
||||
UpdateRhs::Other => {
|
||||
return Err(format!(
|
||||
"Carrier '{}' has complex update (UpdateRhs::Other) - should be rejected by can_lower()",
|
||||
carrier.name
|
||||
);
|
||||
return Ok(carrier_param); // Pass-through: no JoinIR update
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
@ -259,15 +266,22 @@ pub fn emit_carrier_update(
|
||||
)
|
||||
})?
|
||||
}
|
||||
// Phase 178: String updates detected but not lowered to JoinIR yet
|
||||
// The Rust MIR path handles string concatenation
|
||||
// For JoinIR: just pass through the carrier param (no JoinIR update)
|
||||
UpdateRhs::StringLiteral(_) | UpdateRhs::Other => {
|
||||
eprintln!(
|
||||
"[joinir/pattern2] Phase 178: Carrier '{}' has string/complex update - skipping JoinIR emit, using param passthrough",
|
||||
// Phase 188: String updates now emit JoinIR BinOp
|
||||
// StringAppendLiteral: s = s + "literal"
|
||||
UpdateRhs::StringLiteral(s) => {
|
||||
let const_id = alloc_value();
|
||||
instructions.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: const_id,
|
||||
value: ConstValue::String(s.clone()),
|
||||
}));
|
||||
const_id
|
||||
}
|
||||
// Phase 178/188: Complex updates (method calls) still rejected
|
||||
UpdateRhs::Other => {
|
||||
return Err(format!(
|
||||
"Carrier '{}' has complex update (UpdateRhs::Other) - should be rejected by can_lower()",
|
||||
carrier.name
|
||||
);
|
||||
return Ok(carrier_param); // Pass-through: no JoinIR update
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user