fix: Resolve MIR phi value bug and HTTP error handling

- Fix MIR builder to correctly return phi values in if-else statements
  - Add extract_assigned_var helper to handle Program blocks
  - Update variable mapping after phi node creation
  - Fixes 'Value %14 not set' error in e2e_vm_http_client_error_result

- Fix HTTP plugin error handling for connection failures
  - Return error string instead of handle on tcp_ok=false
  - Enable proper ResultBox(Err) creation for failed connections
  - Now r.isOk() correctly returns false for connection errors

- Add VM fallback for toString() on any Box type
  - Ensures error messages can be displayed even without specific implementation

- All e2e_vm_http_client_error_result tests now pass

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm
2025-08-23 06:51:49 +09:00
parent 3b03d001ba
commit 494a864ed2
5 changed files with 123 additions and 8 deletions

View File

@ -523,6 +523,8 @@ impl MirBuilder {
// Build then branch
self.current_block = Some(then_block);
self.ensure_block_exists(then_block)?;
// Keep a copy of AST for analysis (phi for variable reassignment)
let then_ast_for_analysis = then_branch.clone();
let then_value = self.build_expression(then_branch)?;
if !self.is_current_block_terminated() {
self.emit_instruction(MirInstruction::Jump { target: merge_block })?;
@ -531,8 +533,9 @@ impl MirBuilder {
// Build else branch
self.current_block = Some(else_block);
self.ensure_block_exists(else_block)?;
let else_value = if let Some(else_ast) = else_branch {
self.build_expression(else_ast)?
let (else_value, else_ast_for_analysis) = if let Some(else_ast) = else_branch {
let val = self.build_expression(else_ast.clone())?;
(val, Some(else_ast))
} else {
// No else branch, use void
let void_val = self.value_gen.next();
@ -540,7 +543,7 @@ impl MirBuilder {
dst: void_val,
value: ConstValue::Void,
})?;
void_val
(void_val, None)
};
if !self.is_current_block_terminated() {
self.emit_instruction(MirInstruction::Jump { target: merge_block })?;
@ -558,9 +561,33 @@ impl MirBuilder {
(else_block, else_value),
],
})?;
// Heuristic: If both branches assign the same variable name, bind that variable to the phi result
let assigned_var_then = Self::extract_assigned_var(&then_ast_for_analysis);
let assigned_var_else = else_ast_for_analysis.as_ref().and_then(|a| Self::extract_assigned_var(a));
if let (Some(a), Some(b)) = (assigned_var_then, assigned_var_else) {
if a == b {
self.variable_map.insert(a, result_val);
}
}
Ok(result_val)
}
/// Extract assigned variable name from an AST node if it represents an assignment to a variable.
/// Handles direct Assignment and Program with trailing single-statement Assignment.
fn extract_assigned_var(ast: &ASTNode) -> Option<String> {
match ast {
ASTNode::Assignment { target, .. } => {
if let ASTNode::Variable { name, .. } = target.as_ref() { Some(name.clone()) } else { None }
}
ASTNode::Program { statements, .. } => {
// Inspect the last statement as the resulting value of the block
statements.last().and_then(|st| Self::extract_assigned_var(st))
}
_ => None,
}
}
/// Emit an instruction to the current basic block
pub(super) fn emit_instruction(&mut self, instruction: MirInstruction) -> Result<(), String> {