jolt/jolt-core/jolt
Yogthos 21cd88deee letfn is a macro over a letfn* special form (Clojure semantics)
jolt modelled letfn as a special form directly, so (macroexpand-1 '(letfn …))
returned the form unchanged. Clojure's letfn is a macro that expands to letfn*,
and macroexpansion tooling (tools.macro, tools.analyzer) depends on that — its
special-form handlers key on letfn*, not letfn.

Split it the Clojure way:
- letfn* is now the special form (analyzer), taking flat name/fn-form pairs
  [name1 fn1 name2 fn2 …] — the letrec :let lowering is unchanged.
- letfn is a macro (00-syntax) turning each (name [params] body*) spec into a
  name + (fn name [params] body*) binding, so it expands to letfn*.

So (macroexpand-1 '(letfn [(f [x] x)] (f 1))) now yields
(letfn* [f (fn f [x] x)] (f 1)), and clojure.tools.macro passes its whole suite
(macrolet / symbol-macrolet / mexpand-all). Listed in docs + site.

make test green (+1 corpus row, 0 new divergences), shakesmoke byte-identical.
One re-mint (analyzer + the letfn macro); selfhost holds.
2026-06-27 17:26:18 -04:00
..
passes Nilable record types + flow-sensitive nil narrowing (#235) 2026-06-26 17:16:16 +00:00
analyzer.clj letfn is a macro over a letfn* special form (Clojure semantics) 2026-06-27 17:26:18 -04:00
backend_scheme.clj ^long is a 64-bit long: fast-path-with-fallback ops + logical unsigned shift 2026-06-27 16:04:19 -04:00
deps.clj host interop + deps fixes for running ring-defaults on jolt 2026-06-25 04:42:35 -04:00
ir.clj Run core.memoize's test suite on jolt 2026-06-25 13:23:05 -04:00
main.clj Tree-shaking: drop library code unreachable from -main (lever 3/4) 2026-06-23 19:45:13 -04:00
nrepl.clj nREPL: make the built-in server middleware-extensible 2026-06-22 15:37:14 -04:00
passes.clj Hintless whole-program double inference (#230) 2026-06-26 14:18:10 +00:00