Share the const-keyword-lookup head predicates
The inliner and the type inferencer each recognized (:k m) and (get m :k) lookups with their own copy of the callee tests — the get-callee check was duplicated verbatim across both. Lift kw-callee?/get-callee? into jolt.passes.fold (alongside scalar-const?) and call them from both passes so the head recognition can't drift. Only the head predicates move. The deliberate differences stay: the inliner still accepts any scalar key in the get-form (its scalar-replacement targets can be string/number-keyed maps) while the inferencer requires keyword keys for struct field typing, and the inferencer keeps its two arms separate so each rebuilds args for its form. The backend's value-as-fn ifn-kind is left alone.
This commit is contained in:
parent
e9d56422bd
commit
a893e21111
5 changed files with 91 additions and 73 deletions
BIN
guestbook.sqlite3
Normal file
BIN
guestbook.sqlite3
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
|
|
@ -73,3 +73,19 @@
|
||||||
(defn scalar-const? [n]
|
(defn scalar-const? [n]
|
||||||
(and (= :const (get n :op))
|
(and (= :const (get n :op))
|
||||||
(let [v (get n :val)] (or (keyword? v) (string? v) (number? v) (boolean? v)))))
|
(let [v (get n :val)] (or (keyword? v) (string? v) (number? v) (boolean? v)))))
|
||||||
|
|
||||||
|
;; The two callee shapes a constant-keyword map lookup takes: a keyword in fn
|
||||||
|
;; position — (:k m) — or clojure.core/get with a const key — (get m :k). The
|
||||||
|
;; inliner (scalar replacement) and the type inferencer both recognize these;
|
||||||
|
;; sharing the head predicates keeps the two from drifting. Each caller still
|
||||||
|
;; imposes its own arity, subject, and key-type constraints.
|
||||||
|
(defn kw-callee?
|
||||||
|
"True if fnode is a constant keyword used as a function head — the (:k m) form."
|
||||||
|
[fnode]
|
||||||
|
(and (= :const (get fnode :op)) (keyword? (get fnode :val))))
|
||||||
|
|
||||||
|
(defn get-callee?
|
||||||
|
"True if fnode is the clojure.core/get (or host get) callee — the (get m k) form."
|
||||||
|
[fnode]
|
||||||
|
(or (and (= :var (get fnode :op)) (= "clojure.core" (get fnode :ns)) (= "get" (get fnode :name)))
|
||||||
|
(and (= :host (get fnode :op)) (= "get" (get fnode :name)))))
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
and the `dirty` fixpoint flag. Portable Clojure (compiler-tier)."
|
and the `dirty` fixpoint flag. Portable Clojure (compiler-tier)."
|
||||||
(:require [jolt.host :refer [inline-ir]]
|
(:require [jolt.host :refer [inline-ir]]
|
||||||
[jolt.ir :refer [map-ir-children reduce-ir-children coerce-node]]
|
[jolt.ir :refer [map-ir-children reduce-ir-children coerce-node]]
|
||||||
[jolt.passes.fold :refer [scalar-const?]]))
|
[jolt.passes.fold :refer [scalar-const? kw-callee? get-callee?]]))
|
||||||
|
|
||||||
;; ---------------------------------------------------------------------------
|
;; ---------------------------------------------------------------------------
|
||||||
;; Shared state: a dirty flag the fixpoint loop reads, and a fresh-name counter
|
;; Shared state: a dirty flag the fixpoint loop reads, and a fresh-name counter
|
||||||
|
|
@ -229,7 +229,7 @@
|
||||||
(defn- pure-fn? [f]
|
(defn- pure-fn? [f]
|
||||||
(let [op (get f :op)]
|
(let [op (get f :op)]
|
||||||
(cond
|
(cond
|
||||||
(and (= op :const) (keyword? (get f :val))) true
|
(kw-callee? f) true
|
||||||
(= op :var) (and (= "clojure.core" (get f :ns)) (contains? pure-fns (get f :name)))
|
(= op :var) (and (= "clojure.core" (get f :ns)) (contains? pure-fns (get f :name)))
|
||||||
(= op :host) (contains? pure-fns (get f :name))
|
(= op :host) (contains? pure-fns (get f :name))
|
||||||
:else false)))
|
:else false)))
|
||||||
|
|
@ -282,13 +282,12 @@
|
||||||
(if (= :invoke (get node :op))
|
(if (= :invoke (get node :op))
|
||||||
(let [f (get node :fn) args (get node :args)]
|
(let [f (get node :fn) args (get node :args)]
|
||||||
(cond
|
(cond
|
||||||
(and (= :const (get f :op)) (keyword? (get f :val))
|
(and (kw-callee? f)
|
||||||
(= 1 (count args))
|
(= 1 (count args))
|
||||||
(= :local (get (nth args 0) :op)) (= nm (get (nth args 0) :name)))
|
(= :local (get (nth args 0) :op)) (= nm (get (nth args 0) :name)))
|
||||||
(get f :val)
|
(get f :val)
|
||||||
|
|
||||||
(and (or (and (= :var (get f :op)) (= "clojure.core" (get f :ns)) (= "get" (get f :name)))
|
(and (get-callee? f)
|
||||||
(and (= :host (get f :op)) (= "get" (get f :name))))
|
|
||||||
(= 2 (count args))
|
(= 2 (count args))
|
||||||
(= :local (get (nth args 0) :op)) (= nm (get (nth args 0) :name))
|
(= :local (get (nth args 0) :op)) (= nm (get (nth args 0) :name))
|
||||||
(scalar-const? (nth args 1)))
|
(scalar-const? (nth args 1)))
|
||||||
|
|
@ -500,7 +499,7 @@
|
||||||
lookup folds only for a declared field."
|
lookup folds only for a declared field."
|
||||||
[node]
|
[node]
|
||||||
(let [f (get node :fn) args (get node :args)]
|
(let [f (get node :fn) args (get node :args)]
|
||||||
(if (and (= :const (get f :op)) (keyword? (get f :val)) (= 1 (count args)))
|
(if (and (kw-callee? f) (= 1 (count args)))
|
||||||
(let [m (nth args 0) k (get f :val)]
|
(let [m (nth args 0) k (get f :val)]
|
||||||
(if (and (= :map (get m :op)) (const-key-map? m) (all-vals-pure? m))
|
(if (and (= :map (get m :op)) (const-key-map? m) (all-vals-pure? m))
|
||||||
(do (mark!) (map-val m k))
|
(do (mark!) (map-val m k))
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
top = :any) that types expressions and reuses the same walk as a loose success
|
top = :any) that types expressions and reuses the same walk as a loose success
|
||||||
checker. Also the inter-procedural driver API the back end calls to
|
checker. Also the inter-procedural driver API the back end calls to
|
||||||
propagate param types across a unit / the whole program. Weakly coupled to the
|
propagate param types across a unit / the whole program. Weakly coupled to the
|
||||||
IR-rewriting passes — shares only the const-shape predicate (jolt.passes.fold)."
|
IR-rewriting passes — shares the const-shape predicates (jolt.passes.fold)."
|
||||||
(:require [jolt.passes.fold :refer [scalar-const?]]
|
(:require [jolt.passes.fold :refer [scalar-const? kw-callee? get-callee?]]
|
||||||
[jolt.passes.types.lattice :refer
|
[jolt.passes.types.lattice :refer
|
||||||
[velem selem sfields vec-type? set-type? struct-type? mk-vec mk-set
|
[velem selem sfields vec-type? set-type? struct-type? mk-vec mk-set
|
||||||
mk-struct union-cap scalar-t? union-type? umembers union-of merge-fields
|
mk-struct union-cap scalar-t? union-type? umembers union-of merge-fields
|
||||||
|
|
@ -263,7 +263,7 @@
|
||||||
;; (:k m) / (:k m default): the result is m's field type, and if m is a
|
;; (:k m) / (:k m default): the result is m's field type, and if m is a
|
||||||
;; struct the subject is tagged so the back end drops the guard — this
|
;; struct the subject is tagged so the back end drops the guard — this
|
||||||
;; types nested access end to end (RFC 0005).
|
;; types nested access end to end (RFC 0005).
|
||||||
(and (= :const (get fnode :op)) (keyword? (get fnode :val)) (>= n 1) (<= n 2))
|
(and (kw-callee? fnode) (>= n 1) (<= n 2))
|
||||||
(let [mr (infer (nth args 0) tenv env)
|
(let [mr (infer (nth args 0) tenv env)
|
||||||
mt (nth mr 0)
|
mt (nth mr 0)
|
||||||
msub (if (struct-safe? mt) (mark-struct (nth mr 1) mt) (nth mr 1))
|
msub (if (struct-safe? mt) (mark-struct (nth mr 1) mt) (nth mr 1))
|
||||||
|
|
@ -272,8 +272,7 @@
|
||||||
[(if dr (join ft (nth dr 0)) ft)
|
[(if dr (join ft (nth dr 0)) ft)
|
||||||
(assoc node :args (if dr [msub (nth dr 1)] [msub]))])
|
(assoc node :args (if dr [msub (nth dr 1)] [msub]))])
|
||||||
;; (get m :k [default]): same, when the key is a constant keyword.
|
;; (get m :k [default]): same, when the key is a constant keyword.
|
||||||
(and (or (and (= :var (get fnode :op)) (= "clojure.core" (get fnode :ns)) (= "get" (get fnode :name)))
|
(and (get-callee? fnode)
|
||||||
(and (= :host (get fnode :op)) (= "get" (get fnode :name))))
|
|
||||||
(>= n 2) (= :const (get (nth args 1) :op)) (keyword? (get (nth args 1) :val)))
|
(>= n 2) (= :const (get (nth args 1) :op)) (keyword? (get (nth args 1) :val)))
|
||||||
(let [mr (infer (nth args 0) tenv env)
|
(let [mr (infer (nth args 0) tenv env)
|
||||||
mt (nth mr 0)
|
mt (nth mr 0)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue