mutable deftype fields: (set! field val) in a method

deftype fields tagged ^:unsynchronized-mutable / ^:volatile-mutable can now be
reassigned in place from a method, as on the JVM. A jrec stores fields as cons
cells, so a new jolt-set-field! mutates the pair with set-cdr!. The deftype macro
rewrites (set! mutable-field v) in a method body to (set! (.-field inst) v), and
the analyzer compiles a (set! (.-field obj) v) target to jolt-set-field! — so
both the rewritten symbol form and an explicit interop (set! (.-root this) v) go
through one path. Field reads remain a snapshot at method entry, which is correct
for the universal read-then-set pattern (a repeated set! of the same field in one
call would read the entry value).

Closes the set!-of-local SCI failures: SCI load 202 -> 205/218.
This commit is contained in:
Yogthos 2026-06-22 01:19:03 -04:00
parent b9ab750983
commit 424ce75cf6
9 changed files with 416 additions and 371 deletions

View file

@ -307,6 +307,21 @@
(:volatile-mutable mt)))
true false)))
fields)
;; mutable field symbols (^:unsynchronized-mutable / ^:volatile-mutable):
;; (set! field v) in a method body lowers to (set! (.-field inst) v), the
;; in-place field write the analyzer compiles to jolt-set-field! (jolt-c3q).
mutable-syms (map first (filter second (map vector fields field-muts)))
mutable? (fn [s] (boolean (some (fn [m] (= m s)) mutable-syms)))
rewrite-set (fn rw [inst form]
(cond
(and (seq? form) (seq form) (symbol? (first form))
(= "set!" (name (first form)))
(symbol? (second form)) (mutable? (second form)))
(list 'set! (list (symbol (str ".-" (name (second form)))) inst)
(rw inst (nth form 2)))
(seq? form) (map (fn [x] (rw inst x)) form)
(vector? form) (mapv (fn [x] (rw inst x)) form)
:else form))
;; inline impls register for dispatch but are NOT extenders of the
;; protocol (the JVM compiles them into the class) — register-inline-method,
;; not extend-type.
@ -315,9 +330,10 @@
~@(map (fn [spec]
(let [argv (nth spec 1)
inst (first argv)
binds (vec (mapcat (fn [f] [f `(get ~inst ~(keyword (name f)))]) fields))]
binds (vec (mapcat (fn [f] [f `(get ~inst ~(keyword (name f)))]) fields))
mbody (map (fn [bf] (rewrite-set inst bf)) (drop 2 spec))]
`(register-inline-method ~(name tname) ~(name proto) ~(name (first spec))
(fn ~argv (let [~@binds] ~@(drop 2 spec))))))
(fn ~argv (let [~@binds] ~@mbody)))))
specs)))]
`(do
(def ~tname (make-deftype-ctor (quote ~tname) [~@field-kws] [~@field-tags] [~@field-muts]))