|
68 | 68 | "The namespace of the constants table as a symbol." |
69 | 69 | 'cljs.core.constants) |
70 | 70 |
|
| 71 | +(def ^:private identity-counter (atom 0)) |
| 72 | + |
| 73 | +(defn- add-identity [m] |
| 74 | + (assoc m :identity (swap! identity-counter inc))) |
| 75 | + |
71 | 76 | #?(:clj |
72 | 77 | (def transit-read-opts |
73 | 78 | (try |
|
1440 | 1445 | :form form} |
1441 | 1446 | (var-ast env sym))) |
1442 | 1447 |
|
| 1448 | +(def ^:private predicate->tag |
| 1449 | + '{ |
| 1450 | + ;; Base values |
| 1451 | + cljs.core/nil? clj-nil |
| 1452 | + cljs.core/undefined? clj-nil |
| 1453 | + cljs.core/false? boolean |
| 1454 | + cljs.core/true? boolean |
| 1455 | + cljs.core/zero? number |
| 1456 | + cljs.core/infinite? number |
| 1457 | + |
| 1458 | + ;; Base types |
| 1459 | + cljs.core/boolean? boolean |
| 1460 | + cljs.core/string? string |
| 1461 | + cljs.core/char? string |
| 1462 | + cljs.core/number? number |
| 1463 | + cljs.core/integer? number |
| 1464 | + cljs.core/float? number |
| 1465 | + cljs.core/double? number |
| 1466 | + cljs.core/array? array |
| 1467 | + cljs.core/seq? seq |
| 1468 | + |
| 1469 | + ;; JavaScript types |
| 1470 | + cljs.core/regexp? js/RegExp |
| 1471 | + |
| 1472 | + ;; Types |
| 1473 | + cljs.core/keyword? cljs.core/Keyword |
| 1474 | + cljs.core/var? cljs.core/Var |
| 1475 | + cljs.core/symbol? cljs.core/Symbol |
| 1476 | + cljs.core/volatile? cljs.core/Volatile |
| 1477 | + cljs.core/delay? cljs.core/Delay |
| 1478 | + cljs.core/reduced? cljs.core/Reduced |
| 1479 | + |
| 1480 | + ;; Protocols |
| 1481 | + cljs.core/map-entry? cljs.core/IMapEntry |
| 1482 | + cljs.core/reversible? cljs.core/IReversible |
| 1483 | + cljs.core/uuid? cljs.core/IUUID |
| 1484 | + cljs.core/tagged-literal? cljs.core/ITaggedLiteral |
| 1485 | + cljs.core/iterable? cljs.core/IIterable |
| 1486 | + cljs.core/cloneable? cljs.core/ICloneable |
| 1487 | + cljs.core/inst? cljs.core/Inst |
| 1488 | + cljs.core/counted? cljs.core/ICounted |
| 1489 | + cljs.core/indexed? cljs.core/IIndexed |
| 1490 | + cljs.core/coll? cljs.core/ICollection |
| 1491 | + cljs.core/set? cljs.core/ISet |
| 1492 | + cljs.core/associative? cljs.core/IAssociative |
| 1493 | + cljs.core/ifind? cljs.core/IFind |
| 1494 | + cljs.core/sequential? cljs.core/ISequential |
| 1495 | + cljs.core/sorted? cljs.core/ISorted |
| 1496 | + cljs.core/reduceable cljs.core/IReduce |
| 1497 | + cljs.core/map? cljs.core/IMap |
| 1498 | + cljs.core/list? cljs.core/IList |
| 1499 | + cljs.core/record? cljs.core/IRecord |
| 1500 | + cljs.core/vector? cljs.core/IVector |
| 1501 | + cljs.core/chunked-seq? cljs.core/IChunkedSeq |
| 1502 | + cljs.core/ifn? cljs.core/IFn |
| 1503 | + |
| 1504 | + ;; Composites |
| 1505 | + cljs.core/seqable? #{cljs.core/ISeqable array string} |
| 1506 | + cljs.core/ident? #{cljs.core/Keyword cljs.core/Symbol} |
| 1507 | + }) |
| 1508 | + |
| 1509 | +(defn- simple-predicate-induced-tag |
| 1510 | + "Look for a predicate-induced tag when the test expression is a simple |
| 1511 | + application of a predicate to a local, as in (string? x)." |
| 1512 | + [env test] |
| 1513 | + (when (and (list? test) |
| 1514 | + (== 2 (count test)) |
| 1515 | + (every? symbol? test)) |
| 1516 | + (let [analyzed-fn (no-warn (analyze (assoc env :context :expr) (first test)))] |
| 1517 | + (when (= :var (:op analyzed-fn)) |
| 1518 | + (when-let [tag (predicate->tag (:name analyzed-fn))] |
| 1519 | + (let [sym (last test)] |
| 1520 | + (when (and (nil? (namespace sym)) |
| 1521 | + (get-in env [:locals sym])) |
| 1522 | + [sym tag]))))))) |
| 1523 | + |
| 1524 | +(defn- type-check-induced-tag |
| 1525 | + "Look for a type-check-induced tag when the test expression is the use of |
| 1526 | + satisfies? or instance? on a local, as in (satisfies? ICounted x)." |
| 1527 | + [env test] |
| 1528 | + (when (and (list? test) |
| 1529 | + (== 3 (count test)) |
| 1530 | + (every? symbol? test)) |
| 1531 | + (let [analyzed-fn (no-warn (analyze (assoc env :context :expr) (first test)))] |
| 1532 | + (when (= :var (:op analyzed-fn)) |
| 1533 | + (when ('#{cljs.core/satisfies? cljs.core/instance?} (:name analyzed-fn)) |
| 1534 | + (let [analyzed-type (no-warn (analyze (assoc env :context :expr) (second test))) |
| 1535 | + tag (:name analyzed-type) |
| 1536 | + sym (last test)] |
| 1537 | + (when (and (= :var (:op analyzed-type)) |
| 1538 | + (nil? (namespace sym)) |
| 1539 | + (get-in env [:locals sym])) |
| 1540 | + [sym tag]))))))) |
| 1541 | + |
| 1542 | +(defn- add-predicate-induced-tags |
| 1543 | + "Looks at the test and adds any tags which are induced by virtue |
| 1544 | + of the predicate being satisfied. For exmaple in (if (string? x) x :bar) |
| 1545 | + the local x in the then branch must be of string type." |
| 1546 | + [env test] |
| 1547 | + (let [[local tag] (or (simple-predicate-induced-tag env test) |
| 1548 | + (type-check-induced-tag env test))] |
| 1549 | + (cond-> env |
| 1550 | + local (update-in [:locals local :tag] (fn [prev-tag] |
| 1551 | + (if (or (nil? prev-tag) |
| 1552 | + (= 'any prev-tag)) |
| 1553 | + tag |
| 1554 | + prev-tag)))))) |
| 1555 | + |
1443 | 1556 | (defmethod parse 'if |
1444 | 1557 | [op env [_ test then else :as form] name _] |
1445 | 1558 | (when (< (count form) 3) |
1446 | 1559 | (throw (error env "Too few arguments to if"))) |
1447 | 1560 | (when (> (count form) 4) |
1448 | 1561 | (throw (error env "Too many arguments to if"))) |
1449 | 1562 | (let [test-expr (disallowing-recur (analyze (assoc env :context :expr) test)) |
1450 | | - then-expr (allowing-redef (analyze env then)) |
| 1563 | + then-expr (allowing-redef (analyze (add-predicate-induced-tags env test) then)) |
1451 | 1564 | else-expr (allowing-redef (analyze env else))] |
1452 | 1565 | {:env env :op :if :form form |
1453 | 1566 | :test test-expr :then then-expr :else else-expr |
|
2105 | 2218 | :variadic? (:variadic? init-expr) |
2106 | 2219 | :max-fixed-arity (:max-fixed-arity init-expr) |
2107 | 2220 | :method-params (map :params (:methods init-expr))}) |
2108 | | - be)] |
| 2221 | + be) |
| 2222 | + be (add-identity be)] |
2109 | 2223 | (recur (conj bes be) |
2110 | 2224 | (assoc-in env [:locals name] be) |
2111 | 2225 | (next bindings)))) |
|
0 commit comments