b5a0a729e6
El SDK CI - dev / build-and-test (pull_request) Failing after 14m49s
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.
29 lines
1.4 KiB
EmacsLisp
29 lines
1.4 KiB
EmacsLisp
fn getstr(x: String) -> String { return x }
|
|
fn getint(x: Int) -> Int { return x }
|
|
fn ok(label: String) -> Void { println("ok " + label) }
|
|
fn bad(label: String) -> Void { println("FAIL " + label) }
|
|
|
|
let s1: String = "hello"
|
|
let s2: String = "hello"
|
|
let s3: String = "world"
|
|
let i1: Int = 5
|
|
let i2: Int = 5
|
|
let i3: Int = 9
|
|
|
|
if "abc" == "abc" { ok("str literal eq") } else { bad("str literal eq") }
|
|
if "abc" == "xyz" { bad("str literal ne") } else { ok("str literal ne") }
|
|
if s1 == s2 { ok("str var eq") } else { bad("str var eq") }
|
|
if s1 == s3 { bad("str var ne") } else { ok("str var ne") }
|
|
if getstr("hi") == "hi" { ok("str call vs literal") } else { bad("str call vs literal") }
|
|
if s1 == getstr("hello") { ok("str var vs call") } else { bad("str var vs call") }
|
|
if s1 == getstr("nope") { bad("str var vs call ne") } else { ok("str var vs call ne") }
|
|
if i1 == i2 { ok("int var eq") } else { bad("int var eq") }
|
|
if i1 == i3 { bad("int var ne") } else { ok("int var ne") }
|
|
if getint(5) == i1 { ok("int call vs var") } else { bad("int call vs var") }
|
|
if getint(9) == i1 { bad("int call vs var ne") } else { ok("int call vs var ne") }
|
|
if s1 != s3 { ok("str NOTEQ") } else { bad("str NOTEQ") }
|
|
if s1 != s2 { bad("str NOTEQ same") } else { ok("str NOTEQ same") }
|
|
if i1 != i3 { ok("int NOTEQ") } else { bad("int NOTEQ") }
|
|
if getint(9) != i1 { ok("int call NOTEQ") } else { bad("int call NOTEQ") }
|
|
println("done")
|