diff --git a/FIX.org b/FIX.org index 9cf7bcc..8ec7dab 100644 --- a/FIX.org +++ b/FIX.org @@ -436,18 +436,46 @@ rename. typed-flan branch freezes the static language pre-dyn. 6. defclass = named dyn map + shape tag; CLOS class dispatch AND Clojure-style arbitrary dispatch functions. After 1. 7. dyn if: truthiness (nil/false are false, all else true). Typed stays - strict bool. — LANDED, a94efcc + strict bool. — LANDED, 264765a Reaches when, cond, if's own condition, and's condition, or's condition, not and while for free or by hand, all through one funnel - in check.ml (check_truthy). One thing fell out of it that nobody had - decided: and's answer position already carries a non-bool dyn value - through, Clojure-style, because its short-circuit sentinel is the else - arm and the real value's type wins; or's sentinel is the then arm - instead, so it is what decides the whole expression's type, and or's - answer stays a strict bool. Reordering or to match and is a real fix - and nobody's called it yet — left alone, noted in parse.ml at - shortcircuit. + in check.ml (check_truthy). Two things fell out of it that nobody had + decided going in, one fixed on review and one left as the author's + call: + + - or's answer used to stay a strict bool where and's already carried a + non-bool dyn value through, Clojure-style — and's short-circuit + sentinel sits in the else arm, so the real value's type wins there, + but or's sat in the then arm, the one check_if types first, so it + decided the whole expression's type and a later non-bool dyn answer + hit the strict bool boundary and trapped. (or nil "x"), the + canonical (or x default) idiom, crashed rather than answering "x". + FIXED, ad0f1fb: or now binds its test to a temp and answers the + temp, Clojure's own expansion, evaluating the test once and handing + back whichever operand actually decided it. + - A bare keyword condition used to be checked with want:Bool from the + start and refused by the keyword arm's enum-or-refuse case: ":kw is + an enum member where an enum is expected and a dyn keyword + elsewhere, but bool is expected here", there being no enum in play. + Checked with no expectation first, as every scrutinee now is, it + resolves as the dyn keyword instead, and a dyn keyword is + unconditionally truthy — a typed if with a bare keyword condition + now compiles and always takes the then branch. The author's call: + lispy truthiness wins here, the lost diagnostic is not brought back. + Pinned in test_flan.ml so it does not regress by accident. + + Also noted at check_truthy (check.ml) and not acted on: check_truthy's + own retry-on-failure, needed to keep a refused literal's or None's + message unchanged, re-runs the whole failing subtree rather than only + the leaf that needs it, which is exponential in how deep a chain of + nested not gets on a program that does not type-check. Moot for + anything that compiles; visible only around twenty levels deep, and + only the dev daemon's half-typed-form recompiles could ever feel it. + A cheaper retry was tried and shelved — it would need to thread want + exactly as far as the full retry already does, or it changes which + literal further inside a compound condition gets the nicer message, + not just the speed. 8. Return slot stays mandatory (dyn or ()) — the parse ambiguity it closes is real; revisit only if it grates. SETTLED 2026-09-19, reconfirmed with the author: both spellings stay legal, () is not collapsing into dyn.