fix(lang): a function named like a compiler built-in is refused; reseed

A program's own `run` was never called: every call to it lowered to the
built-in System.run (C's system()), and clang failed on the IR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-24 22:09:29 +03:00
parent ae61e99e06
commit 3d2a103dfb
6 changed files with 10686 additions and 10500 deletions

View file

@ -120,7 +120,8 @@ Screens are drawn through a registered renderer. `Value` gains a float kind.
Also:
- A program's function named like one of the runtime's is refused; it had been silently taking the
runtime's own calls.
runtime's own calls. So is one named like a compiler built-in (`run`, `exit`, `free`, `fill`,
...): every call to a program's own `run` compiled into C's `system()`, and clang failed on the IR.
- An index is evaluated before the slice's elements are read. A `xs[f()]` whose `f` grew `xs`
read stale memory.
- A runtime error names the file its expression is in, not the program's.

View file

@ -0,0 +1,7 @@
# builtin_name.ludic - a function named like a compiler built-in. `run` is the low-level System.run
# (C's system()): every call to a program's own `run` compiled into that instead, and the program
# failed in clang with a type error in the IR. (Rejected on purpose: tools/ludic-cli/test.ludic.)
program BuiltinName {
function run(hz: int) -> string { return `{hz}` }
entry { print(run(60)) }
}

View file

@ -148,8 +148,15 @@ function ck_listener(l: Node) -> void {
ck_pop(m)
}
# a program's function named like one of the runtime's takes every call the runtime makes to its
# own - the runtime's ui_measure started answering to a package's - so the name is refused
# own - the runtime's ui_measure started answering to a package's - so the name is refused; one
# named like a compiler built-in never ran at all (every call to `run` was C's system()), so too
function ck_runtime_shadows() -> void {
var u = 0
while u < g_prog_user_end {
let d = prog[u]
if d.kind == N_FN and (is_intrinsic(d.s) or is_intrinsic2(d.s)) { ck_err("shadow", d, `{d.s} is a built-in of the compiler, and a call to it would never reach this function; choose another name`) }
u += 1
}
var r = g_prog_user_end
while r < len(prog) {
let d = prog[r]

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -717,6 +717,7 @@ function cmd_dev_test() -> int {
feat_case("events/answer", "", "10 20 0", "answer.ludic (a listener's return ends that listener, not the dispatch)")
reject_case("rejected/duplicate_const", "'KEY_LEFT' is defined twice", "a const defined twice is refused, naming both places")
reject_case("rejected/duplicate_property", "'Look' is defined twice", "a property defined twice is refused")
reject_case("rejected/builtin_name", "run is a built-in of the compiler", "a function named like a compiler built-in (run, exit, free...) is refused")
reject_case("rejected/redeclared_local", "'v0' is declared twice in this block", "a local declared twice in one block is refused")
reject_case("rejected/missing_return", "can reach its end without returning", "a function that can run off its end without its result is refused")
feat_case("functions/values", "", "42 10 25 49 81 1.5 1", "values.ludic (L2: fn types, fn name, calls through a local, global, field, element, parameter, result)")