feat(joinir): string accumulator emitter (JoinIR)
- Add StringAccumulatorEmitter in join_ir/lowering/common/ - Emit string concat as BinOp(Add) for polymorphic VM/LLVM handling - Ensure VM/LLVM same semantics - Fail-Fast: RHS must be Variable (not Literal/MethodCall) - Pattern2 wiring: string carrier昇格 + type refinement + validation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -186,8 +186,9 @@ fn prepare_pattern2_inputs(
|
||||
|
||||
// Phase 100 P2-2: Mutable Accumulator Analysis
|
||||
// Detect accumulator pattern (target = target + x) and promote to carrier
|
||||
// Phase 100 P3-3: Added AccumulatorKind support for string accumulators
|
||||
use crate::mir::loop_pattern_detection::mutable_accumulator_analyzer::{
|
||||
MutableAccumulatorAnalyzer, RhsExprKind,
|
||||
AccumulatorKind, MutableAccumulatorAnalyzer, RhsExprKind,
|
||||
};
|
||||
|
||||
let mutable_spec = MutableAccumulatorAnalyzer::analyze(body)?;
|
||||
@ -221,6 +222,81 @@ fn prepare_pattern2_inputs(
|
||||
)
|
||||
})?;
|
||||
|
||||
// Phase 100 P3-3: Refine AccumulatorKind based on actual target type
|
||||
// AST-only detection (P3-1) defaults to Int for Variables
|
||||
// Here we check actual type from builder's type context
|
||||
let mut refined_kind = spec.kind; // Start with AST-detected kind
|
||||
if spec.rhs_expr_kind == RhsExprKind::Var && refined_kind == AccumulatorKind::Int {
|
||||
// Check if target is string-typed (refine Int → String if needed)
|
||||
use crate::mir::MirType;
|
||||
if let Some(target_type) = builder.type_ctx.value_types.get(target_id) {
|
||||
match target_type {
|
||||
MirType::Box(box_name) if box_name == "StringBox" => {
|
||||
refined_kind = AccumulatorKind::String;
|
||||
if verbose {
|
||||
log.log(
|
||||
"phase100_p3",
|
||||
format!(
|
||||
"Refined accumulator kind: Int → String (target '{}' is StringBox)",
|
||||
spec.target_name
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
MirType::Integer => {
|
||||
// Confirmed Int
|
||||
if verbose {
|
||||
log.log(
|
||||
"phase100_p3",
|
||||
format!(
|
||||
"Confirmed accumulator kind: Int (target '{}' is Integer)",
|
||||
spec.target_name
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Unknown type - keep default Int for backward compat
|
||||
if verbose {
|
||||
log.log(
|
||||
"phase100_p3",
|
||||
format!(
|
||||
"Accumulator kind: Int (default, target '{}' type unknown: {:?})",
|
||||
spec.target_name, target_type
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 100 P3-3: Validate String accumulator constraints
|
||||
if refined_kind == AccumulatorKind::String {
|
||||
// String accumulator RHS must be Variable (not Literal, not MethodCall)
|
||||
match spec.rhs_expr_kind {
|
||||
RhsExprKind::Var => {
|
||||
// OK: Variable RHS is allowed for String accumulators
|
||||
if verbose {
|
||||
log.log(
|
||||
"phase100_p3",
|
||||
format!(
|
||||
"String accumulator '{}' = '{}' + '{}' (Variable RHS: OK)",
|
||||
spec.target_name, spec.target_name, spec.rhs_var_or_lit
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
RhsExprKind::Literal => {
|
||||
// Fail-Fast: Literal RHS not supported in P3 (will be P3.1)
|
||||
return Err(format!(
|
||||
"[joinir/mutable-acc] String accumulator '{}' with Literal RHS not supported in Phase 100 P3 (will be P3.1)",
|
||||
spec.target_name
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check RHS read-only via captured_env lookup
|
||||
// According to spec: x ∈ {Const, BodyLocal, Captured, Pinned, Carrier}
|
||||
// At this point in prepare_pattern2_inputs:
|
||||
|
||||
Reference in New Issue
Block a user