Apply the new CLAUDE.md "no silent unimplemented arms" rule to the
interp. Every `else => return error.CannotEvalComptime` and
`else => return val` (passthrough) gets a one-line `bailDetail` that
surfaces through `printInterpBailDiag` as
`op=X/X: <reason>` instead of a bare `CannotEvalComptime`.
Tightened sites:
- `.deref` else-arm used to return the operand unchanged for ANY
Value kind. Now: enumerated allow-list (`.aggregate`, `.string`
are legitimate pre-dereferenced values); scalars / handles / undef
/ null bail loudly. Previously, dereffing e.g. a `.boolean`
silently produced a bare `.boolean` and the caller treated it as
a successful deref.
- `.unbox_any` else-arm used to return the operand unchanged for any
non-aggregate. Now: enumerated bails for scalars / handles / void.
An unbox_any whose operand wasn't routed through `box_any` first
is a frontend bug and now shows up as one.
- `.compiler_call` for an unregistered hook silently returned
`CannotEvalComptime`. Now names the missing hook category in the
detail.
- `.length` / `.data_ptr` / `.subslice` / `.array_to_slice` /
`.global_addr` / `.call_indirect` / `struct_get` / `enum_tag` /
`enum_payload` / `unary -` / `field_name_get` / `field_value_get`
/ `objc_msg_send` / `jni_msg_send`: every `else` arm now carries
a specific reason.
- `evalArith` / `evalCmp` use `typeErrorDetail` so mismatched
operand pairs surface "neither both-int nor both-float-coercible"
instead of bare TypeError.
- `callForeign` distinguishes "dlsym error" vs "symbol not found"
vs "> 8 args" instead of returning the same error for all three.
- `execBuiltin` arms for ops the lowering shouldn't have emitted at
comptime (`.cast`, `.type_of`, `.alloc`, `.dealloc`) bail with a
reason instead of a bare error.
154/154 still passing. Behavioural change: the `.deref` /
`.unbox_any` arms used to silently produce a value for Value kinds
they shouldn't have accepted. Any consumer relying on that silent
fall-through now bails — which is the point.