Joseph Ferano 2ec12c064d handler-bind has a value, and both backends now say the same one
(defn compute [] i64 (handler-bind [...] (risky))) printed 0 through LLVM
and 2 through --x86, and neither was the restart's answer. The divergence
was real and the cause was in neither backend: check_handler_bind wrote
[ignore want] and typed the form Unit, so a unit in value position was
never checked against the expectation that would have refused it. Both
lowerings then answered a caller that had no business asking -- emit.ml a
literal zeroinitializer, x86.ml whatever the body's last form had left in
the destination slot. One of those looked like a value.

Unit was the wrong answer anyway. Every use of handler-bind in value
position in this repository -- restarts.flan, cleanup.flan,
p6-transfer.flan, p10-defer-transfer.flan -- writes it as a restart-case
body, where §3 requires the body and the clauses to agree in type; making
the form unit refuses all four. So it takes with-allocator's shape, which
is the same shape for the same reason: the body's last form is the value,
threaded through [expect] like any other. handler-case, whose value is the
handler's rather than the body's, is untouched and still refused by name in
parse.ml -- that difference is the whole of what separates the two, and it
is not this one.

emit.ml returns [last] with no phi and no slot: the pad terminates at
current_pad and never at the join, so the join has one predecessor and the
body's value dominates it. x86.ml needed no change at all -- it had been
passing dst and the type through to the body all along.

p12-handler-value.flan is the shape the survey could not see, plus the
neighbours a divergence usually travels with: a clause parameter, nested
restart-cases, a defer between the signal and the restart-case, and f64
and string across the transfer. All six already agreed; the handler-bind
value was alone. @x86 MATCH 128 -> 129, DIFFER 0.
2026-09-19 10:14:07 +07:00
..