The direction a container-fixed binding admits, pinned

A narrower scalar at a $t a slice already fixed widens into the fixed
type — the same cast a monomorphic parameter applies — where the old
rule refused both directions. One accepts pin, one runtime line in
int-generic.flan, and the web page's predicate table catches up: five
predicates, integer? at the head, and the entailment chain grown one
link.
This commit is contained in:
Joseph Ferano 2026-09-20 21:48:39 +07:00
parent f71cc40bb5
commit cdda829835
4 changed files with 29 additions and 7 deletions

View File

@ -101,4 +101,12 @@
;; A literal beside a wider variable joins too: 4 arrives as an i32 and the
;; copy is i64's.
(let [w (i64 38)]
(println (tri w 3 1))))
(println (tri w 3 1)))
;; And the one direction a container-bound variable does admit: the slice
;; fixed $t at i32 exactly, and a narrower scalar widens *into* that — the
;; same conversion a monomorphic i32 parameter would apply. (The reverse,
;; an i64 scalar against this slice, stays refused; the checker pins it.)
(let [ns [5 3 9 1]]
(match (index-of (slice ns 0 4) (i16 9))
(Some i) (println i)
_ (println -1))))

View File

@ -2652,12 +2652,14 @@ let () =
spells. Then the integer?-only operations at several widths, and last
the join family: [true true], [6 6] and [42] are mixed widths at one
$t answering identically in both argument orders, from one copy at
the wider type (FIX.org 2026-09-20). *)
the wider type (FIX.org 2026-09-20). The closing [2] is an i16 scalar
widening into the i32 a slice fixed index-of's $t at the one
direction a container-bound variable admits. *)
let int_generic_out =
"7\n7\n7\n7\n7\n7\n-2147483648\n-9223372036854775808\n\
0\n0\n1.5\n2.5\n\
7\n15\n31\ntrue\nfalse\ntrue\n240\n9\n5\n-2\n301\n301\n\
true\ntrue\n6\n6\n42\n"
true\ntrue\n6\n6\n42\n2\n"
in
outputs "integer? and the collapsed abs" "programs/int-generic.flan"
int_generic_out;

View File

@ -5030,6 +5030,14 @@ let () =
"(defn main [] () (let [ns [5 3 9 1]] \
(match (index-of (slice ns 0 4) (i64 9)) \
(Some i) (println i) _ (println -1))))";
(* The one direction a container-fixed binding does admit, and it is new
with the join: a *narrower* scalar widens into the type the container
fixed, through the same cast a monomorphic i32 parameter applies. This
used to refuse with the same both-ways sentence as everything else. *)
accepts "a narrower scalar widens into a container-fixed binding"
"(defn main [] () (let [ns [5 3 9 1]] \
(match (index-of (slice ns 0 4) (i16 9)) \
(Some i) (println i) _ (println -1))))";
(* The written conversion is what the message asks for, and it is accepted:
the refusal is about the *implicit* step, not about reaching i64. *)
accepts "the written conversion is accepted"

View File

@ -927,11 +927,12 @@ $t)} at the head of the body, or take the operation as a parameter — a
<p>What makes that liveable is a <code>where</code> clause, written as a Clojure-style
map at the head of the body — <code>{:where (ordered? $t)}</code>, or a vector when
there is more than one: <code>{:where [(ordered? $t) (hashable? $u)]}</code>. There
are four predicates, and each gates builtins the compiler already has:</p>
are five predicates, and each gates builtins the compiler already has:</p>
<div class="scroll">
<table>
<tr><th>Predicate</th><th>What it admits</th></tr>
<tr><td><code>integer?</code></td><td><code>bit-and</code> <code>bit-or</code> <code>bit-xor</code> <code>&lt;&lt;</code> <code>&gt;&gt;</code> — every integer type, no float</td></tr>
<tr><td><code>numeric?</code></td><td><code>+</code> <code>-</code> <code>*</code> <code>/</code> <code>%</code>, and a cast <code>(t x)</code></td></tr>
<tr><td><code>ordered?</code></td><td><code>&lt;</code> <code>&lt;=</code> <code>&gt;</code> <code>&gt;=</code> <code>min</code> <code>max</code></td></tr>
<tr><td><code>equal?</code></td><td><code>=</code> and <code>!=</code></td></tr>
@ -940,9 +941,12 @@ are four predicates, and each gates builtins the compiler already has:</p>
</div>
<p>They entail each other in one direction, so one clause usually does:
<code>numeric?</code> gives <code>ordered?</code>, and <code>ordered?</code> gives
<code>equal?</code>. A <code>sort</code> that compares its elements declares
<code>ordered?</code> and nothing else.</p>
<code>integer?</code> gives <code>numeric?</code>, <code>numeric?</code> gives
<code>ordered?</code>, and <code>ordered?</code> gives <code>equal?</code>. A
<code>sort</code> that compares its elements declares <code>ordered?</code> and
nothing else, and the prelude's <code>abs</code> declares <code>integer?</code>
alone — the bound is what keeps its integer body away from the floats, whose
<code>abs-f32</code>/<code>abs-f64</code> are libm's sign-bit clear.</p>
<p><strong>Every value copies.</strong> There used to be a fifth predicate,
<code>copyable?</code>, gating a second read of a move-only variable; the move