(ns ^:typed.clojure com.tailrecursion.blacktide.compiler.passes.invariants
"Remove loop parameters that only forward an outer lexical value. Their
initializers remain in place, and recur keeps exactly the retained parameters."
(:require [clojure.set :as set]
[com.tailrecursion.nanopass :as np]
[com.tailrecursion.blacktide.compiler.languages :as l]
[typed.clojure :as-alias t]))
(np/defpass assigned {:from [l/Joined Expr] :to (t/Set t/Sym)}
[node]
:bind (conj (assigned (:body node)) (:target (:binding node)))
:join (into (assigned (:body node)) (:targets node))
:branch (set/union (assigned (:yes node)) (assigned (:no node)))
:switch (into #{} (mapcat assigned) (:arms node))
;; Inner bindings are private; only enclosing join targets export changes.
:loop #{}
:recur #{} :return #{} :throw #{})
(np/defpass expression {:from [l/Joined Expr] :to [l/Joined Expr] :args [(t/Set t/Sym)]}
[invariants node]
:loop (let [invariants (set/difference (set (:slots node)) (assigned (:body node)))]
(assoc node :slots (filterv #(not (contains? invariants %)) (:slots node))
:body (expression invariants (:body node))))
:recur (assoc node :slots (filterv #(not (contains? invariants %)) (:slots node))))