Recognize early return guard patterns in dominance analysis
This improves the basic-block-local dominance analysis to recognize
common "early return guard" patterns like `x === nothing && return
nothing`.
Variables assigned after such patterns no longer require Box allocation
because the subsequent code is guaranteed to execute if we reach it.
The `&&` and `||` operators are desugared to `if` expressions before
scope analysis. For example:
- `x && return` becomes `if x; return; else false; end`
- `x || return` becomes `if x; x; else return; end`
The new `is_early_return_guard` function detects these patterns by
checking if exactly one branch of an `if` expression is an early exit
(return/throw/break/continue).
This is a workaround for the fact that dominance analysis is performed
on tree-structured IR before linearization, where proper dominance
analysis would be straightforward. A more robust solution would be to
perform this analysis after `linearize_ir`, as flisp does.