codegen: Bool is int-like, so Bool comparisons stop lowering to str_eq #138

Merged
will.anderson merged 1 commits from fix/bool-is-int-like into dev 2026-08-16 02:54:35 +00:00
Owner
fn check(label: String, cond: Bool, want: Bool) -> Void {
    if cond == want { ... }     ->  if (str_eq(cond, want))   // SIGSEGV
}

Bool has always been an integer in the value model — type_to_c maps Bool → "int", and el_runtime.h says "Bool -> el_val_t (0 = false, nonzero = true)". But Bool names were registered nowhere: params tracked Int and Float, let tracked Int and Float. Neither knew about Bool.

So comparing two Bools fell through to str_eq, dereferencing 0 or 1 as a char*.

Third instance of one family tonight, after #137 (a call on either side of == poisoned the operator) and #136 (a missing import compiled clean). Same shape each time: something the compiler couldn't type, silently handled as a string.

Found while writing #137's own test harness — the first version crashed on exactly this, on both old and new compilers. A test harness that can't compare two Bools is a good way to notice.

Verified:

  • the harness that segfaulted on every prior compiler (exit 139, no output) now runs clean: 14 passed, 0 failed
  • self-hosting fixpoint byte-identical
  • compiler's own generated C differs by 8 lines — only the intended registration
  • neuron's soul amalgam regenerates in 424 ms, exit 0, byte-identical
  • test_math 13/13, test_string 27/27, test_core 10/10, test_text 12/12

Adds tests/runtime/operator_typing_test.el so this family is covered going forward rather than rediscovered.

```el fn check(label: String, cond: Bool, want: Bool) -> Void { if cond == want { ... } -> if (str_eq(cond, want)) // SIGSEGV } ``` Bool has always been an integer in the value model — `type_to_c` maps `Bool → "int"`, and `el_runtime.h` says *"Bool -> el_val_t (0 = false, nonzero = true)"*. But Bool names were registered **nowhere**: params tracked Int and Float, `let` tracked Int and Float. Neither knew about Bool. So comparing two Bools fell through to `str_eq`, dereferencing 0 or 1 as a `char*`. **Third instance of one family tonight**, after #137 (a call on either side of `==` poisoned the operator) and #136 (a missing import compiled clean). Same shape each time: something the compiler couldn't type, silently handled as a string. Found while writing #137's own test harness — the first version crashed on exactly this, on both old and new compilers. A test harness that can't compare two Bools is a good way to notice. **Verified:** - the harness that segfaulted on every prior compiler (exit 139, no output) now runs clean: **14 passed, 0 failed** - self-hosting fixpoint **byte-identical** - compiler's own generated C differs by **8 lines** — only the intended registration - neuron's soul amalgam regenerates in 424 ms, exit 0, **byte-identical** - test_math 13/13, test_string 27/27, test_core 10/10, test_text 12/12 Adds `tests/runtime/operator_typing_test.el` so this family is covered going forward rather than rediscovered.
will.anderson added 1 commit 2026-08-16 02:54:13 +00:00
codegen: Bool is int-like, so Bool comparisons stop lowering to str_eq
El SDK CI - dev / build-and-test (pull_request) Failing after 14m49s
b5a0a729e6
fn check(label: String, cond: Bool, want: Bool) -> Void {
        if cond == want { ... }        ->  if (str_eq(cond, want))   SIGSEGV
    }

Bool has always been an integer in the value model — type_to_c maps Bool to
"int", and el_runtime.h states "Bool -> el_val_t (0 = false, nonzero = true)".
But Bool names were registered NOWHERE: build_int_names_for_params tracked Int
and Float params, and the `let` path tracked Int and Float bindings. Neither
knew about Bool.

So comparing two Bools fell through to str_eq, which dereferenced 0 or 1 as a
char* and segfaulted immediately.

This is the third instance of one family found tonight, after el #137 (a call
on either side of == poisoned the operator) and el #136 (a missing import
compiled clean). All three are the same shape: something the compiler could not
type, silently handled as a string.

Found while writing #137's own test harness — the first version of that harness
crashed on exactly this, on both the old and new compiler, which is how it
surfaced. A test harness that cannot compare two Bools is a good way to notice.

VERIFIED:
  - the harness that segfaulted on every prior compiler (exit 139, no output)
    now runs clean: 14 passed, 0 failed
  - self-hosting fixpoint byte-identical
  - the compiler's own generated C differs by 8 lines — only the intended
    registration
  - neuron's full soul amalgam regenerates in 424ms, exit 0, BYTE-IDENTICAL
  - test_math 13/13, test_string 27/27, test_core 10/10, test_text 12/12

Adds tests/runtime/operator_typing_test.el, the 15-case suite from #137, so
this family is covered going forward rather than rediscovered.
will.anderson merged commit 63fe8a766d into dev 2026-08-16 02:54:35 +00:00
Sign in to join this conversation.