Replace the ad-hoc inference lattice (a flat :struct-map tag plus {:vec ELEM})
with one recursive structural type: {:struct {field -> T}}, {:vec T}, {:set T},
scalar tags, and :any. A keyword lookup now returns its field's type, so nested
access like (:r (:direction ray)) is typed end to end and drops its guard. join
is field-wise and element-wise with a depth cap of 4 so the inter-procedural
fixpoint still terminates.
The back end honors a struct hint on any subject node, not just locals, so an
inferred field type on a nested lookup specializes. The orchestrator's fixpoint
joins through the portable join-types so compound types no longer collapse to
:any.
Ray tracer goes 12.8s to 11.0s with no hints, matching the explicit ^:struct
version (10.9s). Render checksum unchanged (1915337), full gate green,
conformance x3 modes pass.
jolt-5uj
41 lines
2.3 KiB
Text
41 lines
2.3 KiB
Text
# Collection-element types + HOF awareness, Phase 3 (jolt-d6u). A vector carries
|
|
# its element type ({:vec ELEM}); a reduce/map/filter closure over it gets that
|
|
# element type on its element param. So a lookup inside a reduce closure over a
|
|
# vector-of-structs specializes — no hint — WHEN the element type is provable.
|
|
(import ../../src/jolt/api :as api)
|
|
(import ../../src/jolt/backend :as backend)
|
|
(import ../../src/jolt/types :as types)
|
|
(import ../../src/jolt/reader :as reader)
|
|
|
|
(print "Type inference Phase 3 (jolt-d6u)...")
|
|
|
|
(os/setenv "JOLT_DIRECT_LINK" "1")
|
|
(def ctx (api/init {:compile? true}))
|
|
(api/eval-string ctx "(ns p3)")
|
|
(def pns (types/ctx-find-ns ctx "jolt.passes"))
|
|
(def reinfer (types/var-get (types/ns-find pns "reinfer-def")))
|
|
# helper: analyze a defn, reinfer with seeded param types, count guards
|
|
(defn guards [src ptmap]
|
|
(def d (backend/analyze-form ctx (reader/parse-string src)))
|
|
(length (string/find-all ":jolt/type" (string/format "%p" (backend/emit-ir ctx (reinfer d ptmap))))))
|
|
|
|
# a reduce closure's element param gets the vector's element type
|
|
(def red "(defn f [coll] (reduce (fn [acc h] (+ acc (:r h))) 0 coll))")
|
|
(assert (= 0 (guards red @{"coll" {:vec {:struct {}}}})) "reduce element typed -> bare lookup in closure")
|
|
(assert (= 1 (guards red @{"coll" {:vec :any}})) "reduce over vector of unknown -> guard kept")
|
|
(assert (= 1 (guards red @{})) "untyped coll -> guard kept")
|
|
|
|
# mapv over a vector-of-structs types the closure element too
|
|
(def mp "(defn g [coll] (mapv (fn [h] (:r h)) coll))")
|
|
(assert (= 0 (guards mp @{"coll" {:vec {:struct {}}}})) "mapv element typed -> bare lookup")
|
|
(assert (= 1 (guards mp @{"coll" {:vec :any}})) "mapv over unknown element -> guard")
|
|
|
|
# element type is DERIVED, not just seeded: a vector literal of structs, reduced
|
|
(def derived "(defn h2 [] (reduce (fn [acc x] (+ acc (:r x))) 0 [{:r 1 :g 2} {:r 3 :g 4}]))")
|
|
(assert (= 0 (guards derived @{})) "vector literal of structs -> element struct -> bare lookup")
|
|
|
|
# correctness: the specialized closures compute the same
|
|
(assert (= 4 (api/eval-string ctx "((fn [coll] (reduce (fn [acc h] (+ acc (:r h))) 0 coll)) [{:r 1} {:r 3}])")) "reduce value")
|
|
(assert (= 4 (api/eval-string ctx "(reduce (fn [acc x] (+ acc (:r x))) 0 [{:r 1 :g 2} {:r 3 :g 4}])")) "derived value")
|
|
|
|
(print "Type inference Phase 3 passed!")
|