proxy [ThreadLocal] via thread-parameter; clojure.test/*testing-vars*

- (proxy [ThreadLocal] [] (initialValue [] body)) now builds a real per-thread
  store backed by a Chez thread-parameter, with a lazy initialValue; .get/.set/
  .remove work. Other proxies stay nil. test.check's no-seed PRNG (next-rng) uses
  one, so gen/sample and gen/generate (and everything built on them) now work.
- clojure.test/*testing-vars* (+ *report-counters*) are bound vars now, so a
  defspec run through its :test metadata / default reporter doesn't hit an unbound
  var.

make test green (+1 corpus row), shakesmoke byte-identical. One re-mint (proxy).
This commit is contained in:
Yogthos 2026-06-27 19:51:49 -04:00
parent f32bd335e3
commit 4d61145e9c
6 changed files with 587 additions and 558 deletions

View file

@ -558,8 +558,14 @@
(parse-extend-impls type-impls))))
;; extend is a real FUNCTION — defined above extend-type.
;; JVM proxies are unsupported.
(defmacro proxy [& args] nil)
;; JVM proxies are unsupported in general, EXCEPT (proxy [ThreadLocal] [] (initialValue
;; [] body)) — a per-thread store with a lazy initial value (test.check's no-seed
;; PRNG uses one). Other proxies stay nil.
(defmacro proxy [supers ctor-args & methods]
(when (and (vector? supers) (= 1 (count supers))
(let [s (name (first supers))] (or (= s "ThreadLocal") (= s "InheritableThreadLocal"))))
(let [init (some (fn [m] (when (= "initialValue" (name (first m))) m)) methods)]
`(jolt.host/make-thread-local (fn [] ~@(when init (nnext init)))))))
;; definterface is JVM-only; bind the name to a marker and return the name (not a
;; var), matching the JVM where definterface yields the interface Class.
(defmacro definterface [name-sym & body]