├── script ├── repl └── test ├── images └── part-of-typed-clojure-project.png ├── src ├── test │ ├── cljs │ │ └── cljs │ │ │ └── core │ │ │ └── typed │ │ │ └── test │ │ │ ├── dep_one.cljs │ │ │ ├── ann.cljs │ │ │ ├── dep_two.cljs │ │ │ ├── goog_import.cljs │ │ │ ├── identity.cljs │ │ │ ├── js_obj.cljs │ │ │ ├── dnolen │ │ │ └── utils │ │ │ │ ├── helpers.cljs │ │ │ │ ├── dom.cljs │ │ │ │ └── reactive.cljs │ │ │ ├── csp.cljs │ │ │ └── ympbyc │ │ │ └── test_base_env.cljs │ └── clojure │ │ └── clojure │ │ └── core │ │ └── typed │ │ └── test │ │ ├── cljs_utils.clj │ │ ├── cljs_core.clj │ │ └── cljs.clj ├── assembly │ └── slim.xml └── main │ └── clojure │ └── clojure │ └── core │ └── typed │ ├── check_ns_cljs.clj │ ├── analyzer_api_intercept.clj │ ├── bootstrap_cljs.clj │ ├── check_form_cljs.clj │ ├── util_cljs.clj │ ├── check │ └── dot_cljs.clj │ ├── emit_form_cljs.clj │ ├── analyze_cljs.clj │ ├── jsnominal_env.clj │ ├── base_env_helper_cljs.clj │ ├── check_cljs.clj │ └── base_env_cljs.clj ├── IDEAS ├── README.md ├── deps.edn ├── TODO ├── pom.xml └── epl-v10.html /script/repl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | clj -Atest:nREPL 4 | -------------------------------------------------------------------------------- /script/test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | clojure -Atest:runner 4 | -------------------------------------------------------------------------------- /images/part-of-typed-clojure-project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clojure/core.typed.checker.js/master/images/part-of-typed-clojure-project.png -------------------------------------------------------------------------------- /src/test/cljs/cljs/core/typed/test/dep_one.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.core.typed.test.dep-one 2 | (:require [cljs.core.typed :as t :include-macros true])) 3 | 4 | (def a 1) 5 | -------------------------------------------------------------------------------- /src/test/cljs/cljs/core/typed/test/ann.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.core.typed.test.ann 2 | (:require [cljs.core.typed :refer-macros [ann check-ns]])) 3 | 4 | (ann foo number) 5 | (def foo 1) 6 | -------------------------------------------------------------------------------- /src/test/cljs/cljs/core/typed/test/dep_two.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.core.typed.test.dep-two 2 | (:require [cljs.core.typed :as t :include-macros true] 3 | [cljs.core.typed.test.dep-one :as one])) 4 | 5 | (def b (inc one/a)) 6 | -------------------------------------------------------------------------------- /src/test/cljs/cljs/core/typed/test/goog_import.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.core.typed.test.goog-import 2 | (:require [cljs.core.typed :as t]) 3 | (:import [goog.events EventType])) 4 | 5 | (t/ann et [EventType -> EventType]) 6 | (defn et [e] 7 | e) 8 | -------------------------------------------------------------------------------- /src/test/cljs/cljs/core/typed/test/identity.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.core.typed.test.identity 2 | (:require [cljs.core.typed :as t])) 3 | 4 | (t/ann my-identity (t/All [x] [x -> (t/U x t/Number)])) 5 | (defn my-identity [x] 6 | (if (number? x) 7 | (inc x) 8 | x)) 9 | -------------------------------------------------------------------------------- /IDEAS: -------------------------------------------------------------------------------- 1 | 1. Generate TS annotations using https://github.com/fable-compiler/ts2fable 2 | 2. Generate Google Closure annotations using https://github.com/jleyba/js-dossier 3 | 4 | Converting TS->Goog 5 | - https://github.com/honzabrecka/ts-to-goog 6 | - https://github.com/angular/tsickle 7 | -------------------------------------------------------------------------------- /src/test/cljs/cljs/core/typed/test/js_obj.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.core.typed.test.js-obj 2 | (:require [cljs.core.typed :as t])) 3 | 4 | (t/ann jo [-> (t/JSObj {:a t/JSNumber})]) 5 | (defn jo [] 6 | #js {:a 2}) 7 | 8 | #_ 9 | (t/ann jo2 [-> (t/JSObj {:a t/JSNumber})]) 10 | ;; TODO 11 | #_ 12 | (defn jo2 [] 13 | (js-obj :a 2)) 14 | -------------------------------------------------------------------------------- /src/test/cljs/cljs/core/typed/test/dnolen/utils/helpers.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.core.typed.test.dnolen.utils.helpers) 2 | 3 | (defn ^{:ann '[Any Any -> Any]} 4 | index-of [xs x] 5 | (let [len (count xs)] 6 | (loop [i 0] 7 | (if (< i len) 8 | (if (= (nth xs i) x) 9 | i 10 | (recur (inc i))) 11 | -1)))) 12 | -------------------------------------------------------------------------------- /src/assembly/slim.xml: -------------------------------------------------------------------------------- 1 | 2 | slim 3 | 4 | jar 5 | 6 | false 7 | 8 | 9 | src/main/clojure 10 | / 11 | 12 | 13 | src/main/cljs 14 | / 15 | 16 | 17 | src/main/java 18 | / 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # core.typed.checker.js 2 | 3 | 4 | 5 | Type checker for Typed Clojure, for ClojureScript on JS. 6 | 7 | ## YourKit 8 | 9 | YourKit is kindly supporting core.typed and other open source projects with its full-featured Java Profiler. 10 | YourKit, LLC is the creator of innovative and intelligent tools for profiling 11 | Java and .NET applications. Take a look at YourKit's leading software products: 12 | 13 | * YourKit Java Profiler and 14 | * YourKit .NET Profiler. 15 | 16 | ## License 17 | 18 | Copyright © Ambrose Bonnaire-Sergeant, Rich Hickey & contributors. 19 | 20 | Licensed under the EPL (see the file epl-v10.html). 21 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/core/typed/check_ns_cljs.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Ambrose Bonnaire-Sergeant, Rich Hickey & contributors. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.core.typed.check-ns-cljs 10 | (:require [cljs.compiler :as comp] 11 | [clojure.core.typed.current-impl :as impl] 12 | [cljs.env :as env] 13 | [clojure.core.typed.util-cljs :as ucljs] 14 | [clojure.core.typed.check-ns-common :as chk-ns])) 15 | 16 | (defn check-ns-info 17 | [ns-or-syms opt] 18 | (ucljs/with-cljs-typed-env 19 | (comp/with-core-cljs 20 | nil 21 | #(chk-ns/check-ns-info impl/clojurescript ns-or-syms opt)))) 22 | 23 | (defn check-ns 24 | [ns-or-syms opt] 25 | (ucljs/with-cljs-typed-env 26 | (comp/with-core-cljs 27 | nil 28 | #(chk-ns/check-ns impl/clojurescript ns-or-syms opt)))) 29 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/core/typed/analyzer_api_intercept.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Ambrose Bonnaire-Sergeant, Rich Hickey & contributors. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.core.typed.analyzer-api-intercept 10 | (:require [cljs.analyzer.api :as api] 11 | [clojure.core.typed.ast-utils :as ast-u])) 12 | 13 | (def ops-found (atom #{})) 14 | 15 | (defn reset-found [] 16 | (reset! ops-found #{})) 17 | 18 | (defn walk-collect-ops [{:keys [op children] :as node}] 19 | (when-not (some (partial = op) @ops-found) 20 | (swap! ops-found #(conj % op))) 21 | (when children 22 | (doseq [c children] 23 | (walk-collect-ops (c node))))) 24 | 25 | (defn analyze 26 | ([env form] (analyze env form nil {})) 27 | ([env form x opts] 28 | (let [result (api/analyze env form x opts)] 29 | (walk-collect-ops result) 30 | ;(println ops-found) 31 | result))) 32 | 33 | (defn empty-env [] 34 | (api/empty-env)) 35 | -------------------------------------------------------------------------------- /src/test/cljs/cljs/core/typed/test/csp.cljs: -------------------------------------------------------------------------------- 1 | ; from David Nolen's blog 2 | (ns cljs.core.typed.test.csp 3 | (:refer-clojure :exclude [map]) 4 | (:require [cljs.core.async :as async 5 | :refer [! chan put! timeout]] 6 | [clojure.string :as string] 7 | [cljs.core.typed.test.dnolen.utils.dom :refer [by-id set-html! offset]] 8 | [cljs.core.typed.test.dnolen.utils.reactive :refer [listen map]]) 9 | (:require-macros [cljs.core.async.macros :refer [go alt!]])) 10 | 11 | (def c (chan)) 12 | 13 | (defn render [q] 14 | (apply str 15 | (for [p (reverse q)] 16 | (str "
Process " p "
")))) 17 | 18 | #_(go (while true (! c 1))) 19 | #_(go (while true (! c 2))) 20 | #_(go (while true (! c 3))) 21 | 22 | (defn peekn 23 | "Returns vector of (up to) n items from the end of vector v" 24 | [v n] 25 | (if (> (count v) n) 26 | (subvec v (- (count v) n)) 27 | v)) 28 | 29 | (let [el (by-id "ex0") 30 | out (by-id "ex0-out")] 31 | (go (loop [q []] 32 | (set-html! out (render q)) 33 | (recur (-> (conj q ( (t/U nil js/HTMLElement)]) 9 | (defn by-id [id] 10 | (.getElementById js/document id)) 11 | 12 | (ann set-html! [js/HTMLElement t/JSString -> t/JSString]) 13 | (defn set-html! [el s] 14 | (set! (.-innerHTML el) s)) 15 | 16 | (ann set-text! [js/Element (t/U t/JSString t/JSNumber) -> js/Window]) 17 | (defn set-text! [el s] 18 | (dom/setTextContent el s)) 19 | 20 | (ann set-class! [(t/U js/Node nil) t/JSString -> t/Any]) 21 | (defn set-class! [el name] 22 | (classes/set el name)) 23 | 24 | (ann add-class! [(t/U nil js/Node) t/JSString -> t/JSBoolean]) 25 | (defn add-class! [el name] 26 | (classes/add el name)) 27 | 28 | (ann remove-class! [(t/U js/Node nil) (t/U nil t/JSString) -> t/JSBoolean]) 29 | (defn remove-class! [el name] 30 | (classes/remove el name)) 31 | 32 | (ann tag-match [t/JSString -> [js/HTMLElement -> t/Any]]) 33 | (defn tag-match [tag] 34 | (fn [el] 35 | (when-let [tag-name (.-tagName el)] 36 | (t/ann-form tag-name t/JSString) 37 | (= tag (.toLowerCase tag-name))))) 38 | 39 | (ann el-matcher [t/Any -> [t/Any -> t/Any]]) 40 | (defn el-matcher [el] 41 | (fn [other] (identical? other el))) 42 | 43 | (ann by-tag-name [(t/U nil js/Document js/Element) (t/U nil t/JSString) 44 | -> (t/U nil (ISeq js/Element))]) 45 | (defn by-tag-name [el tag] 46 | (prim-seq (dom/getElementsByTagNameAndClass tag nil el))) 47 | 48 | (ann offset [(t/U nil js/Element) -> '[t/JSNumber t/JSNumber]]) 49 | (defn offset [el] 50 | [(style/getPageOffsetLeft el) (style/getPageOffsetTop el)]) 51 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/core/typed/check_form_cljs.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Ambrose Bonnaire-Sergeant, Rich Hickey & contributors. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.core.typed.check-form-cljs 10 | (:require [clojure.core.typed.check-form-common :as chk-form] 11 | [clojure.core.typed.analyze-cljs :as ana-cljs] 12 | [clojure.core.typed.check-cljs :as chk-cljs] 13 | [clojure.core.typed.util-cljs :as ucljs] 14 | [cljs.env :as env] 15 | [cljs.compiler :as comp] 16 | [clojure.core.typed.current-impl :as impl])) 17 | 18 | (defn config-map [] 19 | {:impl impl/clojurescript 20 | :unparse-ns (ucljs/cljs-ns) 21 | :ast-for-form ana-cljs/ast-for-form 22 | :check-expr chk-cljs/check-expr}) 23 | 24 | (defn check-form-info 25 | [form & opt] 26 | (let [config (config-map)] 27 | (impl/with-full-impl (:impl config) 28 | (apply chk-form/check-form-info config 29 | form opt)))) 30 | 31 | (defn check-form-cljs 32 | "Check a single form with an optional expected type. 33 | Intended to be called from Clojure. For evaluation at the Clojurescript 34 | REPL see cf." 35 | [form expected expected-provided?] 36 | (ucljs/with-cljs-typed-env 37 | (comp/with-core-cljs 38 | nil 39 | #(let [config (config-map)] 40 | (impl/with-full-impl (:impl config) 41 | (chk-form/check-form* config 42 | form expected expected-provided?)))))) 43 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/core/typed/util_cljs.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Ambrose Bonnaire-Sergeant, Rich Hickey & contributors. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^:skip-wiki clojure.core.typed.util-cljs 10 | (:require [clojure.core.typed.current-impl :as impl] 11 | [cljs.analyzer :as ana] 12 | [clojure.core.typed.emit-form-cljs :as emit-form] 13 | [cljs.compiler :as comp] 14 | [cljs.env :as env])) 15 | 16 | (def default-env (env/default-compiler-env)) 17 | 18 | (defmacro with-cljs-typed-env [& body] 19 | `(env/with-compiler-env (or env/*compiler* default-env) 20 | ~@body)) 21 | 22 | (defn var-exists? [env prefix suffix] 23 | (let [compiler env/*compiler* 24 | _ (assert compiler)] 25 | (contains? (get-in @compiler [::ana/namespaces prefix :defs]) 26 | suffix))) 27 | 28 | (defn resolve-var [nsym sym] 29 | {:post [((some-fn symbol? nil?) %)]} 30 | (let [unresolved? (atom false) 31 | r (with-cljs-typed-env 32 | (binding [ana/*cljs-ns* nsym] 33 | (comp/with-core-cljs 34 | nil 35 | #(ana/resolve-var (ana/empty-env) sym 36 | (fn [env ns sym] 37 | (when-not (var-exists? env ns sym) 38 | (reset! unresolved? true))))))) 39 | sym* (when-not @unresolved? 40 | (:name r)) 41 | _ (when sym* 42 | (assert (symbol? sym*) sym*) 43 | (assert (namespace sym*) sym*))] 44 | ;(prn sym sym*) 45 | sym*)) 46 | 47 | (defn cljs-ns [] 48 | ana/*cljs-ns*) 49 | 50 | (defn emit-form [ast] 51 | (emit-form/emit-form ast)) 52 | 53 | (defmacro with-core-cljs-typed [& body] 54 | `(comp/with-core-cljs 55 | nil 56 | #(do (when-not (get-in @env/*compiler* [::ana/namespaces 'cljs.core.typed :defs]) 57 | (ana/analyze-file "cljs/core/typed.cljs")) 58 | ~@body))) 59 | -------------------------------------------------------------------------------- /deps.edn: -------------------------------------------------------------------------------- 1 | {:paths ["src/main/clojure" 2 | "src/main/cljs" 3 | ] 4 | :deps {org.clojure/clojure {:mvn/version "1.10.0-beta5"} 5 | org.clojure/core.typed {:local/root "../module-check"} 6 | org.clojure/core.typed.rt {:local/root "../module-rt"} 7 | org.clojure/clojurescript {:mvn/version "1.10.373"}} 8 | :aliases {:nREPL 9 | {:extra-paths ["script"] 10 | :extra-deps 11 | {nrepl/nrepl {:mvn/version "0.4.5"} 12 | cider/piggieback {:mvn/version "0.3.8"}} 13 | :main-opts ["-m" "nrepl.cmdline" 14 | "--interactive"]} 15 | 16 | :reply 17 | {:extra-deps 18 | {reply {:mvn/version "0.4.1"}} 19 | :main-opts ["-m" "reply.main"]} 20 | 21 | :start-repl 22 | {:extra-paths ["script"] 23 | :extra-deps 24 | {com.bhauman/rebel-readline {:mvn/version "0.1.4"}} 25 | :main-opts ["-m" "start-repl"]} 26 | 27 | :clj-1.10.0-beta5 {:override-deps {org.clojure/clojure {:mvn/version "1.10.0-beta5"}}} 28 | :test 29 | {:extra-paths ["src/test/clojure" 30 | "src/test/cljs" 31 | "../module-check/src/test/clojure" 32 | "../module-check/src/test/cljs"] 33 | :extra-deps {org.clojure/tools.nrepl {:mvn/version "0.2.6" 34 | :exclusions [org.clojure/clojure]} 35 | org.clojure/core.async {:mvn/version "0.3.465" 36 | :exclusions [org.clojure/tools.analyzer.jvm]} 37 | org.clojure/tools.trace {:mvn/version "0.7.5" 38 | :exclusions [org.clojure/clojure]} 39 | org.clojure/test.check {:mvn/version "0.9.0"} 40 | com.gfredericks/test.chuck {:mvn/version "0.2.6"}}} 41 | :runner 42 | {:extra-deps {org.typedclojure/test-runner 43 | {:git/url "https://github.com/typedclojure/test-runner" 44 | :sha "2d7af465ac90b2d083753daf251bdb4a09ae97cd"}} 45 | :main-opts ["-m" "cognitect.test-runner" 46 | "-d" "src/test/clojure/clojure/core/typed/test" 47 | "-r" ".*" 48 | ;"-w" "clojure.test.junit/with-junit-output" 49 | ;"-o" "junit-output.xml" 50 | ]}}} 51 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/core/typed/check/dot_cljs.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Ambrose Bonnaire-Sergeant, Rich Hickey & contributors. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.core.typed.check.dot-cljs 10 | (:require [clojure.core.typed.type-rep :as r] 11 | [clojure.core.typed.utils :as u] 12 | [clojure.core.typed.type-ctors :as c] 13 | [clojure.core.typed.jsnominal-env :as jsnom] 14 | [clojure.core.typed.parse-unparse :as prs] 15 | [clojure.core.typed.check.funapp :as funapp] 16 | [clojure.core.typed.errors :as err])) 17 | 18 | (defn check-dot [check {:keys [target field method args] :as dot-expr} expected] 19 | (let [ctarget (check target) 20 | target-t (-> ctarget u/expr-type r/ret-t) 21 | resolved (let [t (c/fully-resolve-type target-t)] 22 | ;TODO DataType 23 | (when ((some-fn r/JSNominal? 24 | r/JSString? 25 | #_r/DataType?) t) 26 | t))] 27 | (if resolved 28 | (cond 29 | field 30 | (let [field-type (cond 31 | (r/JSString? resolved) 32 | (jsnom/get-field 'string nil field) 33 | (r/JSNominal? resolved) 34 | (jsnom/get-field (:name resolved) (:poly? resolved) field)) 35 | _ (assert field-type (str "Don't know how to get field " field 36 | " from " (prs/unparse-type resolved)))] 37 | (assoc dot-expr 38 | u/expr-type (r/ret field-type))) 39 | :else 40 | (let [method-type (cond 41 | (r/JSString? resolved) 42 | (jsnom/get-method 'string nil method) 43 | (r/JSNominal? resolved) 44 | (jsnom/get-method (:name resolved) (:poly? resolved) method)) 45 | _ (assert method-type (str "Don't know how to call method " method 46 | " from " (prs/unparse-type resolved))) 47 | cargs (mapv check args) 48 | actual (funapp/check-funapp nil cargs (r/ret method-type) (map u/expr-type cargs) 49 | expected)] 50 | (assoc dot-expr 51 | u/expr-type actual))) 52 | (err/tc-delayed-error (str "Don't know how to use type " (prs/unparse-type target-t) 53 | " with " 54 | (if field (str "field " field) 55 | (str "method " method))) 56 | :return 57 | (assoc dot-expr 58 | u/expr-type (r/ret (or (when expected 59 | (r/ret-t expected)) 60 | (r/TCError-maker)))))))) 61 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | * Next 2 | 3 | [ ] add JS primitives 4 | [x] cljs.core.typed/JSUndefined 5 | * 'undefined' in TypeScript 6 | * idea 1: nil expands to (U nil Undefined) internally, but always elide Undefined 7 | when pretty-printing a union that includes both nil and Undefined. 8 | * This to avoids: 9 | Expected: nil, Given: nil 10 | since 11 | Expected: (U Undefined nil), Given: nil 12 | * Problem: lots of special casing for Nil? in the type checker 13 | * support nil?/undefined?/some? predicates 14 | * recognize undefined as a false value 15 | * (= x nil) ;=> (is x (U nil Undefined)) 16 | * idea 2: New type JSNull 17 | (U JSNull JSUndefined) <: nil 18 | nil Any]) 28 | (f nil) 29 | * structural equality on `nil` should be enhanced 30 | (let [x :- JSNull nil 31 | y :- nil nil 32 | z :- JSUndefined ...] 33 | (= x y z)) 34 | ; true ; tt | ff 35 | [x] support undefined? predicates 36 | * unit tests for 'if' 37 | [*] cljs.core.typed/JSNumber 38 | * 'number' in TypeScript 39 | * (ann number? (Pred JSNumber)) 40 | [*] cljs.core.typed/JSBoolean 41 | * 'boolean' in TypeScript 42 | [*] cljs.core.typed/JSString 43 | * 'string' in TypeScript 44 | [*] cljs.core.typed/JSSymbol 45 | * 'symbol' in TypeScript 46 | [*] add cljs.core.typed/JSObject 47 | * any non-primitive type 48 | * 'object' in TypeScript 49 | * https://blog.mariusschulz.com/2017/02/24/typescript-2-2-the-object-type 50 | * 'Object' in Google Closure (or 'Object' maybe?) 51 | * https://github.com/google/closure-compiler/wiki/A-word-about-the-type-Object 52 | [*] rename int => cljs.core.typed/JSInteger 53 | * for `integer?` 54 | [ ] create JSObj type 55 | * analogous to HMap 56 | * Use undefined to signal optional 57 | * (JSObj {:a (t/U Node t/JSUndefined) 58 | :b}) 59 | [ ] implement ann-js 60 | [ ] implement ann-jsclass 61 | [ ] implement ann-jsinterface 62 | [ ] implement ann-jsalias 63 | [ ] support js/undefined top-level builtin classes 64 | * eg. js/String, js/Symbol, js/Function 65 | * Note. js/Object is 'Object' in TypeScript 66 | * Note. js/Function is 'Function' in Google Closure 67 | * Note. js/Array is 'Array' in Google Closure 68 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects 69 | * https://funcool.github.io/clojurescript-unraveled/ 70 | [ ] add common Regex annotation for #"" 71 | [ ] remove cljs.core.typed/IPersistentMap etc. 72 | [ ] remove ArrayCLJS 73 | * replace with js/Array 74 | [ ] remove FunctionCLJS 75 | * replace with js/Function 76 | [ ] fix cct.subtype/resolve-JS-reference function 77 | [ ] remove letfn> etc. 78 | * replace with non-> versions 79 | * rename primitives to lower case (or namespaced in `js`?) 80 | * JSboolean, JSsymbol, JSstring, JSnull, JSundefined 81 | * js/boolean, js/symbol, js/string, js/null, js/undefined 82 | * handle special Closure types 83 | * possibly prefix with `js`? 84 | * js/IObject, js/IArrayLike, js/IThenable 85 | 86 | # Later 87 | 88 | * add heterogeneous object type 89 | * optional entries 90 | * delete Array stuff for CLJ/CLJS 91 | * revise default js-nominal mappings 92 | * pprint JSUndefined and JSNull to `nil` when appropriate 93 | * `boolean?` tests for primitive boolean 94 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/core/typed/emit_form_cljs.clj: -------------------------------------------------------------------------------- 1 | ; Copyright (c) Rich Hickey. All rights reserved. 2 | ; The use and distribution terms for this software are covered by the 3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ; which can be found in the file epl-v10.html at the root of this distribution. 5 | ; By using this software in any fashion, you are agreeing to be bound by 6 | ; the terms of this license. 7 | ; You must not remove this notice, or any other, from this software. 8 | 9 | ;copied from clojure.tools.analyzer.passes.js.emit-form 10 | (ns ^:skip-wiki clojure.core.typed.emit-form-cljs 11 | (:require [clojure.tools.analyzer.passes 12 | [emit-form :as default] 13 | [uniquify :refer [uniquify-locals]]] 14 | [clojure.string :as s] 15 | [cljs.tagged-literals :refer [->JSValue]]) 16 | (:import cljs.tagged_literals.JSValue 17 | java.io.Writer)) 18 | 19 | (defmulti -emit-form (fn [{:keys [op]} _] op)) 20 | 21 | (defn -emit-form* 22 | [{:keys [form] :as ast} opts] 23 | (let [expr (-emit-form ast opts)] 24 | (if-let [m (and (instance? clojure.lang.IObj expr) 25 | (meta form))] 26 | (with-meta expr (merge m (meta expr))) 27 | expr))) 28 | 29 | (defn emit-form 30 | "Return the form represented by the given AST 31 | Opts is a set of options, valid options are: 32 | * :hygienic 33 | * :qualified-symbols" 34 | {:pass-info {:walk :none :depends #{#'uniquify-locals} :compiler true}} 35 | ([ast] (emit-form ast #{})) 36 | ([ast opts] 37 | (binding [default/-emit-form* -emit-form*] 38 | (-emit-form* ast opts)))) 39 | 40 | (defn emit-hygienic-form 41 | "Return an hygienic form represented by the given AST" 42 | {:pass-info {:walk :none :depends #{#'uniquify-locals} :compiler true}} 43 | [ast] 44 | (binding [default/-emit-form* -emit-form*] 45 | (-emit-form* ast #{:hygienic}))) 46 | 47 | (defmethod -emit-form :default 48 | [ast opts] 49 | (default/-emit-form ast opts)) 50 | 51 | (defmethod -emit-form :js 52 | [{:keys [segs args]} opts] 53 | (list* 'js* (s/join "~{}" segs) (mapv #(-emit-form* % opts) args))) 54 | 55 | (defmethod -emit-form :js-object 56 | [{:keys [keys vals]} opts] 57 | (->JSValue (zipmap keys (map #(-emit-form* % opts) vals)))) 58 | 59 | (defmethod -emit-form :js-array 60 | [{:keys [items]} opts] 61 | (->JSValue (mapv #(-emit-form* % opts) items))) 62 | 63 | (defmethod print-method JSValue [^JSValue o ^Writer w] 64 | (.write w "#js ") 65 | (.write w (str (.val o)))) 66 | 67 | (defmethod -emit-form :deftype 68 | [{name :t :keys [fields pmask body]} opts] 69 | (list 'deftype* name (map #(-emit-form* % opts) fields) pmask 70 | (-emit-form* body opts))) 71 | 72 | (defmethod -emit-form :defrecord 73 | [{name :t :keys [fields pmask body]} opts] 74 | (list 'defrecord* name (map #(-emit-form* % opts) fields) pmask 75 | (-emit-form* body opts))) 76 | 77 | (defmethod -emit-form :case-then 78 | [{:keys [then]} opts] 79 | (-emit-form* then opts)) 80 | 81 | (defmethod -emit-form :case-test 82 | [{:keys [test]} opts] 83 | (-emit-form* test opts)) 84 | 85 | (defmethod -emit-form :case 86 | [{:keys [test nodes default]} opts] 87 | `(case* ~(-emit-form* test opts) 88 | ~@(reduce (fn [acc {:keys [tests then]}] 89 | (-> acc 90 | (update-in [0] conj (mapv #(-emit-form* % opts) tests)) 91 | (update-in [1] conj (-emit-form* then opts)))) 92 | [[] []] nodes) 93 | ~(-emit-form* default opts))) 94 | 95 | -------------------------------------------------------------------------------- /src/test/clojure/clojure/core/typed/test/cljs_utils.clj: -------------------------------------------------------------------------------- 1 | (ns clojure.core.typed.test.cljs-utils 2 | (:require [clojure.core.typed :as clj-t] 3 | [cljs.core.typed :as cljs-t] 4 | [cljs.repl.rhino :as rhino] 5 | [cljs.repl :as repl] 6 | [cljs.analyzer :as ana] 7 | [clojure.core.typed.analyze-cljs :as ana-cljs] 8 | [clojure.core.typed.errors :as err] 9 | [clojure.set :as set])) 10 | 11 | (cljs-t/load-if-needed) 12 | 13 | (require '[clojure.test :refer :all :as test] 14 | '[cljs.core.typed :as t] 15 | '[clojure.core.typed.type-ctors :as c] 16 | '[clojure.core.typed.type-rep :as r] 17 | '[clojure.core.typed.current-impl :as impl] 18 | '[clojure.core.typed.parse-unparse :as prs] 19 | '[clojure.core.typed.subtype :as sub] 20 | '[clojure.core.typed.util-cljs :as ucljs] 21 | '[clojure.core.typed.coerce-utils :as coerce] 22 | '[clojure.core.typed.test.common-utils :as common-test] 23 | '[clojure.core.typed.check-form-cljs :as chk-frm-cljs] 24 | '[cljs.env :as env]) 25 | 26 | (defmacro cljs [& body] 27 | `(impl/with-cljs-impl 28 | (ucljs/with-cljs-typed-env 29 | ~@body))) 30 | 31 | (defmacro is-cljs [& body] 32 | `(is (cljs ~@body))) 33 | 34 | (defmacro is-cf [& body] 35 | `(is-cljs (t/cf ~@body) true)) 36 | 37 | (defn check-opt [opt] 38 | #_(assert (empty? (set/difference (set (keys opt)) 39 | #{:expected :ret})))) 40 | 41 | (defn tc-common* [frm {{:keys [syn provided?]} :expected-syntax :keys [expected-ret] :as opt}] 42 | (let [nsym (gensym 'clojure.core.typed.test.temp)] 43 | (check-opt opt) 44 | `(binding [ana/*cljs-ns* ana/*cljs-ns*] 45 | (ucljs/with-cljs-typed-env 46 | (let [expected-ret# ~expected-ret 47 | ; first element of this list must be the symbol ns 48 | ns-form# '(~'ns ~nsym 49 | ;~'(:refer-clojure :exclude [fn]) 50 | ~'(:require [cljs.core.typed :as t :include-macros true] 51 | [cljs.core :as core])) 52 | _# (ana/analyze (ana/empty-env) ns-form#)] 53 | (t/check-form-info 54 | '~frm 55 | :expected-ret expected-ret# 56 | :expected '~syn 57 | :type-provided? ~provided?)))))) 58 | 59 | (defmacro tc-e 60 | "Type check an an expression in namespace that :refer's 61 | all of clojure.core.typed (aliased to t) and aliases clojure.core 62 | to core. 63 | 64 | Takes one form and then options, and returns true if the form checks 65 | with the expected input/output types according to the provided options. 66 | 67 | The first form in the options can be a static type syntax scoped 68 | in the new namespace. This is disambiguated with a call to keyword? 69 | (literal keywords aren't valid type syntax). 70 | 71 | eg. (tc-e (+ 1 1) Num) 72 | ;=> Num 73 | 74 | Keyword Options: 75 | 76 | :expected-ret An expected ret, evaluated in the current namespace (not the new 77 | one that refers c.c.t). Cannot be provided in combination with the implicit 78 | first option as a type, as above. 79 | :ret Check the return TCResult of this expression against this ret. Evaluated 80 | in the current namespace." 81 | [frm & opts] 82 | (apply common-test/tc-e tc-common* frm opts)) 83 | 84 | (defmacro is-tc-e [& body] 85 | `(test/is (do (tc-e ~@body) 86 | true))) 87 | 88 | (defmacro is-tc-err [& body] 89 | `(test/is (tc-err ~@body))) 90 | 91 | (defmacro tc-err [frm & opts] 92 | (apply common-test/tc-err tc-common* frm opts)) 93 | 94 | (defn subtype? [& rs] 95 | (impl/with-cljs-impl 96 | (sub/reset-subtype-cache) 97 | (apply sub/subtype? rs))) 98 | 99 | (defmacro sub? [s t] 100 | `(impl/with-cljs-impl 101 | (sub/reset-subtype-cache) 102 | (subtype? (prs/parse-type '~s) 103 | (prs/parse-type '~t)))) 104 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/core/typed/analyze_cljs.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Ambrose Bonnaire-Sergeant, Rich Hickey & contributors. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^:skip-wiki clojure.core.typed.analyze-cljs 10 | (:refer-clojure :exclude [extenders]) 11 | (:require [clojure.core.typed.current-impl :as impl] 12 | [clojure.core.typed.util-cljs :as uc] 13 | [clojure.core.typed.analyzer-api-intercept :as api] 14 | [cljs.analyzer :as ana] 15 | [clojure.tools.reader :as reader] 16 | [clojure.java.io :as io] 17 | [cljs.env :as env] 18 | [cljs.util :as cljsu])) 19 | 20 | (declare ast-for-form) 21 | 22 | (defn ast-for-form-in-ns 23 | "Returns an AST node for the form 24 | analyzed in the given namespace" 25 | [nsym form] 26 | (uc/with-cljs-typed-env 27 | (binding [ana/*cljs-ns* nsym] 28 | (ast-for-form form {:eval-fn false})))) 29 | 30 | ; FIXME reintroduce hygienic transformation! 31 | (defn ast-for-form 32 | "Returns an AST node for the form" 33 | [form {:keys [expected eval-fn] :as opt}] 34 | ;; TODO support bindings-atom, as in c.c.t.analyze-clj 35 | ;; TODO propagate analyzer env from opt 36 | (uc/with-cljs-typed-env 37 | (let [ast (api/analyze (api/empty-env) form)] 38 | ;(prn "ast-for-form" (:op ast)) 39 | (if eval-fn 40 | (eval-fn ast opt) 41 | ast)))) 42 | 43 | ; like cljs.analyze/analyze-form-seq, but returns a vector of 44 | ; analysis results 45 | (defn analyze-form-seq 46 | ([forms] 47 | (analyze-form-seq forms nil)) 48 | ([forms opts] 49 | (uc/with-cljs-typed-env 50 | (let [env (assoc (api/empty-env) :build-options opts)] 51 | (binding [ana/*file-defs* nil 52 | ;#?@(:clj [*unchecked-if* false]) 53 | ana/*unchecked-if* false 54 | ana/*cljs-ns* 'cljs.user 55 | ana/*cljs-file* nil 56 | reader/*alias-map* (or reader/*alias-map* {})] 57 | (loop [ns nil forms forms 58 | out []] 59 | (if (some? forms) 60 | (let [form (first forms) 61 | env (assoc env :ns (ana/get-namespace ana/*cljs-ns*)) 62 | ast (api/analyze env form nil opts)] 63 | (if (= (:op ast) :ns) 64 | (recur (:name ast) (next forms) (conj out ast)) 65 | (recur ns (next forms) (conj out ast)))) 66 | out))))))) 67 | 68 | ;; FIXME hygienic transformation 69 | (defn ast-for-ns 70 | "Returns a vector of AST nodes contained 71 | in the given namespace symbol nsym" 72 | [nsym] 73 | {:pre [(symbol? nsym)]} 74 | (analyze-form-seq (ana/forms-seq* (io/reader (cljsu/ns->source nsym))))) 75 | 76 | (let [get-namespace (delay (impl/dynaload 'cljs.analyzer/get-namespace))] 77 | (defn extenders 78 | "Returns a set of descendants for a protocol" 79 | [psym] 80 | {:pre [(symbol? psym) 81 | (namespace psym)]} 82 | (assert nil "FIXME extenders") 83 | (require 'cljs.analyzer) 84 | (or (get-in (@get-namespace (symbol (namespace psym))) 85 | [:defs (symbol (name psym)) :impls]) 86 | #{}))) 87 | 88 | (let [analyze-symbol (delay (impl/dynaload 'cljs.analyzer/analyze-symbol)) 89 | empty-env (delay (impl/dynaload 'cljs.analyzer/empty-env))] 90 | (defn analyze-qualified-symbol 91 | "Return a var expr that the fully qualified symbol names" 92 | [sym] 93 | {:pre [(symbol? sym)] 94 | :post [(= :var (:op %))]} 95 | ;; is this still correct? 96 | (assert nil "FIXME analyze-qualified-symbol") 97 | (@analyze-symbol (@empty-env) sym))) 98 | 99 | ;(analyze-qualified-symbol 'cljs.core/ISeq) 100 | ;(analyze-qualified-symbol 'cljs.core.SubVec) 101 | 102 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | core.typed.cljs 5 | An optional type system for ClojureScript — full system for annotating and type-checking. 6 | core.typed.cljs 7 | 8 | 9 | org.clojure 10 | core.typed-pom 11 | 0.5.4-SNAPSHOT 12 | 13 | 14 | 15 | 16 | 17 | com.theoryinpractise 18 | clojure-maven-plugin 19 | 1.7.1 20 | 21 | 22 | clojure-compile 23 | compile 24 | 25 | 26 | clojure-test 27 | test 28 | 29 | 30 | 31 | -Xmx2048m 32 | true 33 | true 34 | 35 | false 36 | true 37 | 38 | !clojure.core.typed.util-cljs 39 | !clojure.core.typed.test.cljs 40 | !cljs.core.typed.* 41 | !clojure.core.typed.base-env-cljs 42 | !clojure.core.typed.check-form-cljs 43 | !clojure.core.typed.check-ns-cljs 44 | !clojure.core.typed.test.cljs-utils 45 | 46 | 47 | clojure.core.typed.test.* 48 | 49 | 50 | src/main/clojure 51 | src/main/cljs 52 | 53 | 54 | src/test/clojure 55 | src/test/cljs 56 | 57 | 58 | 59 | 60 | maven-jar-plugin 61 | 2.4 62 | 63 | 64 | default-jar 65 | package 66 | 67 | jar 68 | 69 | 70 | 71 | 72 | 92 | 93 | 94 | 95 | 96 | 97 | org.clojure 98 | core.typed 99 | 0.5.4-SNAPSHOT 100 | 101 | 102 | org.clojure 103 | clojurescript 104 | 1.10.373 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /src/test/cljs/cljs/core/typed/test/dnolen/utils/reactive.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.core.typed.test.dnolen.utils.reactive 2 | (:refer-clojure :exclude [map filter remove distinct]) 3 | (:require [goog.events :as events] 4 | [goog.events.EventType] 5 | [goog.dom :as gdom] 6 | [cljs.core.async :refer [>! go>]] 12 | [cljs.core.typed :refer [def-alias typed-deps ann]]) 13 | (:import goog.events.EventType)) 14 | 15 | (typed-deps cljs.core.typed.async 16 | cljs.core.typed.test.dnolen.utils.dom 17 | cljs.core.typed.test.dnolen.utils.helpers) 18 | 19 | (ann ^:no-check atom? (predicate (Atom Nothing Any))) 20 | (defn atom? [x] 21 | (instance? Atom x)) 22 | 23 | (ann keyword->event-type (I (IMap Any string) 24 | [Any -> (U nil string)])) 25 | (def keyword->event-type 26 | {:keyup goog.events.EventType.KEYUP 27 | :keydown goog.events.EventType.KEYDOWN 28 | :keypress goog.events.EventType.KEYPRESS 29 | :click goog.events.EventType.CLICK 30 | :dblclick goog.events.EventType.DBLCLICK 31 | :mouseover goog.events.EventType.MOUSEOVER 32 | :mouseout goog.events.EventType.MOUSEOUT 33 | :mousemove goog.events.EventType.MOUSEMOVE}) 34 | 35 | (ann listen (Fn [js/EventTarget Any -> (Chan js/Event)] 36 | [js/EventTarget Any Any -> (Chan js/Event)])) 37 | (defn listen 38 | ([el type] (listen el type false)) 39 | ([el type prevent-default?] 40 | (let [out (chan> js/Event)] 41 | (events/listen el (keyword->event-type type) 42 | (fn [^{:ann 'js/EventTarget} e] 43 | (if (atom? prevent-default?) 44 | (when @prevent-default? 45 | (.preventDefault e)) 46 | (when prevent-default? 47 | (.preventDefault e))) 48 | (put! out e))) 49 | out))) 50 | 51 | (ann map (All [a b] 52 | [[a -> b] (Chan a) -> (Chan b)])) 53 | (defn map [f in] 54 | (let [out (chan> b)] 55 | (go> b 56 | (loop [] 57 | (if-let [x (! out (f x)) 59 | (recur)) 60 | (close! out)))) 61 | out)) 62 | 63 | (ann filter (All [a b] 64 | [[a -> Any :filters {:then (is b 0)}] (Chan a) -> (Chan b)])) 65 | (defn filter [pred in] 66 | (let [out (chan> b)] 67 | (go> b 68 | (loop [] 69 | (if-let [x (! out x)) 71 | (recur)) 72 | (close! out)))) 73 | out)) 74 | 75 | (ann remove (All [a b] 76 | [[a -> Any :filters {:else (is b 0)}] (Chan a) -> (Chan b)])) 77 | (defn remove [f source] 78 | (let [out (chan> b)] 79 | (go> x 80 | (loop [] 81 | (if-let [v (! out v)) 83 | (recur)) 84 | (close! out)))) 85 | out)) 86 | 87 | (ann distinct (All [x] [(Chan x) -> (Chan x)])) 88 | (defn distinct [in] 89 | (let [out (chan> x)] 90 | (go> x 91 | (loop [last nil] 92 | (if-let [x (! out x)) 94 | (recur x)) 95 | (close! out)))) 96 | out)) 97 | 98 | (ann fan-in (All [x] [(U nil (ISeqable (Chan x))) -> (Chan x)])) 99 | (defn fan-in [ins] 100 | (let [out (chan> x)] 101 | (go> x 102 | (while true 103 | (let [[x] (alts! ins)] 104 | (>! out x)))) 105 | out)) 106 | 107 | (ann toggle (All [x] [(Chan x) -> '{:chan (Chan Any) 108 | :control (Chan Any)}])) 109 | (defn toggle [in] 110 | (let [out (chan> Any) 111 | control (chan> Any)] 112 | (go (loop [on true] 113 | (recur 114 | (alt! 115 | in ([x] (when on (>! out x)) on) 116 | control ([x] x))))) 117 | {:chan out 118 | :control control})) 119 | 120 | (defn mouse-enter [el] 121 | (let [matcher (dom/el-matcher el)] 122 | (->> (listen el :mouseover) 123 | (filter 124 | (fn [e] 125 | (and (identical? el (.-target e)) 126 | (if-let [rel (.-relatedTarget e)] 127 | (nil? (gdom/getAncestor rel matcher)) 128 | true)))) 129 | (map (constantly :enter))))) 130 | 131 | (defn mouse-leave [el] 132 | (let [matcher (dom/el-matcher el)] 133 | (->> (listen el :mouseout) 134 | (filter 135 | (fn [e] 136 | (and (identical? el (.-target e)) 137 | (if-let [rel (.-relatedTarget e)] 138 | (nil? (gdom/getAncestor rel matcher)) 139 | true)))) 140 | (map (constantly :leave))))) 141 | 142 | (defn hover [el] 143 | (distinct (fan-in [(mouse-enter el) (mouse-leave el)]))) 144 | 145 | (defn hover-child [el tag] 146 | (let [matcher (dom/tag-match tag) 147 | matches (dom/by-tag-name el tag) 148 | over (->> (listen el :mouseover) 149 | (map 150 | #(let [target (.-target %)] 151 | (if (matcher target) 152 | target 153 | (if-let [el (gdom/getAncestor target matcher)] 154 | el 155 | :no-match)))) 156 | (remove #{:no-match}) 157 | (map #(index-of matches %))) 158 | out (->> (listen el :mouseout) 159 | (filter 160 | (fn [e] 161 | (and (matcher (.-target e)) 162 | (not (matcher (.-relatedTarget e)))))) 163 | (map (constantly :clear)))] 164 | (distinct (fan-in [over out])))) 165 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/core/typed/jsnominal_env.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Ambrose Bonnaire-Sergeant, Rich Hickey & contributors. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns ^:skip-wiki clojure.core.typed.jsnominal-env 10 | (:refer-clojure :exclude [get-method]) 11 | (:require [clojure.core.typed.type-rep :as r] 12 | [clojure.core.typed.type-ctors :as c] 13 | [clojure.core.typed.contract-utils :as con] 14 | [clojure.core.typed :as t] 15 | [clojure.core.typed.current-impl :as impl] 16 | [clojure.core.typed.env :as env]) 17 | (:import (clojure.core.typed.type_rep Scope))) 18 | 19 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 20 | ;; JSNominal 21 | 22 | (t/defalias JSNominalEntry 23 | "A map entry for a JSNominal type." 24 | '{:jsnominal r/Type 25 | :fields (t/Map t/Sym (t/U Scope r/Type)) 26 | :methods (t/Map t/Sym (t/U Scope r/Type)) 27 | :ctors (t/U Scope r/Type nil) 28 | :ancestors (t/Set (t/U Scope r/Type))}) 29 | 30 | (t/defalias JSNominalEnv 31 | "A map of symbols of JSNomainalEntry's" 32 | (t/Map t/Sym JSNominalEntry)) 33 | 34 | (defn jsnominal-env [] 35 | {:post [(map? %)]} 36 | (impl/jsnominal-env)) 37 | 38 | (def jsnominal-env? 39 | (con/hash-c? symbol? 40 | (con/hmap-c? :jsnominal r/Type? 41 | :fields (con/hash-c? symbol? (some-fn r/Scope? r/Type?)) 42 | :methods (con/hash-c? symbol? (some-fn r/Scope? r/Type?)) 43 | :ctor (some-fn nil? r/Scope? r/Type?) 44 | :ancestors (con/set-c? (some-fn r/Scope? r/Type?))))) 45 | 46 | (t/ann init-jsnominal-entry [r/Type -> JSNominalEntry]) 47 | (defn init-jsnominal-entry [nom] 48 | {:post [(jsnominal-env? %)]} 49 | {:jsnominal nom 50 | :fields {} 51 | :methods {} 52 | :ctors nil 53 | :ancestors #{}}) 54 | 55 | (t/ann ^:no-check get-jsnominal [t/Any -> (t/Nilable r/Type)]) 56 | (defn get-jsnominal 57 | "Returns the nomainal JS type with class symbol csym. 58 | Returns nil if not found." 59 | [csym] 60 | {:post [((some-fn nil? r/Type?) %)]} 61 | (-> (get (impl/jsnominal-env) csym) :jsnominal)) 62 | 63 | (t/ann contains-jsnominal? [t/Any -> boolean]) 64 | (defn contains-jsnominal? 65 | [csym] 66 | (boolean (get-jsnominal csym))) 67 | 68 | ;(t/ann add-jsnominal [t/Sym r/Type -> nil]) 69 | ;(defn add-jsnominal [csym type] 70 | ; (assert (r/Type? type) 71 | ; (str "JS nominal" csym " not a type: " type)) 72 | ; ; remove old fields etc. 73 | ; (swap! JSNOMINAL-ENV assoc-in [csym] (init-jsnominal-entry type)) 74 | ; nil) 75 | ; 76 | ;(t/ann add-method [t/Sym JSNominal (t/U Scope r/Type) -> nil]) 77 | ;(defn add-method 78 | ; "Add a new method to the JS nominal type csym. Assumes 79 | ; the method type is properly Scope'd" 80 | ; [csym method-sym type] 81 | ; (swap! JSNOMINAL-ENV assoc-in [csym :methods method-sym] type) 82 | ; nil) 83 | ; 84 | ;(t/ann add-field [t/Sym JSNominal (t/U Scope r/Type) -> nil]) 85 | ;(defn add-field 86 | ; "Add a new field to the JS nominal type csym. Assumes 87 | ; the field type is properly Scope'd" 88 | ; [csym field-sym type] 89 | ; (swap! JSNOMINAL-ENV update-in [csym :fields field-sym] (constantly type))) 90 | 91 | (declare get-method get-field get-inherited-property) 92 | 93 | (t/ann ^:no-check get-method [t/Sym (t/U nil (t/Seqable r/Type)) t/Sym -> (t/U nil r/Type)]) 94 | (defn get-method 95 | "Returns the instantiated method type named method-sym on nominal csym." 96 | [csym args method-sym] 97 | {:pre [(symbol? csym) 98 | (every? r/Type? args) 99 | (symbol? method-sym)] 100 | :post [((some-fn nil? r/Type?) %)]} 101 | (println (str "Searching " csym "#" method-sym)) 102 | (if-let [tscope (get-in (impl/jsnominal-env) [csym :methods method-sym])] 103 | (c/inst-and-subst tscope args) 104 | (get-inherited-property get-method csym args method-sym))) 105 | 106 | (t/ann ^:no-check get-inherited-property [[t/Sym (t/Option (t/Seqable r/Type)) t/Sym -> (t/Option r/Type)] 107 | t/Sym (t/Option (t/Seqable r/Type)) t/Sym -> (t/Option r/Type)]) 108 | (defn get-inherited-property 109 | "search for the property in the interfaces ancestors 110 | method: (get-inherited-property get-method csym args method-sym) 111 | field: (get-inherited-property get-field csym args field-sym)" 112 | [f csym args method-sym] 113 | ;(println (->> (get-in (impl/jsnominal-env) [csym :ancestors]) (map :id))) 114 | (->> (get-in (impl/jsnominal-env) [csym :ancestors]) 115 | (map #(f (:id %) args method-sym)) 116 | (filter identity) 117 | first)) 118 | 119 | (t/ann ^:no-check get-field [t/Sym (t/U nil (t/Seqable r/Type)) t/Sym -> (t/U nil r/Type)]) 120 | (defn get-field 121 | "Returns the instantiated field type named field-sym on nominal csym." 122 | [csym args field-sym] 123 | {:pre [(symbol? csym) 124 | (every? r/Type? args) 125 | (symbol? field-sym)] 126 | :post [((some-fn nil? r/Type?) %)]} 127 | (if-let [tscope (get-in (impl/jsnominal-env) [csym :fields field-sym])] 128 | (c/inst-and-subst tscope args) 129 | (get-inherited-property get-method csym args field-sym))) 130 | 131 | (t/ann ^:no-check get-ctor [t/Sym (t/U nil (t/Seqable r/Type)) -> (t/U nil r/Type)]) 132 | (defn get-ctor 133 | "Returns the instantiated constructor type on nominal csym." 134 | [csym args] 135 | {:pre [(symbol? csym) 136 | (every? r/Type? args)] 137 | :post [((some-fn nil? r/Type?) %)]} 138 | (when-let [tscope (get-in (impl/jsnominal-env) [csym :ctor])] 139 | (c/inst-and-subst tscope args))) 140 | 141 | (t/ann ^:no-check reset-jsnominal! [JSNominalEnv -> nil]) 142 | (defn reset-jsnominal! [m] 143 | {:pre [(jsnominal-env? m)] 144 | :post [(nil? %)]} 145 | (impl/reset-jsnominal-env! m) 146 | nil) 147 | -------------------------------------------------------------------------------- /src/test/cljs/cljs/core/typed/test/ympbyc/test_base_env.cljs: -------------------------------------------------------------------------------- 1 | (ns cljs.core.typed.test.ympbyc.test-base-env 2 | (:require-macros [cljs.core.typed :refer [ann ann-jsnominal] :as ct]) 3 | (:require [cljs.core.typed :refer [All U IFn Option I Any Seqable Vec HSequential NonEmptyASeq NonEmptySeqable Atom1 Set Coll Map] :as t] 4 | [cljs.core :refer [IVector ISeq ASeq List]])) 5 | 6 | ;;seq 7 | (ann seq-vec (NonEmptySeqable number)) 8 | (def seq-vec (seq [1 2 3])) 9 | 10 | (ann seq-empty (Option (NonEmptyASeq nil))) 11 | (def seq-empty (seq [])) 12 | 13 | ;;fst 14 | 15 | (ann vec-fst number) 16 | (def vec-fst (first [8])) 17 | 18 | (ann seq-fst number) 19 | (def seq-fst (first (seq [1 2 3]))) 20 | 21 | (ann fst-nil nil) 22 | (def fst-nil (first nil)) 23 | 24 | 25 | ;;rest 26 | 27 | (ann vec-rest (ASeq number)) 28 | (def vec-rest (rest [1 2 3])) 29 | 30 | (ann seq-rest (ASeq number)) 31 | (def seq-rest (rest (seq [1 2 3]))) 32 | 33 | (ann rest-empty (ASeq nil)) 34 | (def rest-empty (rest [])) 35 | 36 | 37 | ;;last 38 | 39 | (ann vec-last number) 40 | (def vec-last (last [1 2 3])) 41 | 42 | (ann seq-last number) 43 | (def seq-last (last (seq [1 2 3]))) 44 | 45 | (ann last-nil (Option number)) 46 | (def last-nil (last [])) 47 | 48 | 49 | ;;butlast 50 | 51 | (ann vec-butlast (ASeq number)) 52 | (def vec-butlast (butlast [1 2 3])) 53 | 54 | (ann seq-butlast (ASeq number)) 55 | (def vec-butlast (butlast (seq [1 2 3]))) 56 | 57 | (ann butlast-empty (ASeq nil)) 58 | (def butlast-empty (butlast [])) 59 | 60 | 61 | ;;test if NonEmptySeqable is Seqable 62 | (ann nonemp (All [x] [(NonEmptySeqable x) -> number])) 63 | (defn foo [xs] 1) 64 | 65 | (foo (seq [1 2 3])) 66 | 67 | 68 | 69 | (ann second-vec number) 70 | (def second-vec (second [1 2 3])) 71 | 72 | (ann second-empty nil) 73 | (def second-empty (second [])) 74 | 75 | (ann second-nil nil) 76 | (def second-nil (second nil)) 77 | 78 | (ann second-seq (Option number)) 79 | (def second-seq (second (seq [1 2 3]))) 80 | 81 | 82 | 83 | (ann clj-to-jsjs Any) 84 | (def clj-to-js (clj->js {:a 1})) 85 | 86 | ;BUG: Use of js-obj triggers "js-op missing" in check_cljs 87 | ;(ann js-to-clj Any) 88 | ;(def js-to-clj (js->clj (js-obj "a" 1 "b" 2))) 89 | 90 | (ann cljs.core/nil? [Any -> boolean]) 91 | 92 | (ann nil-pred-t boolean) 93 | (def nil-pred-t (nil? nil)) 94 | 95 | (ann nil-pred-f boolean) 96 | (def nil-pred-f (nil? "nil")) 97 | 98 | 99 | 100 | (ann ifn?-test-t boolean) 101 | (def ifn?-test-t (ifn? (fn [x] x))) 102 | 103 | (ann ifn?-test-f boolean) 104 | (def ifn-test-f (ifn? "foo")) 105 | 106 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 107 | ;; test vars in base-env-common 108 | 109 | 110 | (ann id-test number) 111 | (def id-test (identity 8)) 112 | 113 | (ann take-vec (ASeq int)) 114 | (def take-vec (take 2 [1 2 3 4])) 115 | 116 | 117 | (ann drop-vec (ASeq int)) 118 | (def drop-vec (drop 2 [1 2 3 4])) 119 | 120 | (ann get-set (Option int)) 121 | (def get-set (get #{1 2 3} 2)) 122 | 123 | (ann sym-test Symbol) 124 | (def sym-test 'foo) 125 | 126 | 127 | ;BUG: subtyping fails 128 | ;(ann atom-test (Atom1 number)) 129 | ;(def atom-test (atom 3)) 130 | 131 | (ann set-test (Set number)) 132 | (def set-test #{5}) 133 | 134 | (ann number?-t boolean) 135 | (def number?-t (number? 8)) 136 | 137 | (ann number?-f boolean) 138 | (def number?-f (number? [1 2])) 139 | 140 | (ann string?-t boolean) 141 | (def string?-t (string? "hello")) 142 | 143 | (ann seq?-t boolean) 144 | (def seq-t (seq? (seq [1 2 3]))) 145 | 146 | (ann seq?-f boolean) 147 | (def seq-f (seq? [1 2 3])) 148 | 149 | ;BUG: Use of `list` invokes an error 150 | ;(ann cljs.core/-conj [Any Any -> (Coll Any)]) 151 | ;(ann cljs.core.List.EMPTY (List Any)) ;;this fails somehow 152 | ;(ann list?-test boolean) 153 | ;(def list?-test (list? (list 1 2 3))) 154 | 155 | (ann apply-test number) 156 | (def apply-test (apply + [2 3])) 157 | 158 | (ann apply-test-str string) 159 | (def apply-test-str (apply str ["hello, " "world"])) 160 | 161 | 162 | (ann conj-1 (IVector string)) 163 | (def conj-1 (conj ["foo"] "bar")) 164 | 165 | (ann conj-2 (ASeq number)) 166 | (def conj-2 (conj (seq [3 4 5]) 1 2)) 167 | 168 | (ann conj-3 (ASeq (Vec number))) 169 | (def conj-3 (conj (seq [[1] [2 3]]) [8] [9])) 170 | 171 | ;BUG: this throws assert failed 172 | ;(ann conj-4 (t/Map Keyword number)) 173 | ;(def conj-4 (conj {:foo 5} [:bar 8])) 174 | ;(ann conj-5 (t/Map Keyword Any)) 175 | ;(def conj-5 (conj {:foo "bar"} {:baz 123})) 176 | 177 | 178 | (ann get-1 (Option number)) 179 | (def get-1 (get #{1 2 3} 3)) 180 | 181 | (ann get-2 boolean) 182 | (def get-2 (get {:a true :b false} :c false)) 183 | 184 | 185 | (ann assoc-vec (Vec string)) 186 | (def assoc-vec (assoc ["foo" "bar"] 2 "baz")) 187 | 188 | (ann assoc-map (t/Map (Vec number) string)) 189 | (def assoc-map (assoc {[2 3] "foo"} [4 5] "bar")) 190 | 191 | (ann dissoc-1 (t/Map Keyword number)) 192 | (def dissoc-1 (dissoc {:foo 8 :bar 9} :foo)) 193 | 194 | (ann fn?-1 boolean) 195 | (def fn?-1 (fn? (fn [x y] y))) 196 | 197 | (ann fn?-2 boolean) 198 | (def fn?-2 (fn? cljs.core/map)) 199 | 200 | (ann peek-1 (t/Map Keyword string)) 201 | (def peek-1 (peek [{:foo "bar" :baz "zot"} {:foo "bar"}])) 202 | 203 | 204 | (ann pop-1 (Vec number)) 205 | (def pop-1 (pop [1 2 3])) 206 | 207 | (ann disj-1 (Set number)) 208 | (def disj-1 (disj #{1 2 3 4} 3 4)) 209 | 210 | 211 | ;;jsnominals 212 | (ann-jsnominal js/Object 213 | [[] 214 | :fields {} 215 | :methods {keys (Array string) 216 | toString [-> string]}]) 217 | 218 | (ann-jsnominal js/Document 219 | [[] 220 | :fields {} 221 | :methods 222 | {getElementById [string -> (cljs.core.typed/Option js/HTMLElement)] 223 | querySelector [string -> (cljs.core.typed/Option js/HTMLElement)]} 224 | :ancestors #{js/Object}]) 225 | 226 | ;(ann js/document js/Document) 227 | 228 | (ann get-el [string -> (Option js/HTMLElement)]) 229 | (defn get-el [sel] (.querySelector js/document sel)) 230 | 231 | (ann inner-html [js/HTMLElement -> string]) 232 | (defn inner-html [el] (.-innerHTML el)) 233 | 234 | (ann inner-html-result string) 235 | (def inner-html-result 236 | (let [el (get-el "body")] 237 | (if el (inner-html el) ""))) 238 | 239 | ;;inheritance 240 | 241 | (ann document-is-object string) 242 | (def document-is-object (.toString js/document)) 243 | -------------------------------------------------------------------------------- /src/test/clojure/clojure/core/typed/test/cljs_core.clj: -------------------------------------------------------------------------------- 1 | (ns clojure.core.typed.test.cljs-core 2 | (:require [cljs.core.typed :as t] 3 | [cljs.core :as core] 4 | [clojure.core.typed.test.cljs-utils :refer [is-tc-e tc-e]] 5 | [clojure.test :refer :all])) 6 | 7 | ;;; defining tests this way should help estimate the coverage 8 | ;;; cljs.core vars not included in (keys @core-tests) are totally untested 9 | 10 | (def core-tests (atom {})) 11 | 12 | (defmacro add-test [f & pairs] 13 | (assert (even? (count pairs))) 14 | `(swap! core-tests conj 15 | ['~(symbol "cljs.core" (name f)) '~pairs])) 16 | 17 | ;;tests for single parameter functions 18 | (defmacro add-test1 [f & pairs] 19 | (assert (even? (count pairs))) 20 | `(swap! core-tests conj 21 | [(with-meta '~(symbol "cljs.core" (name f)) 22 | {:single-arg true}) 23 | '~pairs])) 24 | 25 | (defmacro run-core-tests [] 26 | (cons 'do 27 | (for [[f cases] @core-tests 28 | [args expected] (partition 2 cases)] 29 | (if (:single-arg (meta f)) 30 | `(is-tc-e (~f ~args) ~expected) 31 | `(is-tc-e (~f ~@args) ~expected))))) 32 | 33 | 34 | ;;; core vars test 35 | 36 | (add-test1 seq 37 | [1 2 3] (t/NonEmptySeqable t/JSNumber) 38 | [] (t/Option (t/NonEmptyASeq t/Any))) 39 | 40 | (add-test1 first 41 | [8] t/JSNumber 42 | (seq [1 2 3]) t/JSNumber 43 | nil nil) 44 | 45 | (add-test1 rest 46 | [1 2 3] (core/ASeq t/JSNumber) 47 | (seq [1 2 3]) (core/ASeq t/JSNumber) 48 | [] (core/ASeq t/Any)) 49 | 50 | (add-test1 last 51 | [1 2 3] t/JSNumber 52 | (seq [1 2 3]) t/JSNumber 53 | [] (t/Option t/Any)) 54 | 55 | (add-test1 butlast 56 | [1 2 3] (core/ASeq t/JSNumber) 57 | (seq [1 2 3]) (core/ASeq t/JSNumber) 58 | [] (core/ASeq t/Any)) 59 | 60 | (add-test1 second 61 | [1 2 3] t/JSNumber 62 | [] nil 63 | nil nil 64 | (seq [1 2 3]) (t/Option t/JSNumber)) 65 | 66 | 67 | (add-test1 clj->js 68 | {:a 1} t/Any) 69 | 70 | (add-test1 nil? 71 | nil t/JSBoolean 72 | "nil" t/JSBoolean) 73 | 74 | (add-test1 ifn? 75 | (fn [x] x) t/JSBoolean 76 | "foo" t/JSBoolean) 77 | 78 | (add-test1 identity 79 | 8 t/JSNumber 80 | "hello" t/JSString 81 | [0] (t/Vec t/JSNumber)) 82 | 83 | (add-test take 84 | [2 [1 2 3 4]] (core/ASeq t/CLJSInteger)) 85 | 86 | (add-test drop 87 | [2 [1 2 3 4]] (core/ASeq t/CLJSInteger)) 88 | 89 | (add-test1 number? 90 | 8 t/JSBoolean 91 | [1 2] t/JSBoolean) 92 | 93 | (add-test1 string? 94 | "hello" t/JSBoolean) 95 | 96 | (add-test1 seq? 97 | (seq [1 2 3]) t/JSBoolean 98 | [1 2 3] t/JSBoolean) 99 | 100 | (add-test apply 101 | [+ [2 3]] t/JSNumber 102 | [str ["hello" "world"]] t/JSString) 103 | 104 | (add-test conj 105 | [["foo"] "bar"] (core/IVector t/JSString) 106 | [(seq [3 4 5]) 1 2] (core/ASeq t/JSNumber) 107 | [(seq [[1] [2 3]]) [8] [9]] (core/ASeq (t/Vec t/JSNumber)) 108 | ;[{:foo 5} [:bar 8]] (t/Map core/Keyword t/JSNumber) 109 | ;[{:foo "bar"} {:baz 1 2 3}] (t/Map core/Keyword t/Any) 110 | ) 111 | 112 | (add-test get 113 | [#{1 2 3} 3] (t/Option t/JSNumber) 114 | [{:a true :b false} :c false] t/JSBoolean) 115 | 116 | (add-test assoc 117 | [["foo" "bar"] 2 "baz"] (t/Vec t/JSString) 118 | [{[2 3] "foo"} [4 5] "bar"] (t/Map (t/Vec t/JSNumber) t/JSString)) 119 | 120 | (add-test dissoc 121 | [{:foo 8 :bar 9} :foo] (t/Map core/Keyword t/JSNumber)) 122 | 123 | (add-test1 fn? 124 | (fn [x y] y) t/JSBoolean 125 | cljs.core/map t/JSBoolean) 126 | 127 | (add-test1 peek 128 | [{:foo "bar" :baz "zot"} {:foo "bar"}] (t/Map core/Keyword t/JSString)) 129 | 130 | (add-test1 pop 131 | [1 2 3] (t/Vec t/JSNumber)) 132 | 133 | (add-test disj 134 | [#{1 2 3 4} 3 4] (t/Set t/JSNumber)) 135 | 136 | (add-test1 empty? 137 | [] t/JSBoolean 138 | #{} t/JSBoolean 139 | [1] t/JSBoolean 140 | {:a 1} t/JSBoolean) 141 | 142 | (add-test1 coll? 143 | {:a 1} t/JSBoolean 144 | #{1 2} t/JSBoolean 145 | [2 3] t/JSBoolean 146 | "foo" t/JSBoolean 147 | 2 t/JSBoolean) 148 | 149 | (add-test1 map? 150 | {:a 1} t/JSBoolean 151 | {} t/JSBoolean 152 | [0 1] t/JSBoolean) 153 | 154 | (add-test1 vector? 155 | [] t/JSBoolean 156 | [1] t/JSBoolean 157 | {:a 1} t/JSBoolean 158 | "foo" t/JSBoolean) 159 | 160 | (add-test1 false? 161 | [] t/JSBoolean 162 | false t/JSBoolean 163 | true t/JSBoolean 164 | 1 t/JSBoolean) 165 | 166 | (add-test1 true? 167 | [] t/JSBoolean 168 | false t/JSBoolean 169 | true t/JSBoolean 170 | 1 t/JSBoolean) 171 | 172 | (add-test1 seq? 173 | [] t/JSBoolean 174 | #{2 3} t/JSBoolean 175 | (seq [1 2]) t/JSBoolean 176 | (seq #{2 3}) t/JSBoolean) 177 | 178 | (add-test1 boolean 179 | [] t/JSBoolean 180 | "true" t/JSBoolean 181 | :false t/JSBoolean) 182 | 183 | (add-test1 integer? 184 | 2 t/JSBoolean 185 | 1.3 t/JSBoolean 186 | "8" t/JSBoolean) 187 | 188 | (add-test contains? 189 | [[1 2 3] 2] t/JSBoolean 190 | [#{1 2} 8] t/JSBoolean 191 | [(seq []) "a"] t/JSBoolean) 192 | 193 | (add-test find 194 | [{:a 1 :b 2} :b] (t/Option (t/HVec [Keyword t/JSNumber])) 195 | [[:a :b] 0] (t/Option (t/HVec [t/CLJSInteger Keyword]))) 196 | 197 | (add-test distinct? 198 | [:a :b] t/JSBoolean 199 | [[1] [1] [1]] t/JSBoolean 200 | [:a "foo" []] t/JSBoolean) 201 | 202 | (add-test compare 203 | [[1 2] [2 3]] t/JSNumber 204 | ["foo" "bar"] t/JSNumber 205 | [2 1] t/JSNumber) 206 | 207 | (add-test sort 208 | [[2 4 2 1 5 3]] (t/Option (core/ASeq t/CLJSInteger)) 209 | [[:a :c :b]] (t/Option (core/ASeq Keyword)) 210 | [(t/fn [x :- t/CLJSInteger y :- t/CLJSInteger] :- t/CLJSInteger (- x y)) 211 | [6 1 7 3 2]] (t/Option (core/ASeq t/CLJSInteger))) 212 | 213 | (add-test1 shuffle 214 | [1 2 3 4] (t/Vec t/CLJSInteger) 215 | #{4 8 2} (t/Vec t/CLJSInteger)) 216 | 217 | ;FIXME reenable after porting to tools.analyzer.js. Some issue with hygienic renaming 218 | #_(add-test reduce 219 | [(t/fn [x :- t/CLJSInteger y :- t/JSString] :- t/CLJSInteger 0) 220 | ["foo" "bar" "baz"]] t/CLJSInteger 221 | [(t/fn [x :- t/CLJSInteger y :- t/CLJSInteger] :- (core/Reduced t/CLJSInteger) (reduced 0)) 222 | #{8 36 2}] t/CLJSInteger 223 | [(t/fn [x :- t/CLJSInteger y :- t/CLJSInteger] :- (core/Reduced t/CLJSInteger) (reduced 0)) 224 | #{8 36 2} 0] t/CLJSInteger) 225 | 226 | (add-test reduce-kv 227 | [(t/fn [a :- t/CLJSInteger k :- Keyword v :- t/CLJSInteger] :- t/CLJSInteger (+ a v)) 228 | 0 {:a 1 :b 2 :c 3}] t/CLJSInteger) 229 | 230 | (add-test < 231 | [1 5] t/JSBoolean 232 | [1.8 0.8] t/JSBoolean 233 | [1/2 3/2] t/JSBoolean) 234 | 235 | (add-test1 int 236 | 1 t/CLJSInteger) 237 | 238 | (add-test mod 239 | [8 2] t/AnyInteger 240 | [8.1 2.1] t/JSNumber) 241 | 242 | (add-test rand 243 | [] t/JSNumber 244 | [8] t/JSNumber) 245 | 246 | (add-test1 rand-int 247 | 1 t/CLJSInteger 248 | 1000 t/CLJSInteger) 249 | 250 | (add-test nthnext 251 | [nil 8] nil 252 | [#{2 3 1} 1] (t/Option (t/NonEmptyASeq t/CLJSInteger)) 253 | [[1 2 3] 9] (t/Option (t/NonEmptyASeq t/CLJSInteger))) 254 | 255 | (comment add-test1 rseq 256 | [1 2 3] (t/Option (t/NonEmptyASeq t/CLJSInteger))) 257 | 258 | (add-test1 reverse 259 | [1 2 3] (core/ASeq t/CLJSInteger) 260 | {:a 1 :b 2} (core/ASeq t/Any) 261 | #{1 2 3} (core/ASeq t/CLJSInteger)) 262 | 263 | (comment add-test list 264 | [1 2 3] (t/PersistentList t/CLJSInteger) 265 | [:a 2] (t/PersistentList t/Any)) 266 | 267 | (add-test cons 268 | [1 [2 3]] (core/ASeq t/CLJSInteger) 269 | [[1] [[2]]] (core/ASeq (t/Vec t/CLJSInteger))) 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | (deftest cljs-core-fns-refined-test 278 | (run-core-tests)) 279 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/core/typed/base_env_helper_cljs.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Ambrose Bonnaire-Sergeant, Rich Hickey & contributors. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.core.typed.base-env-helper-cljs 10 | (:refer-clojure :exclude [type]) 11 | (:require [clojure.core.typed.type-rep :as r] 12 | [clojure.core.typed.parse-unparse :as prs] 13 | [clojure.core.typed.utils :as u] 14 | [clojure.core.typed.free-ops :as free-ops] 15 | [clojure.core.typed.type-ctors :as c] 16 | [clojure.core.typed.declared-kind-env :as decl-env] 17 | [clojure.core.typed.rclass-env :as rcls] 18 | [clojure.core.typed.current-impl :as impl] 19 | [clojure.core.typed.name-env :as nme-env] 20 | [clojure.core.typed.jsnominal-env :as jsnom] 21 | [clojure.core.typed.datatype-env :as dtenv] 22 | ;[clojure.core.typed.util-cljs :as ucljs] 23 | ;[cljs.analyzer :as ana] 24 | ;[cljs.compiler :as comp] 25 | [clojure.pprint :as pprint])) 26 | 27 | (defmacro alias-mappings [& args] 28 | `(impl/with-cljs-impl 29 | (let [ts# (partition 2 '~args)] 30 | (into {} 31 | (doall 32 | (for [[s# t#] ts#] 33 | (let [;desc# (-> s# meta :doc) 34 | ;doc# (str (when desc# 35 | ; (str desc# "\n\n")) 36 | ; (with-out-str (pprint/pprint t#))) 37 | ;_# (assert (and (symbol? s#) 38 | ; (namespace s#)) 39 | ; "Need fully qualified symbol") 40 | ;v# (intern (find-ns (symbol (namespace s#))) (symbol (name s#))) 41 | ;_# (alter-meta! v# merge {:doc doc#}) 42 | ] 43 | [(with-meta s# nil) (prs/parse-type t#)]))))))) 44 | 45 | (defmacro var-mappings [& args] 46 | `(impl/with-cljs-impl 47 | (let [ts# (partition 2 '~args)] 48 | (into {} 49 | (doall 50 | (for [[s# t#] ts#] 51 | (do 52 | (assert (and (symbol? s#) 53 | (namespace s#)) 54 | "Need fully qualified symbol") 55 | [s# (prs/parse-type t#)]))))))) 56 | 57 | (defmacro js-var-mappings [& args] 58 | `(impl/with-cljs-impl 59 | (let [ts# (partition 2 '~args)] 60 | (into {} 61 | (doall 62 | (for [[s# t#] ts#] 63 | [s# (prs/parse-type t#)])))))) 64 | 65 | (defn declared-kind-for-protocol [binder] 66 | (let [fs (map first binder) 67 | _ (assert (every? symbol? fs) fs) 68 | vs (map (fn [[v & {:keys [variance]}]] variance) binder)] 69 | (c/TypeFn* fs vs (repeat (count vs) r/no-bounds) r/-any))) 70 | 71 | (defmacro protocol-mappings [& args] 72 | `(impl/with-cljs-impl 73 | (let [ts# (partition 2 '~args)] 74 | (into {} 75 | (doall 76 | (for [[n# [fields# & {:as opts#}]] ts#] 77 | (let [vs# (seq 78 | (for [[_# & {variance# :variance}] fields#] 79 | variance#)) 80 | decl-kind# (declared-kind-for-protocol fields#) 81 | ;FIXME this is harder than it has to be 82 | ; add a Name so the methods can be parsed 83 | _# (nme-env/declare-protocol* n#) 84 | _# (when (r/TypeFn? decl-kind#) 85 | (decl-env/add-declared-kind n# decl-kind#)) 86 | names# (when (seq fields#) 87 | (map first fields#)) 88 | ; FIXME specify bounds 89 | bnds# (when (seq fields#) 90 | (repeat (count fields#) r/no-bounds)) 91 | frees# (map r/make-F names#) 92 | methods# (free-ops/with-bounded-frees (zipmap frees# bnds#) 93 | (into {} 94 | (for [[mname# mtype#] (:methods opts#)] 95 | [mname# (prs/parse-type mtype#)]))) 96 | the-var# n# 97 | on-class# (c/Protocol-var->on-class the-var#)] 98 | (decl-env/remove-declared-kind n#) 99 | [n# (c/Protocol* names# vs# frees# the-var# 100 | on-class# methods# bnds#)]))))))) 101 | 102 | (defn jsnominal-entry [[n [binder & {:as opts}]]] 103 | (let [names (when (seq binder) 104 | (map first binder)) 105 | {vs :variances 106 | names :names 107 | bnds :bnds} 108 | (when (seq binder) 109 | ; don't bound frees because mutually dependent bounds are problematic 110 | ; FIXME ... Or is this just laziness? 111 | (let [b (free-ops/with-free-symbols names 112 | (mapv prs/parse-tfn-binder binder))] 113 | {:variances (map :variance b) 114 | :names (map :nme b) 115 | :bnds (map :bound b)})) 116 | frees (map r/make-F names) 117 | methods (free-ops/with-bounded-frees (zipmap frees bnds) 118 | (into {} 119 | (for [[mname mtype] (:methods opts)] 120 | [mname (c/abstract-many names (prs/parse-type mtype))]))) 121 | fields (free-ops/with-bounded-frees (zipmap frees bnds) 122 | (into {} 123 | (for [[mname mtype] (:fields opts)] 124 | [mname (c/abstract-many names (prs/parse-type mtype))]))) 125 | ctor (when-let [ctor (:ctor opts)] 126 | (free-ops/with-bounded-frees (zipmap frees bnds) 127 | (c/abstract-many names (prs/parse-type ctor)))) 128 | ancestors (free-ops/with-bounded-frees (zipmap frees bnds) 129 | (into #{} 130 | (for [mtype (:ancestors opts)] 131 | (c/abstract-many names (prs/parse-type mtype)))))] 132 | (decl-env/remove-declared-kind n) 133 | [n {:jsnominal (c/JSNominal* names vs frees n bnds) 134 | :fields fields 135 | :methods methods 136 | :ctor ctor 137 | :ancestors ancestors}])) 138 | 139 | 140 | (defmacro jsnominal-mappings [& args] 141 | `(impl/with-cljs-impl 142 | (let [ts# (partition 2 '~args)] 143 | (into {} 144 | (doall 145 | (for [t# ts#] 146 | (jsnominal-entry t#))))))) 147 | 148 | (defmacro datatype-mappings [& args] 149 | `(impl/with-cljs-impl 150 | (let [ts# (partition 2 '~args)] 151 | (into {} 152 | (doall 153 | (for [[n# [binder# & {record?# :record? :as opts#}]] ts#] 154 | (let [names# (when (seq binder#) 155 | (map first binder#)) 156 | {vs# :variances 157 | names# :names 158 | bnds# :bnds} 159 | (when (seq binder#) 160 | ; don't bound frees because mutually dependent bounds are problematic 161 | ; FIXME ... Or is this just laziness? 162 | (let [b# (free-ops/with-free-symbols names# 163 | (mapv prs/parse-tfn-binder binder#))] 164 | {:variances (seq (map :variance b#)) 165 | :names (seq (map :nme b#)) 166 | :bnds (seq (map :bound b#))})) 167 | frees# (seq (map r/make-F names#)) 168 | fields# (free-ops/with-bounded-frees (zipmap frees# bnds#) 169 | (into {} 170 | (for [[mname# mtype#] (:fields opts#)] 171 | [mname# (prs/parse-type mtype#)])))] 172 | (decl-env/remove-declared-kind n#) 173 | [n# (c/DataType* names# vs# frees# n# bnds# fields# (boolean record?#))]))))))) 174 | 175 | (defmacro jsenv-mappings [& args] 176 | `(impl/with-cljs-impl 177 | (let [ts# (partition 2 '~args)] 178 | (into {} 179 | (doall 180 | (for [[s# t#] ts#] 181 | [s# (prs/parse-type t#)])))))) 182 | -------------------------------------------------------------------------------- /src/test/clojure/clojure/core/typed/test/cljs.clj: -------------------------------------------------------------------------------- 1 | (ns clojure.core.typed.test.cljs 2 | (:require [clojure.core.typed.test.cljs-utils :refer :all] 3 | [clojure.test :refer :all] 4 | [clojure.core.typed.type-rep :as r] 5 | [clojure.core.typed.subtype :as sub] 6 | [cljs.core.typed :as t] 7 | [clojure.core.typed.util-cljs :as ucljs] 8 | [clojure.core.typed.current-impl :as impl] 9 | [clojure.core.typed.type-ctors :as c] 10 | [clojure.core.typed.parse-unparse :as prs] 11 | 12 | [clojure.core.typed.base-env-common :refer [delay-and-cache-env] 13 | :as common] 14 | [clojure.core.typed.var-env :as var-env] 15 | [clojure.core.typed.test.cljs-core :as core-test] 16 | [clojure.core.typed.analyzer-api-intercept :as fake-ana-api])) 17 | 18 | (deftest parse-prims-cljs-test 19 | (is-cljs (= (prs/parse-cljs 'cljs.core.typed/JSNumber) 20 | (r/JSNumber-maker))) 21 | (is-cljs (= (prs/parse-cljs 'cljs.core.typed/CLJSInteger) 22 | (r/CLJSInteger-maker))) 23 | (is-cljs (= (prs/parse-cljs 'cljs.core.typed/JSBoolean) 24 | (r/JSBoolean-maker))) 25 | (is-cljs (= (prs/parse-cljs 'cljs.core.typed/JSObject) 26 | (r/JSObject-maker))) 27 | (is-cljs (= (prs/parse-cljs 'cljs.core.typed/JSString) 28 | (r/JSString-maker)))) 29 | 30 | (deftest parse-array-cljs-test 31 | (is-cljs (= (prs/parse-cljs '(Array cljs.core.typed/JSNumber)) 32 | (r/ArrayCLJS-maker (prs/parse-cljs 'cljs.core.typed/JSNumber) 33 | (prs/parse-cljs 'cljs.core.typed/JSNumber))))) 34 | 35 | (deftest unparse-prims-cljs-test 36 | (is-cljs (= 'cljs.core.typed/JSNumber 37 | (prs/unparse-type (prs/parse-cljs 'cljs.core.typed/JSNumber)))) 38 | (is-cljs (= 'cljs.core.typed/JSBoolean 39 | (prs/unparse-type (prs/parse-cljs 'cljs.core.typed/JSBoolean)))) 40 | (is-cljs (= 'cljs.core.typed/CLJSInteger 41 | (prs/unparse-type (prs/parse-cljs 'cljs.core.typed/CLJSInteger)))) 42 | (is-cljs (= '(Array cljs.core.typed/JSNumber) 43 | (prs/unparse-type (prs/parse-cljs '(Array cljs.core.typed/JSNumber))))) 44 | (is-cljs (= '(Array2 cljs.core.typed/JSNumber cljs.core.typed/JSBoolean) 45 | (prs/unparse-type (prs/parse-cljs '(Array2 cljs.core.typed/JSNumber cljs.core.typed/JSBoolean)))))) 46 | 47 | (deftest subtype-prims-cljs-test 48 | (is-cljs (sub/subtype? (r/-val 1) (prs/parse-cljs 'cljs.core.typed/JSNumber)))) 49 | 50 | ;FIXME 51 | #_ 52 | (deftest throw-test 53 | (is-tc-e (throw (js/JSError. "foo")) 54 | t/Nothing)) 55 | 56 | (deftest ann-test 57 | (is-tc-e (do (t/ann foo t/JSNumber) 58 | (def foo 1))) 59 | (is-tc-err (do (t/ann foo t/JSNumber) 60 | (def foo nil)))) 61 | 62 | (deftest check-ns-test 63 | (is-cljs (t/check-ns* 'cljs.core.typed.test.ann))) 64 | 65 | (deftest parse-protocol-test 66 | (is-cljs (prs/parse-cljs '(cljs.core/IMap cljs.core.typed/JSNumber cljs.core.typed/JSNumber)))) 67 | 68 | (deftest Protocol-of-test 69 | (is-cljs (c/Protocol-of 'cljs.core/IMap [(r/JSNumber-maker) 70 | (r/JSNumber-maker)]))) 71 | 72 | (deftest heterogeneous-ds-test 73 | (is-tc-e [1 2] 74 | '[t/JSNumber t/JSNumber]) 75 | (is-tc-e [1 2] 76 | (IVector t/JSNumber)) 77 | (is-tc-e {:a 1} 78 | '{:a t/JSNumber}) 79 | (is-tc-e {1 1} 80 | (IMap t/JSNumber t/JSNumber)) 81 | (is-tc-e #{1} 82 | (ISet t/JSNumber)) 83 | (is-tc-e (let [a 1] #{1 a}) 84 | (ISet t/JSNumber))) 85 | 86 | (deftest js*-test 87 | (is-tc-e (+ 1 1))) 88 | 89 | (deftest fn-test 90 | (is-tc-e (fn a [b] a)) 91 | (is-tc-e (fn [a] a) 92 | (t/All [x] [x -> x]))) 93 | 94 | (deftest inst-test 95 | (is-tc-e (let [f (-> (fn [a] a) 96 | (t/ann-form (t/All [x] [x -> x])))] 97 | ((t/inst f t/JSNumber) 1)) 98 | t/JSNumber)) 99 | 100 | (deftest letfn-test 101 | (is-tc-e (t/letfn> [a :- (t/All [x] [x -> x]) 102 | (a [b] b)] 103 | (a 1)))) 104 | 105 | ;;commenting-out this test because just :require -ing cljs.core.async fails with internal error 106 | #_(deftest async-test 107 | (is-cljs (t/check-ns* 'cljs.core.typed.async))) 108 | 109 | (deftest inline-annotation-test 110 | ; code from David Nolen's blog 111 | ;FIXME 112 | #_(is-tc-e 113 | (defn ^{:ann '[(t/U nil (ISeqable t/Any)) t/Any -> cljs.core.typed/CLJSInteger]} 114 | index-of [xs x] 115 | (let [len (count xs)] 116 | (t/loop> 117 | [i :- cljs.core.typed/CLJSInteger, 0] 118 | (if (< i len) 119 | (if (= (nth xs i) x) 120 | i 121 | (recur (inc i))) 122 | -1)))))) 123 | 124 | #_ 125 | (deftest simple-polymorphic-test 126 | (is-cljs (t/check-ns* 'cljs.core.typed.test.identity))) 127 | 128 | (deftest value-supertype-test 129 | (is-tc-e 'a Symbol) 130 | (is-tc-e :a Keyword) 131 | (is-tc-e 1 t/CLJSInteger) 132 | (is-tc-e 1.1 t/JSNumber) 133 | (is-tc-e 1 t/JSNumber) 134 | (is-tc-e true t/JSBoolean) 135 | (is-tc-e "a" t/JSString)) 136 | 137 | (deftest ns-deps-test 138 | (is (t/check-ns* 'cljs.core.typed.test.dep-one)) 139 | (is (t/check-ns* 'cljs.core.typed.test.dep-two))) 140 | 141 | (deftest hvec-infer 142 | (is-tc-e (fn [a] 143 | (a [1 2])) 144 | [[(cljs.core/IVector t/Any) -> t/Any] 145 | -> t/Any]) 146 | (is-tc-e (fn [a] 147 | (a [1 2])) 148 | [(t/All [x] [(cljs.core/IVector x) -> x]) 149 | -> t/Any])) 150 | 151 | (deftest seq-test 152 | (is-tc-e [1 2 3] (t/Coll cljs.core.typed/CLJSInteger)) 153 | (is-tc-e [1 2 3] (t/Seqable cljs.core.typed/CLJSInteger)) ;;not sure if it should be... 154 | (is-tc-e (seq [1 2 3]) (t/NonEmptyASeq cljs.core.typed/CLJSInteger))) 155 | 156 | ;(t/check-ns* 'cljs.core.typed.test.dnolen.utils.dom) 157 | ;(t/check-ns* 'cljs.core.typed.test.dnolen.utils.reactive) 158 | ;(t/check-ns* 'cljs.core.typed.test.dnolen.utils.helpers) 159 | ;(t/check-ns* 'cljs.core.typed.async) 160 | 161 | 162 | (deftest core-fns-test 163 | (t/check-ns* 'cljs.core.typed.test.ympbyc.test-base-env)) 164 | 165 | (deftest ctyp-255-cljs-test 166 | (testing "unparsing protocols is fully qualified in :unknown" 167 | (is-cljs (= (prs/unparse-type (c/Protocol-of 'cljs.core/ISet [r/-any])) 168 | '(cljs.core/ISet clojure.core.typed/Any))))) 169 | 170 | 171 | (def nodes #{:binding :case :case-node :case-test :case-then :const :def :defrecord :deftype :do :fn :fn-method :host-call :host-field :if :invoke :js :js-array :js-object :js-var :let :letfn :local :loop :map :new :no-op :ns :ns* :quote :recur :set :set! :the-var :throw :try :var :vector :with-meta 172 | }) 173 | 174 | (deftest check-case-coverage-test 175 | (fake-ana-api/reset-found) 176 | 177 | ;;let 178 | (is-tc-e (let [x 0 179 | y x] 180 | y) 181 | t/JSNumber) 182 | 183 | ;;case 184 | (is-tc-e (fn [x] (case x 185 | 0 "zero" 186 | "non-zero")) 187 | [t/JSNumber -> cljs.core.typed/JSString]) 188 | 189 | ;;def 190 | (tc-e (def x 1)) 191 | 192 | ;;fn 193 | (tc-e (fn [x] x)) 194 | 195 | 196 | ;;const 197 | (is-tc-e 1 t/JSNumber) 198 | 199 | ;;if 200 | (tc-e (if 1 1 0)) 201 | 202 | ;;letfn 203 | (tc-e (t/letfn> [foo :- [t/JSNumber -> t/JSNumber] 204 | (foo [x] x)] 205 | (foo 2))) 206 | 207 | ;;loop 208 | (is-tc-e (t/loop [a :- t/JSNumber 1 209 | b :- (t/U nil t/JSNumber) nil] 210 | (if b (str a) 211 | (recur 1 1))) 212 | t/Str) 213 | 214 | ;;map 215 | (tc-e {:name "Bob" :job "unemployed"}) 216 | 217 | ;;set 218 | (tc-e #{1 2 3}) 219 | 220 | ;;quote 221 | (tc-e '(1 2 3)) 222 | 223 | 224 | 225 | (print "MISSING NODES (fake ERROR): ") 226 | (doseq [op (sort (clojure.set/difference nodes @fake-ana-api/ops-found))] 227 | (print (str op " "))) 228 | (println)) 229 | 230 | (deftest HSequential-parse-test 231 | (is-tc-e [] (t/HSequential [t/Any *])) 232 | (is-tc-e '() (t/HSeq [t/Any *])) 233 | (is-tc-e #{:kw} (t/HSet [:kw])) 234 | ;; FIXME Value/Val parsing 235 | #_(is-tc-e {:a 1} (t/HMap :mandatory {:a (t/Value 1)})) 236 | #_(is-tc-e {:a 1} (t/HMap :mandatory {:a (t/Val 1)})) 237 | (is-tc-e {:a 1} 238 | (t/Rec [x] (t/U nil (t/HMap :mandatory {:a t/JSNumber} :optional {:b x})))) 239 | ) 240 | 241 | (deftest undefined-test 242 | (is-tc-err nil t/JSUndefined) 243 | (is-tc-err nil t/JSNull) 244 | (is (not (sub? nil cljs.core.typed/JSNull))) 245 | (is (not (sub? nil cljs.core.typed/JSUndefined))) 246 | (is (sub? cljs.core.typed/JSUndefined nil)) 247 | (is (sub? cljs.core.typed/JSNull nil)) 248 | (is-tc-e (t/fn [a :- t/JSUndefined] :- nil 249 | a)) 250 | (is-tc-e (t/fn [a :- t/JSNull] :- nil 251 | a)) 252 | (is-tc-err (t/fn [a :- t/JSNull] :- t/JSUndefined 253 | a)) 254 | (is-tc-err (t/fn [a :- t/JSUndefined] :- t/JSNull 255 | a)) 256 | (is-tc-err (when (undefined? nil) 257 | :kw) 258 | nil) 259 | (is-tc-e (t/fn [a :- t/JSNull] 260 | (when (undefined? a) 261 | :kw)) 262 | [t/JSNull :-> nil]) 263 | (is-tc-e (t/fn [a :- t/JSUndefined] 264 | (when (undefined? a) 265 | :kw)) 266 | [t/JSUndefined :-> ':kw]) 267 | (is-tc-e (do 268 | (t/ann ^:no-check a t/JSUndefined) 269 | (def a nil) 270 | a) 271 | nil) 272 | (is-tc-e (t/fn [a :- (t/U (cljs.core/IVector t/Any) t/JSUndefined)] 273 | (if a 274 | (t/ann-form a (cljs.core/IVector t/Any)) 275 | (t/ann-form a t/JSUndefined)))) 276 | ) 277 | 278 | (deftest ratio-test 279 | (is-tc-e 1/2 t/JSNumber)) 280 | 281 | (deftest goog-imports 282 | (is-cljs (t/check-ns* 'cljs.core.typed.test.goog-import))) 283 | 284 | (deftest jsobj-test 285 | (is-cljs (t/check-ns* 'cljs.core.typed.test.js-obj))) 286 | -------------------------------------------------------------------------------- /epl-v10.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Eclipse Public License - Version 1.0 8 | 25 | 26 | 27 | 28 | 29 | 30 |

Eclipse Public License - v 1.0

31 | 32 |

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE 33 | PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR 34 | DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS 35 | AGREEMENT.

36 | 37 |

1. DEFINITIONS

38 | 39 |

"Contribution" means:

40 | 41 |

a) in the case of the initial Contributor, the initial 42 | code and documentation distributed under this Agreement, and

43 |

b) in the case of each subsequent Contributor:

44 |

i) changes to the Program, and

45 |

ii) additions to the Program;

46 |

where such changes and/or additions to the Program 47 | originate from and are distributed by that particular Contributor. A 48 | Contribution 'originates' from a Contributor if it was added to the 49 | Program by such Contributor itself or anyone acting on such 50 | Contributor's behalf. Contributions do not include additions to the 51 | Program which: (i) are separate modules of software distributed in 52 | conjunction with the Program under their own license agreement, and (ii) 53 | are not derivative works of the Program.

54 | 55 |

"Contributor" means any person or entity that distributes 56 | the Program.

57 | 58 |

"Licensed Patents" mean patent claims licensable by a 59 | Contributor which are necessarily infringed by the use or sale of its 60 | Contribution alone or when combined with the Program.

61 | 62 |

"Program" means the Contributions distributed in accordance 63 | with this Agreement.

64 | 65 |

"Recipient" means anyone who receives the Program under 66 | this Agreement, including all Contributors.

67 | 68 |

2. GRANT OF RIGHTS

69 | 70 |

a) Subject to the terms of this Agreement, each 71 | Contributor hereby grants Recipient a non-exclusive, worldwide, 72 | royalty-free copyright license to reproduce, prepare derivative works 73 | of, publicly display, publicly perform, distribute and sublicense the 74 | Contribution of such Contributor, if any, and such derivative works, in 75 | source code and object code form.

76 | 77 |

b) Subject to the terms of this Agreement, each 78 | Contributor hereby grants Recipient a non-exclusive, worldwide, 79 | royalty-free patent license under Licensed Patents to make, use, sell, 80 | offer to sell, import and otherwise transfer the Contribution of such 81 | Contributor, if any, in source code and object code form. This patent 82 | license shall apply to the combination of the Contribution and the 83 | Program if, at the time the Contribution is added by the Contributor, 84 | such addition of the Contribution causes such combination to be covered 85 | by the Licensed Patents. The patent license shall not apply to any other 86 | combinations which include the Contribution. No hardware per se is 87 | licensed hereunder.

88 | 89 |

c) Recipient understands that although each Contributor 90 | grants the licenses to its Contributions set forth herein, no assurances 91 | are provided by any Contributor that the Program does not infringe the 92 | patent or other intellectual property rights of any other entity. Each 93 | Contributor disclaims any liability to Recipient for claims brought by 94 | any other entity based on infringement of intellectual property rights 95 | or otherwise. As a condition to exercising the rights and licenses 96 | granted hereunder, each Recipient hereby assumes sole responsibility to 97 | secure any other intellectual property rights needed, if any. For 98 | example, if a third party patent license is required to allow Recipient 99 | to distribute the Program, it is Recipient's responsibility to acquire 100 | that license before distributing the Program.

101 | 102 |

d) Each Contributor represents that to its knowledge it 103 | has sufficient copyright rights in its Contribution, if any, to grant 104 | the copyright license set forth in this Agreement.

105 | 106 |

3. REQUIREMENTS

107 | 108 |

A Contributor may choose to distribute the Program in object code 109 | form under its own license agreement, provided that:

110 | 111 |

a) it complies with the terms and conditions of this 112 | Agreement; and

113 | 114 |

b) its license agreement:

115 | 116 |

i) effectively disclaims on behalf of all Contributors 117 | all warranties and conditions, express and implied, including warranties 118 | or conditions of title and non-infringement, and implied warranties or 119 | conditions of merchantability and fitness for a particular purpose;

120 | 121 |

ii) effectively excludes on behalf of all Contributors 122 | all liability for damages, including direct, indirect, special, 123 | incidental and consequential damages, such as lost profits;

124 | 125 |

iii) states that any provisions which differ from this 126 | Agreement are offered by that Contributor alone and not by any other 127 | party; and

128 | 129 |

iv) states that source code for the Program is available 130 | from such Contributor, and informs licensees how to obtain it in a 131 | reasonable manner on or through a medium customarily used for software 132 | exchange.

133 | 134 |

When the Program is made available in source code form:

135 | 136 |

a) it must be made available under this Agreement; and

137 | 138 |

b) a copy of this Agreement must be included with each 139 | copy of the Program.

140 | 141 |

Contributors may not remove or alter any copyright notices contained 142 | within the Program.

143 | 144 |

Each Contributor must identify itself as the originator of its 145 | Contribution, if any, in a manner that reasonably allows subsequent 146 | Recipients to identify the originator of the Contribution.

147 | 148 |

4. COMMERCIAL DISTRIBUTION

149 | 150 |

Commercial distributors of software may accept certain 151 | responsibilities with respect to end users, business partners and the 152 | like. While this license is intended to facilitate the commercial use of 153 | the Program, the Contributor who includes the Program in a commercial 154 | product offering should do so in a manner which does not create 155 | potential liability for other Contributors. Therefore, if a Contributor 156 | includes the Program in a commercial product offering, such Contributor 157 | ("Commercial Contributor") hereby agrees to defend and 158 | indemnify every other Contributor ("Indemnified Contributor") 159 | against any losses, damages and costs (collectively "Losses") 160 | arising from claims, lawsuits and other legal actions brought by a third 161 | party against the Indemnified Contributor to the extent caused by the 162 | acts or omissions of such Commercial Contributor in connection with its 163 | distribution of the Program in a commercial product offering. The 164 | obligations in this section do not apply to any claims or Losses 165 | relating to any actual or alleged intellectual property infringement. In 166 | order to qualify, an Indemnified Contributor must: a) promptly notify 167 | the Commercial Contributor in writing of such claim, and b) allow the 168 | Commercial Contributor to control, and cooperate with the Commercial 169 | Contributor in, the defense and any related settlement negotiations. The 170 | Indemnified Contributor may participate in any such claim at its own 171 | expense.

172 | 173 |

For example, a Contributor might include the Program in a commercial 174 | product offering, Product X. That Contributor is then a Commercial 175 | Contributor. If that Commercial Contributor then makes performance 176 | claims, or offers warranties related to Product X, those performance 177 | claims and warranties are such Commercial Contributor's responsibility 178 | alone. Under this section, the Commercial Contributor would have to 179 | defend claims against the other Contributors related to those 180 | performance claims and warranties, and if a court requires any other 181 | Contributor to pay any damages as a result, the Commercial Contributor 182 | must pay those damages.

183 | 184 |

5. NO WARRANTY

185 | 186 |

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS 187 | PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 188 | OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, 189 | ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY 190 | OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely 191 | responsible for determining the appropriateness of using and 192 | distributing the Program and assumes all risks associated with its 193 | exercise of rights under this Agreement , including but not limited to 194 | the risks and costs of program errors, compliance with applicable laws, 195 | damage to or loss of data, programs or equipment, and unavailability or 196 | interruption of operations.

197 | 198 |

6. DISCLAIMER OF LIABILITY

199 | 200 |

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT 201 | NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, 202 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING 203 | WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF 204 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 205 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR 206 | DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED 207 | HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

208 | 209 |

7. GENERAL

210 | 211 |

If any provision of this Agreement is invalid or unenforceable under 212 | applicable law, it shall not affect the validity or enforceability of 213 | the remainder of the terms of this Agreement, and without further action 214 | by the parties hereto, such provision shall be reformed to the minimum 215 | extent necessary to make such provision valid and enforceable.

216 | 217 |

If Recipient institutes patent litigation against any entity 218 | (including a cross-claim or counterclaim in a lawsuit) alleging that the 219 | Program itself (excluding combinations of the Program with other 220 | software or hardware) infringes such Recipient's patent(s), then such 221 | Recipient's rights granted under Section 2(b) shall terminate as of the 222 | date such litigation is filed.

223 | 224 |

All Recipient's rights under this Agreement shall terminate if it 225 | fails to comply with any of the material terms or conditions of this 226 | Agreement and does not cure such failure in a reasonable period of time 227 | after becoming aware of such noncompliance. If all Recipient's rights 228 | under this Agreement terminate, Recipient agrees to cease use and 229 | distribution of the Program as soon as reasonably practicable. However, 230 | Recipient's obligations under this Agreement and any licenses granted by 231 | Recipient relating to the Program shall continue and survive.

232 | 233 |

Everyone is permitted to copy and distribute copies of this 234 | Agreement, but in order to avoid inconsistency the Agreement is 235 | copyrighted and may only be modified in the following manner. The 236 | Agreement Steward reserves the right to publish new versions (including 237 | revisions) of this Agreement from time to time. No one other than the 238 | Agreement Steward has the right to modify this Agreement. The Eclipse 239 | Foundation is the initial Agreement Steward. The Eclipse Foundation may 240 | assign the responsibility to serve as the Agreement Steward to a 241 | suitable separate entity. Each new version of the Agreement will be 242 | given a distinguishing version number. The Program (including 243 | Contributions) may always be distributed subject to the version of the 244 | Agreement under which it was received. In addition, after a new version 245 | of the Agreement is published, Contributor may elect to distribute the 246 | Program (including its Contributions) under the new version. Except as 247 | expressly stated in Sections 2(a) and 2(b) above, Recipient receives no 248 | rights or licenses to the intellectual property of any Contributor under 249 | this Agreement, whether expressly, by implication, estoppel or 250 | otherwise. All rights in the Program not expressly granted under this 251 | Agreement are reserved.

252 | 253 |

This Agreement is governed by the laws of the State of New York and 254 | the intellectual property laws of the United States of America. No party 255 | to this Agreement will bring a legal action under this Agreement more 256 | than one year after the cause of action arose. Each party waives its 257 | rights to a jury trial in any resulting litigation.

258 | 259 | 260 | 261 | 262 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/core/typed/check_cljs.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Ambrose Bonnaire-Sergeant, Rich Hickey & contributors. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.core.typed.check-cljs 10 | (:require [clojure.core.typed :as t] 11 | [clojure.core.typed.ast-utils :as ast-u] 12 | [clojure.core.typed.check-below :as below] 13 | [clojure.core.typed.local-result :as local-result] 14 | [clojure.core.typed.constant-type :as constant-type] 15 | [clojure.core.typed.check :as chk] 16 | [clojure.core.typed.check.binding :as binding] 17 | [clojure.core.typed.check.def :as def] 18 | [clojure.core.typed.check.do :as do] 19 | [clojure.core.typed.check.dot-cljs :as dot] 20 | [clojure.core.typed.check.const :as const] 21 | [clojure.core.typed.check.fn :as fn] 22 | [clojure.core.typed.check.fn-method-utils :as fn-method-u] 23 | [clojure.core.typed.check.funapp :as funapp] 24 | [clojure.core.typed.check.if :as if] 25 | [clojure.core.typed.check.let :as let] 26 | [clojure.core.typed.check.letfn :as letfn] 27 | [clojure.core.typed.check.local :as local] 28 | [clojure.core.typed.check.loop :as loop] 29 | [clojure.core.typed.check.map :as map] 30 | [clojure.core.typed.check.print-env :as pr-env] 31 | [clojure.core.typed.check.recur :as recur] 32 | [clojure.core.typed.check.recur-utils :as recur-u] 33 | [clojure.core.typed.check.set :as set] 34 | [clojure.core.typed.check.set-bang :as set!] 35 | [clojure.core.typed.check.throw :as throw] 36 | [clojure.core.typed.check.quote :as quote] 37 | [clojure.core.typed.check.vector :as vec] 38 | [clojure.core.typed.check.with-meta :as with-meta] 39 | [clojure.core.typed.check.special.fn :as special-fn] 40 | [clojure.core.typed.check.special.ann-form :as ann-form] 41 | [clojure.core.typed.check.special.tc-ignore :as tc-ignore] 42 | [clojure.core.typed.check.special.loop :as special-loop] 43 | [clojure.core.typed.errors :as err] 44 | [clojure.core.typed.check.utils :as cu] 45 | [clojure.core.typed.contract-utils :as con] 46 | [clojure.core.typed.type-rep :as r :refer [ret ret-t ret-o]] 47 | [clojure.core.typed.type-ctors :as c] 48 | [clojure.core.typed.subtype :as sub] 49 | [clojure.core.typed.tc-equiv :as equiv] 50 | [clojure.core.typed.utils :as u :refer [expr-type]] 51 | [clojure.core.typed.util-vars :as vs] 52 | [clojure.core.typed.var-env :as var-env] 53 | [clojure.core.typed.parse-unparse :as prs] 54 | [clojure.core.typed.lex-env :as lex] 55 | [clojure.core.typed.filter-rep :as f] 56 | [clojure.core.typed.filter-ops :as fl] 57 | [clojure.core.typed.inst :as inst] 58 | [clojure.core.typed.object-rep :as o] 59 | [clojure.core.typed.jsnominal-env :as jsnom] 60 | [clojure.core.typed.filter-ops :as fo] 61 | [clojure.core.typed.object-rep :a obj] 62 | [clojure.core.typed.analyze-cljs :as ana] 63 | [clojure.string :as c-str])) 64 | 65 | (declare check) 66 | 67 | (defn check-expr [{:keys [env] :as expr} & [expected]] 68 | (binding [vs/*current-env* (if (:line env) env vs/*current-env*) 69 | vs/*current-expr* expr] 70 | (check expr expected))) 71 | 72 | (defn check-asts [asts] 73 | (mapv check-expr asts)) 74 | 75 | (defn check-ns [nsym] 76 | {:pre [(symbol? nsym)] 77 | :post [(nil? %)]} 78 | (cu/check-ns-and-deps* 79 | nsym 80 | {:ast-for-ns ana/ast-for-ns 81 | :check-asts check-asts 82 | :check-ns check-ns})) 83 | 84 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 85 | ;;; Check CLJS AST 86 | 87 | (defmulti -check (fn [expr expected] 88 | (:op expr))) 89 | 90 | (defn check [expr & [expected]] 91 | (-check expr expected)) 92 | 93 | (defmethod -check :no-op 94 | [expr expected] 95 | (assoc expr 96 | expr-type (below/maybe-check-below 97 | (ret r/-any) 98 | expected))) 99 | 100 | (defmethod -check :const 101 | [{:keys [val] :as expr} expected] 102 | ;; FIXME probably want a custom `constant-type` function 103 | (const/check-const constant-type/constant-type false expr expected)) 104 | 105 | (defmethod -check :vector 106 | [expr expected] 107 | (vec/check-vector check expr expected)) 108 | 109 | (defmethod -check :set 110 | [expr expected] 111 | (set/check-set check expr expected)) 112 | 113 | (defmethod -check :map 114 | [expr expected] 115 | (map/check-map check expr expected)) 116 | 117 | (defmethod -check :def 118 | [{:keys [init] :as expr} expected] 119 | (if init 120 | (def/check-normal-def check expr expected) 121 | (assoc expr 122 | u/expr-type (below/maybe-check-below 123 | (ret r/-any) 124 | expected)))) 125 | 126 | (defmethod -check :js 127 | [{:keys [js-op args env] :as expr} expected] 128 | (cond 129 | js-op (let [res (expr-type (check {:op :invoke 130 | :from-js-op expr 131 | :env env 132 | :children [:fn :args] 133 | :fn {:op :var 134 | :env env 135 | :name js-op} 136 | :args args} 137 | expected))] 138 | (assoc expr 139 | u/expr-type res)) 140 | :else (do (u/tc-warning (str "js-op missing, inferring Unchecked")) 141 | (assoc expr 142 | u/expr-type (below/maybe-check-below 143 | (r/ret (r/-unchecked)) 144 | expected))))) 145 | 146 | (defmulti invoke-special (fn [{{:keys [op] :as fexpr} :fn :as expr} & expected] 147 | (when (= :var op) 148 | (:name fexpr)))) 149 | 150 | (defmethod invoke-special :default [& _] ::not-special) 151 | 152 | (defmethod invoke-special 'cljs.core.typed/print-env 153 | [{[{debug-string :form :as texpr} :as args] :args :as expr} & [expected]] 154 | (assert (= 1 (count args))) 155 | (assert (string? debug-string)) 156 | ;DO NOT REMOVE 157 | (pr-env/print-env*) 158 | ;DO NOT REMOVE 159 | (assoc expr 160 | expr-type (ret r/-any))) 161 | 162 | (defmethod invoke-special 'cljs.core.typed/inst-poly 163 | [{[pexpr targs-expr :as args] :args :as expr} & [expected]] 164 | (assert (#{2} (count args)) "Wrong arguments to inst") 165 | (let [ptype (let [t (-> (check pexpr) expr-type ret-t)] 166 | (c/fully-resolve-type t)) 167 | _ (assert ((some-fn r/Poly? r/PolyDots?) ptype)) 168 | targs (binding [prs/*parse-type-in-ns* (cu/expr-ns expr)] 169 | (mapv prs/parse-type (-> targs-expr :expr :form)))] 170 | (assoc expr 171 | expr-type (ret (inst/manual-inst ptype targs))))) 172 | 173 | (defmethod invoke-special 'cljs.core.typed/loop>-ann 174 | [{[expr {{expected-bnds-syn :expr} :form}] :args :as dummy-expr} & [expected]] 175 | (let [expected-bnds (binding [prs/*parse-type-in-ns* (cu/expr-ns dummy-expr)] 176 | (mapv prs/parse-type expected-bnds-syn))] 177 | ;loop may be nested, type the first loop found 178 | (binding [recur-u/*loop-bnd-anns* expected-bnds] 179 | (check expr expected)))) 180 | 181 | ; args are backwards if from inlining 182 | (defmethod invoke-special 'cljs.core/instance? 183 | [{:keys [args] :as expr} & [expected]] 184 | (assert (= 2 (count args)) "Wrong arguments to instance?") 185 | ; are arguments the correct way round? 186 | (assert (:from-js-op expr) "instance? without inlining NYI") 187 | (binding [vs/*current-env* (:env expr) 188 | vs/*current-expr* expr] 189 | (let [target-expr (first args) 190 | inst-of-expr (second args) 191 | varsym (when (#{:var} (:op inst-of-expr)) 192 | (-> inst-of-expr :name)) 193 | _ (when-not varsym 194 | (err/int-error (str "First argument to instance? must be a datatype var " 195 | (:op inst-of-expr)))) 196 | inst-of (c/DataType-with-unknown-params varsym) 197 | cexpr (check target-expr) 198 | expr-tr (expr-type cexpr) 199 | final-ret (ret (r/JSBoolean-maker) 200 | (fo/-FS (fo/-filter-at inst-of (ret-o expr-tr)) 201 | (fo/-not-filter-at inst-of (ret-o expr-tr))))] 202 | (assoc expr 203 | expr-type final-ret)))) 204 | 205 | ;= 206 | (defmethod invoke-special 'cljs.core/= 207 | [{:keys [args] :as expr} & [expected]] 208 | {:post [(vector? (:args %)) 209 | (-> % u/expr-type r/TCResult?)]} 210 | (let [cargs (mapv check args)] 211 | (-> expr 212 | (update-in [:fn] check) 213 | (assoc :args cargs 214 | u/expr-type (equiv/tc-equiv := (map u/expr-type cargs) expected))))) 215 | 216 | (defmethod -check :invoke 217 | [{fexpr :fn :keys [args] :as expr} expected] 218 | (let [e (invoke-special expr)] 219 | (cond 220 | (not= e ::not-special) e 221 | :else 222 | (let [cfexpr (check fexpr) 223 | cargs (mapv check args) 224 | ftype (expr-type cfexpr) 225 | argtys (map expr-type cargs) 226 | actual (funapp/check-funapp cfexpr cargs ftype argtys expected)] 227 | (assoc expr 228 | expr-type actual))))) 229 | 230 | ;only local bindings are immutable, vars/js do not partipate in occurrence typing 231 | (defn js-var-result [expr vname expected] 232 | {:pre [((every-pred symbol? namespace) vname) 233 | ((some-fn nil? r/TCResult?) expected)] 234 | :post [(r/TCResult? %)]} 235 | (binding [vs/*current-expr* expr] 236 | (let [t (var-env/type-of vname)] 237 | (below/maybe-check-below 238 | (ret t) 239 | expected)))) 240 | 241 | (defmethod -check :var 242 | [{vname :name :as expr} expected] 243 | (assoc expr expr-type 244 | (js-var-result expr vname expected))) 245 | 246 | ;(ann internal-special-form [Expr (U nil TCResult) -> Expr]) 247 | (u/special-do-op spec/special-form internal-special-form) 248 | 249 | (defmethod internal-special-form ::t/tc-ignore 250 | [expr expected] 251 | (tc-ignore/check-tc-ignore check expr expected)) 252 | 253 | (defn check-fn-rest [remain-dom & {:keys [rest drest kws prest]}] 254 | {:pre [(or (r/Type? rest) 255 | (r/Type? prest) 256 | (r/DottedPretype? drest) 257 | (r/KwArgs? kws)) 258 | (#{1} (count (filter identity [rest drest kws prest])))] 259 | :post [(r/Type? %)]} 260 | ;(prn "rest" rest) 261 | ;(prn "drest" drest) 262 | ;(prn "kws" kws) 263 | (cond 264 | (or rest drest) 265 | (c/Un r/-nil 266 | ; only difference to Clojure impl 267 | (r/TApp-maker (r/Name-maker 'cljs.core.typed/NonEmptySeq) 268 | [(or rest (:pre-type drest))])) 269 | 270 | prest (err/nyi-error "NYI handle prest in CLJS") 271 | :else (c/KwArgs->Type kws))) 272 | 273 | (defmacro prepare-check-fn [& body] 274 | `(binding [fn-method-u/*check-fn-method1-checkfn* check 275 | fn-method-u/*check-fn-method1-rest-type* check-fn-rest] 276 | ~@body)) 277 | 278 | (defmethod internal-special-form ::t/fn 279 | [{[_ _ {{fn-anns :ann} :val} :as statements] :statements fexpr :ret :as expr} expected] 280 | (prepare-check-fn 281 | (special-fn/check-special-fn check expr expected))) 282 | 283 | (defmethod internal-special-form ::t/ann-form 284 | [{[_ _ {{tsyn :type} :val} :as statements] :statements frm :ret, :keys [env], :as expr} expected] 285 | (ann-form/check-ann-form check expr expected)) 286 | 287 | (defmethod internal-special-form ::t/loop 288 | [{[_ _ {{tsyns :ann} :val} :as statements] :statements frm :ret, :keys [env], :as expr} expected] 289 | (special-loop/check-special-loop check expr expected)) 290 | 291 | (defmethod internal-special-form :default 292 | [expr expected] 293 | (err/int-error (str "No such internal form: " (ast-u/emit-form-fn expr)))) 294 | 295 | (defmethod -check :do 296 | [expr expected] 297 | (do/check-do check-expr internal-special-form expr expected)) 298 | 299 | (defmethod -check :fn 300 | [{:keys [methods] :as expr} expected] 301 | (prepare-check-fn 302 | (if expected 303 | (fn/check-fn expr expected) 304 | (special-fn/check-core-fn-no-expected check-expr expr)))) 305 | 306 | (defmethod -check :set! 307 | [{:keys [target val] :as expr} expected] 308 | (set!/check-set! check-expr expr expected)) 309 | 310 | (defmethod -check :if 311 | [{:keys [test then else] :as expr} expected] 312 | (if/check-if check-expr expr expected)) 313 | 314 | (defmethod -check :let 315 | [expr expected] 316 | (let/check-let check-expr expr expected)) 317 | 318 | (defmethod -check :letfn 319 | [{:keys [bindings body env] :as expr} expected] 320 | (letfn/check-letfn bindings body expr expected check-expr)) 321 | 322 | (defmethod -check :recur 323 | [{:keys [exprs env] :as recur-expr} expected] 324 | (recur/check-recur exprs env recur-expr expected check-expr)) 325 | 326 | (defmethod -check :loop 327 | [{:keys [] :as loop-expr} expected] 328 | (loop/check-loop check-expr loop-expr expected)) 329 | 330 | (defmethod -check :ns 331 | [expr expected] 332 | (assoc expr 333 | expr-type (below/maybe-check-below 334 | (ret r/-any) 335 | expected))) 336 | 337 | (defmethod -check :ns* 338 | [expr expected] 339 | (assoc expr 340 | u/expr-type (below/maybe-check-below 341 | (r/ret r/-any) 342 | expected))) 343 | 344 | (defmethod -check :binding 345 | [expr expected] 346 | (binding/check-binding check-expr expr expected)) 347 | 348 | (defmethod -check :quote 349 | [expr expected] 350 | (quote/check-quote check-expr constant-type/constant-type expr expected)) 351 | 352 | ;; adding a bunch of missing methods: 353 | 354 | (defn fail-empty [expr] 355 | (throw (Exception. (str "Not implemented, yet: " (:op expr))))) 356 | 357 | (defmethod -check :new 358 | [{:keys [ctor args] :as expr} expected] 359 | (let [;; TODO check ctor 360 | cargs (mapv check-expr args)] 361 | (u/tc-warning (str "`new` special form is Unchecked")) 362 | (assoc :args cargs 363 | u/expr-type (below/maybe-check-below 364 | ;; TODO actual checks 365 | (r/ret (r/-unchecked)) 366 | expected)))) 367 | 368 | ;; TODO does this actually work? 369 | (defmethod -check :case 370 | [{:keys [test nodes default :as expr]} expected] 371 | (chk/check 372 | {:op :case 373 | :test test 374 | :default default 375 | :tests (mapcat :tests nodes) 376 | :thens (map :then nodes)} 377 | expected)) 378 | 379 | (defmethod -check :case-node 380 | [expr expected] 381 | (fail-empty expr)) 382 | 383 | (defmethod -check :case-test 384 | [expr expected] 385 | (fail-empty expr)) 386 | 387 | (defmethod -check :case-then 388 | [expr expected] 389 | (fail-empty expr)) 390 | 391 | ;TODO 392 | (defmethod -check :defrecord 393 | [expr expected] 394 | (u/tc-warning (str "`defrecord` special form is Unchecked")) 395 | (assoc expr 396 | u/expr-type (below/maybe-check-below 397 | (r/ret (r/-unchecked)) 398 | expected))) 399 | 400 | (defmethod -check :deftype 401 | [expr expected] 402 | (u/tc-warning (str "`deftype` special form is Unchecked")) 403 | (assoc expr 404 | u/expr-type (below/maybe-check-below 405 | (r/ret (r/-unchecked)) 406 | expected))) 407 | 408 | (defmethod -check :fn-method 409 | [expr expected] 410 | (fail-empty expr)) 411 | 412 | ; see clojure.core.typed.check.dot-cljs 413 | ;; TODO check 414 | (defmethod -check :host-call 415 | [{:keys [method target args] :as expr} expected] 416 | (let [ctarget (check-expr target) 417 | cargs (mapv check-expr args)] 418 | (u/tc-warning (str "`.` special form is Unchecked")) 419 | (assoc expr 420 | :target ctarget 421 | :args cargs 422 | u/expr-type (below/maybe-check-below 423 | (r/ret (r/-unchecked)) 424 | expected)))) 425 | 426 | ; see clojure.core.typed.check.dot-cljs 427 | ;; TODO check 428 | (defmethod -check :host-field 429 | [{:keys [target] :as expr} expected] 430 | (let [ctarget (check-expr target)] 431 | (u/tc-warning (str "`.` special form is Unchecked")) 432 | (assoc expr 433 | :target ctarget 434 | u/expr-type (below/maybe-check-below 435 | (r/ret (r/-unchecked)) 436 | expected)))) 437 | 438 | ;; TODO check 439 | (defmethod -check :js-array 440 | [{:keys [items] :as expr} expected] 441 | (let [citems (mapv check-expr items)] 442 | (u/tc-warning (str "`#js []` special form is Unchecked")) 443 | (assoc expr 444 | :items citems 445 | u/expr-type (below/maybe-check-below 446 | (r/ret (r/-unchecked)) 447 | expected)))) 448 | 449 | (defmethod -check :js-object 450 | [{:keys [keys vals] :as expr} expected] 451 | (let [cvals (mapv check-expr vals)] 452 | (assoc expr 453 | :vals cvals 454 | u/expr-type (below/maybe-check-below 455 | (r/ret (r/JSObj-maker (zipmap (map keyword keys) 456 | (map (comp r/ret-t u/expr-type) cvals))) 457 | (fo/-true-filter)) 458 | expected)))) 459 | 460 | ; TODO check 461 | (defmethod -check :js-var 462 | [{:keys [name] :as expr} expected] 463 | (u/tc-warning (str "Assuming JS variable is unchecked " name)) 464 | (assoc expr 465 | u/expr-type (below/maybe-check-below 466 | (r/ret (r/-unchecked)) 467 | expected))) 468 | 469 | (defmethod -check :local 470 | [expr expected] 471 | (local/check-local expr expected)) 472 | 473 | 474 | ; TODO check 475 | (defmethod -check :the-var 476 | [expr expected] 477 | (u/tc-warning (str "`var` special form is Unchecked")) 478 | (assoc expr 479 | u/expr-type (below/maybe-check-below 480 | (r/ret (r/-unchecked)) 481 | expected))) 482 | 483 | (defmethod -check :throw 484 | [expr expected] 485 | (throw/check-throw check-expr expr expected nil)) 486 | 487 | ; TODO check 488 | (defmethod -check :try 489 | [expr expected] 490 | (fail-empty expr)) 491 | 492 | (defmethod -check :with-meta 493 | [expr expected] 494 | (with-meta/check-with-meta check-expr expr expected)) 495 | -------------------------------------------------------------------------------- /src/main/clojure/clojure/core/typed/base_env_cljs.clj: -------------------------------------------------------------------------------- 1 | ;; Copyright (c) Ambrose Bonnaire-Sergeant, Rich Hickey & contributors. 2 | ;; The use and distribution terms for this software are covered by the 3 | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 4 | ;; which can be found in the file epl-v10.html at the root of this distribution. 5 | ;; By using this software in any fashion, you are agreeing to be bound by 6 | ;; the terms of this license. 7 | ;; You must not remove this notice, or any other, from this software. 8 | 9 | (ns clojure.core.typed.base-env-cljs 10 | (:require [clojure.core.typed.base-env-helper-cljs :as h] 11 | [clojure.core.typed.base-env-common :refer [delay-and-cache-env] 12 | :as common] 13 | [clojure.core.typed.current-impl :as impl] 14 | [clojure.core.typed.bootstrap-cljs :as boot] 15 | [cljs.analyzer :as ana] 16 | [clojure.core.typed.util-cljs :as ucljs] 17 | [cljs.env :as env] 18 | [clojure.set :as set])) 19 | 20 | (ucljs/with-cljs-typed-env 21 | (ucljs/with-core-cljs-typed 22 | (binding [ana/*cljs-ns* 'cljs.core.typed] 23 | (delay-and-cache-env ^:private init-protocol-env 24 | (h/protocol-mappings 25 | 26 | cljs.core/Fn [[]] 27 | cljs.core/IFn [[]] 28 | cljs.core/ICloneable [[]] 29 | cljs.core/ICounted [[]] 30 | cljs.core/IEmptyableCollection [[]] 31 | cljs.core/ICollection [[[x :variance :covariant]]] 32 | cljs.core/IIndexed [[]] 33 | cljs.core/ASeq [[[x :variance :covariant]]] 34 | cljs.core/ISeqable [[[x :variance :covariant]]] 35 | cljs.core/ISeq [[[x :variance :covariant]]] 36 | cljs.core/INext [[[x :variance :covariant]]] 37 | cljs.core/ILookup [[[maxk :variance :covariant] 38 | [v :variance :covariant]]] 39 | cljs.core/IAssociative [[[k :variance :covariant] 40 | [v :variance :covariant]]] 41 | cljs.core/IMap [[[k :variance :covariant] 42 | [v :variance :covariant]]] 43 | cljs.core/IMapEntry [[[k :variance :covariant] 44 | [v :variance :covariant]]] 45 | cljs.core/ISet [[[x :variance :covariant]]] 46 | cljs.core/IStack [[[x :variance :covariant]]] 47 | cljs.core/IVector [[[x :variance :covariant]]] 48 | cljs.core/IDeref [[[x :variance :covariant]]] 49 | cljs.core/IDerefWithTimeout [[[x :variance :covariant]]] 50 | cljs.core/IMeta [[]] 51 | cljs.core/IWithMeta [[]] 52 | ;TODO 53 | ;cljs.core/IReduce [[]] 54 | ;cljs.core/IKVReduce [[]] 55 | cljs.core/IList [[[x :variance :covariant]]] 56 | cljs.core/IEquiv [[]] 57 | cljs.core/IHash [[]] 58 | cljs.core/ISequential [[]] 59 | cljs.core/Record [[]] 60 | cljs.core/IReversible [[[x :variance :covariant]]] 61 | cljs.core/ISorted [[]] 62 | cljs.core/IWriter [[]] 63 | cljs.core/IPrintWithWriter [[]] 64 | cljs.core/IPending [[]] 65 | ;TODO 66 | ;cljs.core/IWatchable [[]] 67 | ;cljs.core/IEditableCollection [[]] 68 | ;cljs.core/ITransientCollection [[]] 69 | ;cljs.core/ITransientAssociative [[]] 70 | ;cljs.core/ITransientMap [[]] 71 | ;cljs.core/ITransientVector [[]] 72 | ;cljs.core/ITransientSet [[]] 73 | cljs.core/IComparable [[]] 74 | ;cljs.core/IChunk [[]] 75 | ;cljs.core/IChunkedSeq [[]] 76 | ;cljs.core/IChunkedNext [[]] 77 | cljs.core/INamed [[]] 78 | cljs.core/Reduced [[[x :variance :covariant]]] 79 | )) 80 | 81 | (let [rst! (delay (impl/dynaload 'clojure.core.typed.protocol-env/reset-protocol-env!))] 82 | (defn reset-protocol-env! [] 83 | (impl/with-cljs-impl 84 | (@rst! (init-protocol-env))))) 85 | 86 | #_ 87 | (ann-jsclass js/Document 88 | :extends 89 | :implements 90 | :properties 91 | {getElementById [cljs.core.typed/JSString -> (U nil js/HTMLElement)]} 92 | :static-properties 93 | ) 94 | 95 | (delay-and-cache-env ^:private init-jsnominals 96 | (reset-protocol-env!) 97 | (h/jsnominal-mappings 98 | 99 | ; seems like a good place to put this 100 | ;; FIXME this is actually js/String, delete 101 | string [[] 102 | :fields 103 | {} 104 | :methods 105 | {toLowerCase [-> cljs.core.typed/JSString]}] 106 | 107 | js/Document [[] 108 | :fields 109 | {} 110 | :methods 111 | {getElementById [cljs.core.typed/JSString -> (U nil js/HTMLElement)]}] 112 | 113 | js/HTMLElement [[] 114 | :fields 115 | {innerHTML cljs.core.typed/JSString 116 | tagName (U nil cljs.core.typed/JSString)}] 117 | 118 | 119 | js/Event [[] 120 | :methods 121 | {preventDefault [-> nil]}] 122 | 123 | 124 | ;http://dom.spec.whatwg.org/#interface-eventtarget 125 | js/EventTarget [[]] 126 | 127 | goog.events.Listenable [[]] 128 | goog.events.EventTarget [[]] 129 | )) 130 | 131 | (let [rst! (delay (impl/dynaload 'clojure.core.typed.jsnominal-env/reset-jsnominal!))] 132 | (defn reset-jsnominal-env! [] 133 | (impl/with-cljs-impl 134 | (@rst! (init-jsnominals))))) 135 | 136 | ;;; vars specific to cljs 137 | (delay-and-cache-env ^:private init-var-env 138 | (reset-protocol-env!) 139 | (reset-jsnominal-env!) 140 | (merge 141 | (common/parse-cljs-ann-map @common/common-var-annotations) 142 | (h/var-mappings 143 | 144 | ;internal vars 145 | cljs.core.typed/ann* [Any Any -> Any] 146 | cljs.core.typed/ann-protocol* [Any Any Any -> Any] 147 | cljs.core.typed/ann-datatype* [Any Any Any Any -> Any] 148 | cljs.core.typed/def-alias* [Any Any -> Any] 149 | cljs.core.typed/typed-deps* [Any -> Any] 150 | cljs.core.typed/ann-jsnominal* [Any Any -> Any] 151 | 152 | cljs.core/+ (IFn [cljs.core.typed/CLJSInteger * -> cljs.core.typed/CLJSInteger] 153 | [cljs.core.typed/JSNumber * -> cljs.core.typed/JSNumber]) 154 | cljs.core/- (IFn [cljs.core.typed/CLJSInteger * -> cljs.core.typed/CLJSInteger] 155 | [cljs.core.typed/JSNumber * -> cljs.core.typed/JSNumber]) 156 | cljs.core/* (IFn [cljs.core.typed/CLJSInteger * -> cljs.core.typed/CLJSInteger] 157 | [cljs.core.typed/JSNumber * -> cljs.core.typed/JSNumber]) 158 | cljs.core/nth (All [x y] 159 | (IFn [(U nil (cljs.core/ISeqable x)) cljs.core.typed/CLJSInteger -> x] 160 | [(U nil (cljs.core/ISeqable x)) cljs.core.typed/CLJSInteger y -> (U y x)])) 161 | 162 | cljs.core/*flush-on-newline* cljs.core.typed/JSBoolean 163 | cljs.core/*print-newline* cljs.core.typed/JSBoolean 164 | cljs.core/*print-readably* cljs.core.typed/JSBoolean 165 | cljs.core/*print-meta* cljs.core.typed/JSBoolean 166 | cljs.core/*print-dup* cljs.core.typed/JSBoolean 167 | cljs.core/*print-length* (U nil cljs.core.typed/CLJSInteger) 168 | 169 | cljs.core/enable-console-print! [-> Any] 170 | 171 | cljs.core/truth_ [Any -> Any] 172 | 173 | cljs.core/coercive-= [Any Any -> cljs.core.typed/JSBoolean] 174 | 175 | cljs.core/nil? (Pred nil) 176 | cljs.core/undefined? (Pred JSUndefined) 177 | 178 | cljs.core/array? (ReadOnlyArray Any) 179 | 180 | cljs.core/object? [Any -> cljs.core.typed/JSBoolean] 181 | 182 | cljs.core/native-satisfies? [Any Any -> Any] 183 | 184 | cljs.core/is_proto_ [Any -> Any] 185 | 186 | cljs.core/*main-cli-fn* (U nil [Any * -> Any]) 187 | 188 | cljs.core/missing-protocol [Any Any -> Any] 189 | cljs.core/type->str [Any -> cljs.core.typed/JSString] 190 | 191 | cljs.core/make-array (All [r] 192 | (IFn [cljs.core.typed/CLJSInteger -> (Array r)] 193 | [Any cljs.core.typed/CLJSInteger -> (Array r)])) 194 | 195 | cljs.core/array (All [r] 196 | [r * -> (Array r)]) 197 | 198 | cljs.core/alength [(ReadOnlyArray Any) -> cljs.core.typed/CLJSInteger] 199 | 200 | cljs.core/into-array (All [x] 201 | (IFn [(U nil (cljs.core/ISeqable x)) -> (Array x)] 202 | [Any (U nil (cljs.core/ISeqable x)) -> (Array x)])) 203 | 204 | cljs.core/pr-str* [Any -> cljs.core.typed/JSString] 205 | 206 | cljs.core/clone [Any -> Any] 207 | 208 | cljs.core/cloneable? (Pred cljs.core/ICloneable) 209 | 210 | 211 | cljs.core/count 212 | ; TODO also accepts Counted 213 | ; FIXME should return integer 214 | [(U nil (cljs.core/ISeqable Any)) -> cljs.core.typed/CLJSInteger :object {:id 0, :path [Count]}] 215 | cljs.core/prim-seq 216 | (All [x] 217 | [(cljs.core/ISeqable x) -> (U nil (cljs.core/ISeq x))]) 218 | 219 | cljs.core/key-test [Keyword Any -> cljs.core.typed/JSBoolean] 220 | 221 | cljs.core/fn? [Any -> cljs.core.typed/JSBoolean] 222 | cljs.core/ifn? [Any -> cljs.core.typed/JSBoolean] 223 | 224 | ;;pop needs to be defined here because 225 | ;;definition of List differs between clj and cljs 226 | cljs.core/pop (All [x] 227 | (IFn 228 | [(IList x) -> (IList x)] 229 | [(Vec x) -> (Vec x)] 230 | [(Stack x) -> (Stack x)])) 231 | 232 | cljs.core/clj->js [Any -> Any] 233 | cljs.core/js->clj [Any -> Any] 234 | cljs.core/js-obj [Any * -> Any] 235 | 236 | ;;pseudo-private vars 237 | cljs.core/-conj [Any Any -> Any] 238 | ;cljs.core.List.Empty (IList Any) 239 | ))) 240 | 241 | (delay-and-cache-env ^:private init-var-nochecks 242 | (set (keys (init-var-env)))) 243 | 244 | (delay-and-cache-env init-jsvar-env 245 | (reset-protocol-env!) 246 | (reset-jsnominal-env!) 247 | (h/js-var-mappings 248 | ;; js 249 | 250 | js/document js/Document 251 | 252 | ;; goog.dom 253 | 254 | goog.dom/setTextContent [js/Element (U cljs.core.typed/JSString cljs.core.typed/JSNumber) -> js/Window] 255 | goog.dom/getElementsByTagNameAndClass 256 | [(U nil cljs.core.typed/JSString) (U nil cljs.core.typed/JSString) (U nil js/Document js/Element) -> (cljs.core/ISeqable js/Element)] 257 | goog.dom.classes/set [(U js/Node nil) cljs.core.typed/JSString -> Any] 258 | goog.dom.classes/add [(U js/Node nil) (U nil cljs.core.typed/JSString) * -> cljs.core.typed/JSBoolean] 259 | goog.dom.classes/remove [(U js/Node nil) (U nil cljs.core.typed/JSString) * -> cljs.core.typed/JSBoolean] 260 | goog.style/getPageOffsetLeft [(U nil js/Element) -> cljs.core.typed/JSNumber] 261 | goog.style/getPageOffsetTop [(U nil js/Element) -> cljs.core.typed/JSNumber] 262 | goog.events/listen [(U nil js/EventTarget goog.events.EventTarget goog.events.Listenable) 263 | (U nil cljs.core.typed/JSString (ReadOnlyArray cljs.core.typed/JSString)) -> cljs.core.typed/JSNumber] 264 | 265 | goog.events.EventType.KEYUP cljs.core.typed/JSString 266 | goog.events.EventType.KEYDOWN cljs.core.typed/JSString 267 | goog.events.EventType.KEYPRESS cljs.core.typed/JSString 268 | goog.events.EventType.CLICK cljs.core.typed/JSString 269 | goog.events.EventType.DBLCLICK cljs.core.typed/JSString 270 | goog.events.EventType.MOUSEOVER cljs.core.typed/JSString 271 | goog.events.EventType.MOUSEOUT cljs.core.typed/JSString 272 | goog.events.EventType.MOUSEMOVE cljs.core.typed/JSString 273 | )) 274 | 275 | (delay-and-cache-env init-alias-env 276 | (reset-protocol-env!) 277 | (reset-jsnominal-env!) 278 | (h/alias-mappings 279 | ^{:doc "A type that returns true for cljs.core/integer?"} 280 | cljs.core.typed/AnyInteger cljs.core.typed/CLJSInteger 281 | 282 | ^{:doc "A type that returns true for cljs.core/integer?"} 283 | cljs.core.typed/Integer cljs.core.typed/CLJSInteger 284 | 285 | ^{:doc "A type that returns true for cljs.core/integer?"} 286 | cljs.core.typed/Int cljs.core.typed/CLJSInteger 287 | 288 | ^{:doc "A type that returns true for cljs.core/number?"} 289 | cljs.core.typed/Number cljs.core.typed/JSNumber 290 | 291 | ^{:doc "A type that returns true for cljs.core/number?"} 292 | cljs.core.typed/Num cljs.core.typed/JSNumber 293 | 294 | ^{:doc "A type that returns true for cljs.core/string?"} 295 | cljs.core.typed/String cljs.core.typed/JSString 296 | 297 | ^{:doc "A type that returns true for cljs.core/string?"} 298 | cljs.core.typed/Str cljs.core.typed/JSString 299 | 300 | ^{:doc "A type that returns true for cljs.core/boolean?"} 301 | cljs.core.typed/Boolean cljs.core.typed/JSBoolean 302 | 303 | ^{:doc "vector -- alias for common anns"} 304 | cljs.core.typed/Vec (TFn [[x :variance :covariant]] 305 | (IVector x)) 306 | 307 | ^{:doc "vector -- alias for common anns"} 308 | cljs.core.typed/IPersistentVector (TFn [[x :variance :covariant]] 309 | (IVector x)) 310 | 311 | ^{:doc "map -- alias for common anns"} 312 | cljs.core.typed/Map (TFn [[k :variance :covariant] 313 | [v :variance :covariant]] 314 | (IMap k v)) 315 | 316 | ^{:doc "map -- alias for common anns"} 317 | cljs.core.typed/IPersistentMap (TFn [[k :variance :covariant] 318 | [v :variance :covariant]] 319 | (IMap k v)) 320 | 321 | ^{:doc "map -- alias for common anns"} 322 | cljs.core.typed/APersistentMap (TFn [[k :variance :covariant] 323 | [v :variance :covariant]] 324 | (IMap k v)) 325 | 326 | ^{:doc "associative -- alias for common anns"} 327 | cljs.core.typed/Associative IAssociative 328 | 329 | ^{:doc "An atom that can read and write type x." 330 | :forms [(Atom1 t)]} 331 | cljs.core.typed/Atom1 (TFn [[x :variance :invariant]] 332 | (cljs.core/Atom x x)) 333 | ^{:doc "An atom that can write type w and read type r." 334 | :forms [(Atom2 t)]} 335 | cljs.core.typed/Atom2 (TFn [[w :variance :contravariant] 336 | [r :variance :covariant]] 337 | (cljs.core/Atom w r)) 338 | 339 | ^{:doc "sequential -- alias for common anns"} 340 | cljs.core.typed/Sequential ISequential 341 | 342 | ^{:doc "set -- alias for common anns"} 343 | cljs.core.typed/Set ISet 344 | 345 | ^{:doc "set -- alias for common anns"} 346 | cljs.core.typed/IPersistentSet ISet 347 | 348 | 349 | ^{:doc "A type that can be used to create a sequence of member type x."} 350 | cljs.core.typed/Seqable (TFn [[x :variance :covariant]] 351 | (cljs.core/ISeqable x)) 352 | 353 | ^{:doc "A persistent sequence of member type x." 354 | :forms [(Seq t)]} 355 | cljs.core.typed/Seq (TFn [[x :variance :covariant]] 356 | (cljs.core/ISeq x)) 357 | 358 | ^{:doc "A persistent sequence of member type x with count greater than 0." 359 | :forms [(NonEmptySeq t)]} 360 | cljs.core.typed/NonEmptySeq (TFn [[x :variance :covariant]] 361 | (I (cljs.core/ISeq x) (CountRange 1))) 362 | 363 | 364 | 365 | 366 | ;;copied from impl/init-aliases 367 | 368 | ;;Seqables 369 | ^{:doc "A type that can be used to create a sequence of member type x 370 | with count 0." 371 | :forms [(EmptySeqable t)]} 372 | cljs.core.typed/EmptySeqable (TFn [[x :variance :covariant]] 373 | (I (cljs.core.typed/Seqable x) (ExactCount 0))) 374 | 375 | ^{:doc "A type that can be used to create a sequence of member type x 376 | with count greater than 0." 377 | :forms [(NonEmptySeqable t)]} 378 | cljs.core.typed/NonEmptySeqable 379 | (TFn [[x :variance :covariant]] 380 | (I (cljs.core.typed/Seqable x) (CountRange 1))) 381 | 382 | ;;Option 383 | ^{:doc "A union of x and nil." 384 | :forms [(Option t)]} 385 | cljs.core.typed/Option (TFn [[x :variance :covariant]] (U nil x)) 386 | 387 | 388 | ^{:doc "A persistent collection with member type x." 389 | :forms [(Coll t)]} 390 | cljs.core.typed/Coll (TFn [[x :variance :covariant]] 391 | (cljs.core/ICollection x)) 392 | 393 | ^{:doc "A persistent collection with member type x and count greater than 0." 394 | :forms [(NonEmptyColl t)]} 395 | cljs.core.typed/NonEmptyColl (TFn [[x :variance :covariant]] 396 | (I (cljs.core/ICollection x) 397 | (CountRange 1))) 398 | 399 | ^{:doc "A sequential non-empty seq retured from clojure.core/seq" 400 | :forms [(NonEmptyASeq t)]} 401 | cljs.core.typed/NonEmptyASeq 402 | (TFn [[x :variance :covariant]] 403 | (I (cljs.core/ASeq x) 404 | (cljs.core/ISeq x) 405 | (cljs.core/ISeqable x) 406 | cljs.core/ISequential 407 | ;(Iterable x) 408 | (cljs.core/ICollection x) 409 | (cljs.core/IList x) 410 | ;clojure.lang.IObj 411 | (CountRange 1))) 412 | 413 | 414 | ^{:doc "The type of all things with count 0. Use as part of an intersection. 415 | eg. See EmptySeqable." 416 | :forms [EmptyCount]} 417 | cljs.core.typed/EmptyCount (ExactCount 0) 418 | 419 | ^{:doc "The type of all things with count greater than 0. Use as part of an intersection. 420 | eg. See NonEmptySeq" 421 | :forms [NonEmptyCount]} 422 | cljs.core.typed/NonEmptyCount (CountRange 1) 423 | 424 | ^{:doc "A union of x and nil." 425 | :forms [(Nilable t)]} 426 | cljs.core.typed/Nilable (TFn [[x :variance :covariant]] (U nil x)) 427 | 428 | ^{:doc "A persistent vector returned from clojure.core/vector (and others)" 429 | :forms [(AVec t)]} 430 | cljs.core.typed/AVec (TFn [[x :variance :covariant]] 431 | (I (IPersistentVector x) 432 | ;(java.lang.Iterable x) 433 | (ICollection x) 434 | (IList x) 435 | ;clojure.lang.IObj 436 | )) 437 | 438 | ^{:doc "A persistent vector returned from clojure.core/vector (and others) and count greater than 0." 439 | :forms [(NonEmptyAVec t)]} 440 | cljs.core.typed/NonEmptyAVec (TFn [[x :variance :covariant]] 441 | (I (IPersistentVector x) 442 | ;(java.lang.Iterable x) 443 | (ICollection x) 444 | (IList x) 445 | ;clojure.lang.IObj 446 | (CountRange 1))) 447 | 448 | ^{:doc "The result of clojure.core/seq." 449 | :forms [(NilableNonEmptyASeq t)]} 450 | cljs.core.typed/NilableNonEmptyASeq 451 | (TFn [[x :variance :covariant]] 452 | (U nil 453 | (I (cljs.core/ASeq x) 454 | (cljs.core/ISeq x) 455 | cljs.core/ISequential 456 | ;(Iterable x) 457 | (cljs.core/ICollection x) 458 | (cljs.core/IList x) 459 | ;clojure.lang.IObj 460 | (CountRange 1)))) 461 | 462 | ^{:doc "A Clojure persistent list." 463 | :forms [(PersistentList t)]} 464 | cljs.core.typed/PersistentList 465 | (TFn [[x :variance :covariant]] 466 | (cljs.core/IList x)) 467 | 468 | ^{:doc "Collection"} 469 | cljs.core.typed/Collection 470 | (TFn [[x :variance :covariant]] 471 | (cljs.core/ICollection x)) 472 | 473 | ^{:doc "A Clojure stack." 474 | :forms [(Stack t)]} 475 | cljs.core.typed/Stack 476 | (TFn [[x :variance :covariant]] 477 | (cljs.core/IStack x)) 478 | 479 | ^{:doc "Reversible maps to IReversible" 480 | :forms [(Reversible t)]} 481 | cljs.core.typed/Reversible 482 | (TFn [[x :variance :covariant]] 483 | (cljs.core/IReversible x)))) 484 | 485 | 486 | (let [rst! (delay (impl/dynaload 'clojure.core.typed.name-env/reset-name-env!))] 487 | (defn reset-alias-env! [] 488 | (let [alias-env (init-alias-env)] 489 | ; Ensure init-alias-env agrees with the -base-aliases 490 | (assert (= (set (keys alias-env)) 491 | (set (map #(symbol "cljs.core.typed" (str %)) 492 | boot/-base-aliases))) 493 | (str "core.typed Bug! Base aliases do not agree with base environment." 494 | " Missing from cljs.core.typed ns: " 495 | (set/difference (set (keys alias-env)) 496 | (set (map #(symbol "cljs.core.typed" (str %)) 497 | boot/-base-aliases))) 498 | " Missing from base-env-cljs ns " 499 | (set/difference (set (map #(symbol "cljs.core.typed" (str %)) 500 | boot/-base-aliases)) 501 | (set (keys alias-env))))) 502 | (@rst! alias-env)))) 503 | 504 | (delay-and-cache-env init-declared-kinds {}) 505 | 506 | (delay-and-cache-env init-datatype-env 507 | (reset-protocol-env!) 508 | (reset-jsnominal-env!) 509 | (h/datatype-mappings 510 | 511 | cljs.core/Atom [[[w :variance :contravariant] 512 | [r :variance :covariant]]] 513 | cljs.core/Symbol [[]] 514 | cljs.core/Keyword [[]] 515 | cljs.core/List [[[a :variance :covariant]]] 516 | cljs.core/Reduced [[[x :variance :covariant]]] 517 | )) 518 | ) 519 | 520 | (let [reset-var-type-env! (delay (impl/dynaload 'clojure.core.typed.var-env/reset-var-type-env!)) 521 | reset-jsvar-type-env! (delay (impl/dynaload 'clojure.core.typed.var-env/reset-jsvar-type-env!)) 522 | reset-declared-kinds! (delay (impl/dynaload 'clojure.core.typed.declared-kind-env/reset-declared-kinds!)) 523 | reset-datatype-env! (delay (impl/dynaload 'clojure.core.typed.datatype-env/reset-datatype-env!))] 524 | (defn reset-cljs-envs! [] 525 | (ucljs/with-cljs-typed-env 526 | (impl/with-cljs-impl 527 | (reset-alias-env!) 528 | (@reset-var-type-env! (init-var-env) (init-var-nochecks)) 529 | (@reset-jsvar-type-env! (init-jsvar-env)) 530 | (reset-protocol-env!) 531 | (@reset-declared-kinds! (init-declared-kinds)) 532 | (reset-jsnominal-env!) 533 | (@reset-datatype-env! (init-datatype-env)))) 534 | nil)))) 535 | --------------------------------------------------------------------------------