Skip to content
Prev Previous commit
Next Next commit
Refactor compile_bool_op: extract emit_short_circuit_test and unify w…
…ith compile_bool_op_inner

Reduce code duplication by:
- Extracting the repeated Copy + conditional jump pattern into emit_short_circuit_test
- Merging compile_bool_op and compile_bool_op_inner into a single
  compile_bool_op_with_target with an optional short_circuit_target parameter
- Keeping compile_bool_op as a thin wrapper for the public interface

Co-Authored-By: Claude Opus 4.6 <[email protected]>
  • Loading branch information
moreal and claude committed Feb 17, 2026
commit 35706f1661bc772d6d42d7a87b8a1d85cd5ee2db
115 changes: 33 additions & 82 deletions crates/codegen/src/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6611,70 +6611,45 @@ impl Compiler {
/// Compile a boolean operation as an expression.
/// This means, that the last value remains on the stack.
fn compile_bool_op(&mut self, op: &ast::BoolOp, values: &[ast::Expr]) -> CompileResult<()> {
let after_block = self.new_block();
self.compile_bool_op_with_target(op, values, None)
}

/// Compile a boolean operation as an expression, with an optional
/// short-circuit target override. When `short_circuit_target` is `Some`,
/// the short-circuit jumps go to that block instead of the default
/// `after_block`, enabling jump threading to avoid redundant `__bool__` calls.
fn compile_bool_op_with_target(
&mut self,
op: &ast::BoolOp,
values: &[ast::Expr],
short_circuit_target: Option<BlockIdx>,
) -> CompileResult<()> {
let after_block = self.new_block();
let (last_value, values) = values.split_last().unwrap();
let jump_target = short_circuit_target.unwrap_or(after_block);

for value in values {
// Optimization: when a non-last value is a BoolOp with the opposite
// operator, redirect its short-circuit exits to skip the outer's
// redundant __bool__ test (jump threading).
if let ast::Expr::BoolOp(ast::ExprBoolOp {
op: inner_op,
values: inner_values,
..
}) = value
if short_circuit_target.is_none()
&& let ast::Expr::BoolOp(ast::ExprBoolOp {
op: inner_op,
values: inner_values,
..
}) = value
&& inner_op != op
{
let pop_block = self.new_block();
self.compile_bool_op_inner(inner_op, inner_values, Some(pop_block))?;
// Test the inner result for the outer BoolOp
emit!(self, Instruction::Copy { index: 1_u32 });
match op {
ast::BoolOp::And => {
emit!(
self,
Instruction::PopJumpIfFalse {
target: after_block,
}
);
}
ast::BoolOp::Or => {
emit!(
self,
Instruction::PopJumpIfTrue {
target: after_block,
}
);
}
}
self.compile_bool_op_with_target(inner_op, inner_values, Some(pop_block))?;
self.emit_short_circuit_test(op, after_block);
self.switch_to_block(pop_block);
emit!(self, Instruction::PopTop);
continue;
}

self.compile_expression(value)?;

emit!(self, Instruction::Copy { index: 1_u32 });
match op {
ast::BoolOp::And => {
emit!(
self,
Instruction::PopJumpIfFalse {
target: after_block,
}
);
}
ast::BoolOp::Or => {
emit!(
self,
Instruction::PopJumpIfTrue {
target: after_block,
}
);
}
}

self.emit_short_circuit_test(op, jump_target);
emit!(self, Instruction::PopTop);
}

Expand All @@ -6684,42 +6659,18 @@ impl Compiler {
Ok(())
}

/// Compile a boolean operation as an expression, with an optional
/// short-circuit target override. When `short_circuit_target` is `Some`,
/// the short-circuit jumps go to that block instead of the default
/// `after_block`, enabling jump threading to avoid redundant `__bool__` calls.
fn compile_bool_op_inner(
&mut self,
op: &ast::BoolOp,
values: &[ast::Expr],
short_circuit_target: Option<BlockIdx>,
) -> CompileResult<()> {
let after_block = self.new_block();

let (last_value, values) = values.split_last().unwrap();

let target = short_circuit_target.unwrap_or(after_block);

for value in values {
self.compile_expression(value)?;

emit!(self, Instruction::Copy { index: 1_u32 });
match op {
ast::BoolOp::And => {
emit!(self, Instruction::PopJumpIfFalse { target });
}
ast::BoolOp::Or => {
emit!(self, Instruction::PopJumpIfTrue { target });
}
/// Emit `Copy 1` + conditional jump for short-circuit evaluation.
/// For `And`, emits `PopJumpIfFalse`; for `Or`, emits `PopJumpIfTrue`.
fn emit_short_circuit_test(&mut self, op: &ast::BoolOp, target: BlockIdx) {
emit!(self, Instruction::Copy { index: 1_u32 });
match op {
ast::BoolOp::And => {
emit!(self, Instruction::PopJumpIfFalse { target });
}
ast::BoolOp::Or => {
emit!(self, Instruction::PopJumpIfTrue { target });
}

emit!(self, Instruction::PopTop);
}

// If all values did not qualify, take the value of the last value:
self.compile_expression(last_value)?;
self.switch_to_block(after_block);
Ok(())
}

fn compile_dict(&mut self, items: &[ast::DictItem]) -> CompileResult<()> {
Expand Down