Show the bounds check failing, because "checked" without a message says little

The claim worth making is not that there is a check but that a failure names
the line, and the only way to show that is to trip one.
This commit is contained in:
Joseph Ferano 2026-09-12 03:49:41 +07:00
parent 1d206518cf
commit fc47489802
3 changed files with 34 additions and 3 deletions

10
web/examples/bounds.flan Normal file
View File

@ -0,0 +1,10 @@
(defconst xs [3 i32] [1 2 3])
;; (at xs 7) with a literal index does not reach the backend at all: check.ml
;; rejects it. This one goes through a local, so it is the runtime check that
;; catches it — the same message, and the program stops where it happened.
(defn main []
(let [i 7]
(print-line "before")
(print-i64 (i64 (at xs i)))
(print-line "unreachable")))

3
web/examples/bounds.out Normal file
View File

@ -0,0 +1,3 @@
before
bounds.flan:9:28: index 7 is out of bounds for length 3
exit 134

View File

@ -294,10 +294,28 @@ is why <code>(set (.hp p) 8)</code> above is legal when <code>p</code> is a
<h3>Bounds are checked</h3>
<pre><code>(defconst xs [3 i32] [1 2 3])
;; (at xs 7) with a literal index does not reach the backend at all: check.ml
;; rejects it. This one goes through a local, so it is the runtime check that
;; catches it — the same message, and the program stops where it happened.
(defn main []
(let [i 7]
(print-line "before")
(print-i64 (i64 (at xs i)))
(print-line "unreachable")))</code></pre>
<pre><code class="sh">$ flan run bounds.flan
before
bounds.flan:9:28: index 7 is out of bounds for length 3
$ echo $?
134</code></pre>
<p><code>at</code> and <code>slice</code> emit a comparison and a branch to a cold
block that names the source location and stops. A literal index out of bounds is
rejected at compile time instead. Checks are on by default and are not tied to the
optimisation level; <code>--no-bounds-checks</code> turns them off. Measured cost on a
block that names the source location and stops. Checks are on by default and are not
tied to the optimisation level, which is what lets the acceptance table run the same
programs at <code>-O0</code> and <code>-O2</code> with identical checks;
<code>--no-bounds-checks</code> turns them off. Measured cost on a
50-million-iteration dependency chain over a 1024-element array: 0.110.12s checked
against 0.120.13s unchecked.</p>