|
891 | 891 | 'prototype)}) |
892 | 892 | x)) |
893 | 893 |
|
| 894 | +(defn ->type-set |
| 895 | + "Ensures that a type tag is a set." |
| 896 | + [t] |
| 897 | + (if #?(:clj (set? t) |
| 898 | + :cljs (cljs-set? t)) |
| 899 | + t |
| 900 | + #{t})) |
| 901 | + |
| 902 | +(defn canonicalize-type [t] |
| 903 | + "Ensures that a type tag is either nil, a type symbol, or a non-singleton |
| 904 | + set of type symbols, absorbing clj-nil into seq and all types into any." |
| 905 | + (cond |
| 906 | + (symbol? t) t |
| 907 | + (empty? t) nil |
| 908 | + (== 1 (count t)) (first t) |
| 909 | + (contains? t 'any) 'any |
| 910 | + (contains? t 'seq) (let [res (disj t 'clj-nil)] |
| 911 | + (if (== 1 (count res)) |
| 912 | + 'seq |
| 913 | + res)) |
| 914 | + :else t)) |
| 915 | + |
| 916 | +(defn add-types |
| 917 | + "Produces a union of types." |
| 918 | + ([] 'any) |
| 919 | + ([t1] t1) |
| 920 | + ([t1 t2] |
| 921 | + (if (or (nil? t1) |
| 922 | + (nil? t2)) |
| 923 | + 'any |
| 924 | + (-> (set/union (->type-set t1) (->type-set t2)) |
| 925 | + canonicalize-type))) |
| 926 | + ([t1 t2 & ts] |
| 927 | + (apply add-types (add-types t1 t2) ts))) |
| 928 | + |
894 | 929 | (def alias->type |
895 | 930 | '{object Object |
896 | 931 | string String |
|
1953 | 1988 | fixed-arity (count params') |
1954 | 1989 | recur-frame {:protocol-impl (:protocol-impl env) |
1955 | 1990 | :params params |
1956 | | - :flag (atom nil)} |
| 1991 | + :flag (atom nil) |
| 1992 | + :tags (atom [])} |
1957 | 1993 | recur-frames (cons recur-frame *recur-frames*) |
1958 | 1994 | body-env (assoc env :context :return :locals locals) |
1959 | 1995 | body-form `(do ~@body) |
|
2230 | 2266 | (analyze-let-body* env context exprs))) |
2231 | 2267 |
|
2232 | 2268 | (defn analyze-let |
2233 | | - [encl-env [_ bindings & exprs :as form] is-loop] |
| 2269 | + [encl-env [_ bindings & exprs :as form] is-loop widened-tags] |
2234 | 2270 | (when-not (and (vector? bindings) (even? (count bindings))) |
2235 | 2271 | (throw (error encl-env "bindings must be vector of even number of elements"))) |
2236 | 2272 | (let [context (:context encl-env) |
2237 | 2273 | op (if (true? is-loop) :loop :let) |
| 2274 | + bindings (if widened-tags |
| 2275 | + (vec (mapcat |
| 2276 | + (fn [[name init] widened-tag] |
| 2277 | + [(vary-meta name assoc :tag widened-tag) init]) |
| 2278 | + (partition 2 bindings) |
| 2279 | + widened-tags)) |
| 2280 | + bindings) |
2238 | 2281 | [bes env] (analyze-let-bindings encl-env bindings op) |
2239 | 2282 | recur-frame (when (true? is-loop) |
2240 | | - {:params bes :flag (atom nil)}) |
| 2283 | + {:params bes |
| 2284 | + :flag (atom nil) |
| 2285 | + :tags (atom (mapv :tag bes))}) |
2241 | 2286 | recur-frames (if recur-frame |
2242 | 2287 | (cons recur-frame *recur-frames*) |
2243 | 2288 | *recur-frames*) |
2244 | 2289 | loop-lets (cond |
2245 | 2290 | (true? is-loop) *loop-lets* |
2246 | 2291 | (some? *loop-lets*) (cons {:params bes} *loop-lets*)) |
2247 | 2292 | expr (analyze-let-body env context exprs recur-frames loop-lets) |
2248 | | - children [:bindings :body]] |
2249 | | - {:op op |
2250 | | - :env encl-env |
2251 | | - :bindings bes |
2252 | | - :body (assoc expr :body? true) |
2253 | | - :form form |
2254 | | - :children children})) |
| 2293 | + children [:bindings :body] |
| 2294 | + nil->any (fnil identity 'any)] |
| 2295 | + (if (and is-loop |
| 2296 | + (not widened-tags) |
| 2297 | + (not= (mapv nil->any @(:tags recur-frame)) |
| 2298 | + (mapv (comp nil->any :tag) bes))) |
| 2299 | + (recur encl-env form is-loop @(:tags recur-frame)) |
| 2300 | + {:op op |
| 2301 | + :env encl-env |
| 2302 | + :bindings bes |
| 2303 | + :body (assoc expr :body? true) |
| 2304 | + :form form |
| 2305 | + :children children}))) |
2255 | 2306 |
|
2256 | 2307 | (defmethod parse 'let* |
2257 | 2308 | [op encl-env form _ _] |
2258 | | - (analyze-let encl-env form false)) |
| 2309 | + (analyze-let encl-env form false nil)) |
2259 | 2310 |
|
2260 | 2311 | (defmethod parse 'loop* |
2261 | 2312 | [op encl-env form _ _] |
2262 | | - (analyze-let encl-env form true)) |
| 2313 | + (analyze-let encl-env form true nil)) |
2263 | 2314 |
|
2264 | 2315 | (defmethod parse 'recur |
2265 | 2316 | [op env [_ & exprs :as form] _ _] |
|
2279 | 2330 | (not add-implicit-target-object?)) |
2280 | 2331 | (warning :protocol-impl-recur-with-target env {:form (:form (first exprs))})) |
2281 | 2332 | (reset! (:flag frame) true) |
| 2333 | + (swap! (:tags frame) (fn [tags] |
| 2334 | + (mapv (fn [tag expr] |
| 2335 | + (add-types tag (:tag expr))) |
| 2336 | + tags exprs))) |
2282 | 2337 | (assoc {:env env :op :recur :form form} |
2283 | 2338 | :frame frame |
2284 | 2339 | :exprs exprs |
|
0 commit comments