* parameterise clojure.lang.IFn by its function
* clojure.lang.IFn [[f :variance :covariant :< AnyFunction]]
* (clojure.lang.IFn t) just unwraps t until it's a t/IFn.
* eg. (clojure.lang.IFn [Int -> Bool]) :< [Int -> Bool]
* eg. (clojure.lang.IFn (t/IFn [Int -> Bool])) :< [Int -> Bool]
* eg. (clojure.lang.IFn (t/All [a] (t/IFn [a -> Bool]))) :< (t/All [a] (t/IFn [a -> Bool]))
* eg. (clojure.lang.IFn (clojure.lang.IFn [a -> Bool]])) :< (t/All [a] (t/IFn [a -> Bool]))
* eg. (clojure.lang.IFn (clojure.lang.IFn ':a)) :!< ':a
* eg. (clojure.lang.IFn (clojure.lang.IFn ':a)) :< (All [a] ['{:a a} -> a])
* add t/AnyFunction
* maybe call it t/AnyIFn ?
* kind of ties it to IFn, not Callable/Runnable, but TBH
I think that shipped sailed due to the c.l.IFn subtyping rule
for t/IFn
* add ToIFn type op
* (ToIFn ':a) => (All [x] ['{:a x} :-> x])
* make MultiFn parameterised by its function + dispatch function
* (MultiFn f d)
* eg. (MultiFn [Op -> Any] ':op)
* replace IFn ancestor with (clojure.lang.IFn f)
* move out fake IFn ancestor of IPersistentSet into an intersection in t/Set
* support named arguments in t/IFn
* [x :- Any, y :- Any :-> Any :object x]
* sugar for common multimethod dispatch fns
* eg. (defmulti f (fn [a b] [(class a) (class b)]))
* maybe:
* [x :- Any, y :- Any :-> '[(ResultOf (class x)) (ResultOf (class x))]]
* eg. (defmulti f (fn [a b] [(class (:f a)) (class (:g b))]))
* maybe:
* [x :- Any, y :- Any :-> '[(ResultOf (class (:f x))) (ResultOf (class (:g x)))]]
* [x :- Any, y :- Any :-> '[(Result-> x :f class) (Result-> x :g class)]]
* use var env as a type alias
* eg. (ann foo t/Int)
* (ann-form 1 (TypeOf foo))
* might be useful in mm dispatch fn
* eg. (ann f (MultiFn [Op :-> Any] (TypeOf class)))
(defmulti f class)
* fix JVM primitive coersions
* eg. int <: long
* eg. (Val -1) <: long
* see clojure.lang.Reflector/boxArg for specific rules
* add vars for primitives
* t/int
* t/char
* t/long
* t/short
* t/float
* t/double
* t/byte
* t/boolean
* (defalias Integer/TYPE t/int) etc.
* JVM arrays
* t/int<>
* t/char<>
* t/long<>
* t/short<>
* t/float<>
* t/double<>
* t/byte<>
* t/boolean<>
* (t/Array t)
* exclusively for arrays of reference types
* (t/Array t/int) <!: t/int<>
* (t/Array t/int) <?: (t/Array t/Int)
*
* deprecate Array/Array2/Array3
* [BREAKING] make higher-kinded types explicit
* eg. t/Seq => (t/Seq Any)
* where Any is the upper bound if covariant, lower bound if contravariant
* old behaviour is to expand to (TFn [[a :variance :covariant]] (ISeq a))
* should still allow TFn to expand to itself
* only applies for symbols naming classes or aliases
* alternatively, add support for deprecated warnings on specific classes/aliases
* add HKT op for explicit TFn
* (t/HKT t/Seq) => (TFn [[a :variance :covariant]] (ISeq a))
* (t/HKT t/Map) => (TFn [[a :variance :covariant] [b :variance :covariant]] (IPersistentMap a b))
* allow currying
* (t/HKT t/Map t/Int) => (TFn [[b :variance :covariant]] (IPersistentMap t/Int b))
* (t/HKT t/Map t/Int t/Int) => (IPersistentMap t/Int t/Int)
* move all base-env annotations into real .cljc files that can be shared with cljs impl
* make clojure.core.typed a .cljc file and deprecate cljs.core.typed
* only use positive information when calculating args to defmethod's
* eg. (ann f (t/Multi [Any -> Any] (t/TypeOf number?)))
(defmulti f number?)
(defmethod f true
[a]
; a :- Number
)
(defmethod f false
[a]
; a :- (Not Number)
)
;; don't calculate any information here.
(defmethod f :default
[a]
; a :- Any
)
* Rationale
* defmethod is open to extension anyway, we can't be sure new methods don't exist
* obvious case: might be halfway through evaluating a file, and other defmethod's
aren't evaluated yet
* removes the problem with "unreachable defmethod" in :default
* because very often a default method is implementated that just
throws an error to handle dynamic errors. we still want to check that code.
* use information from `derive` to inform isa? comparisons
* only positive information?
Other ideas
===========
* add type parameter to Keyword for singleton types
* Keyword [[k :variance :covariant <: (I (Instance Keyword) AnyValue)]]
* ['{:a t/Int} :-> t/Int] <: (Keyword ':a)
* add t/ucast for unchecked casts
* don't generate vars for defalias's
* eagerly parse
* (defalias foo t/Int)
;compiles to
=> (swap! registry assoc 'user/foo (parse-type t/Int))
* probably not much overhead?
* assume registry is stable when expanding aliases
* eg. (ann f Int)
(ann g f)
If `f` changes while parsing `g`, I don't think we should
do anything special about that.
* lazily parse
* delay
* (defalias foo t/Int)
;compiles to
=> (let [ns *ns*]
(swap! registry assoc 'user/foo (delay (binding [*ns* ns]
(parse-type 't/Int)))))
* probably doesn't work in CLJS?
* this would be ideal in terms of collection performance
* (swap! registry assoc 'user/foo {:ns 'user :form 't/Int})
* actually, since `pred` and `cast` are macros, we can insert
the cast when the macro expands
* at mexpansion time we can parse the type at the given namespace
* then, have an separate type->contract implementations for clj/cljs
* this assumes the aliases/requires of a ns only accrues, since collection
can happen at any time
* reasonable assumption, we make the same assumption already, just we
"fix" the meaning of aliases earlier (at type definition time instead of type use time)
* or AOT compile annotations?
* (defalias foo t/Int)
;compiles to
=> (swap! registry assoc 'user/foo '{:op :Int})
* what about t/pred?
* seems like an underused feature
* but requires types to be collected
* reasonable to expect that users of t/pred will ensure
annotations are loaded when they use it
* but what about core annotations? what will trigger
those to load?
* perhaps that's also the responsibility of the user
* must (:require [clojure.core.typed.ann.base]) explicitly
* (the type checker will automatically trigger collecting clojure.core.typed.ann.base
at type-checking time)
* can we avoid parsing top-level types altogether at runtime? (since they're only
used at compile time)
* put annotation deps in ns metadata?
{:core.typed {:ann [clojure.core.typed.ann.base
clojure.core.typed.ann.core.async]}}
* can we borrow ideas from clojure.spec?
; add to registry
* (t/defalias ::foo t/Int)
=> {::foo t/Int}
* (t/HMap :req [::foo] :opt [::bar])
* how to deal with s/keys :opt auto-check semantics?
* (t/defalias bar t/Int)
=> {user/bar t/Int}
* (t/ann f [t/Int -> t/Int])
=> {user/f [t/Int -> t/Int]}
; use other var annotations as aliases
* (t/ann g f)
=> {user/f [t/Int -> t/Int]
user/g [t/Int -> t/Int]}
; unnamespaced keywords tag unions, fully qualified
; name types (or specs)
* (t/U :left ::left :right ::right)
* not sure why you'd want this yet
* split out things from clojure.core.typed
* leave core type system features in clojure.core.typed:
* inst, defalias, ann, ann-{datatype,record,protocol,many}, declare-datatypes,
override-method, tc-ignore, ann-form, nilable-param, non-nil-return,
declare-names, declare-protocols, ...
* core macro/fn wrappers => clojure.core.typed.ann.base
or
clojure.core.typed.ann.base.rt
* for, doseq, dotimes, atom, ref ...
* type checking api => clojure.core.typed.check
* check-form-info, check-form*, cf, check-ns-info, check-ns
* runtime type inference => clojure.core.typed.infer-ann
* prepare-infer-ns, refresh-runtime-infer, runtime-infer,
spec-infer,
* experimental features => clojure.core.typed.experimental
* infer-unannotated-vars
* :lang featuers => clojure.core.typed.lang
* internal type checking debugging,
=> clojure.core.typed.debug
* print-filterset, print-env,
* special core types => clojure.core.typed.ann.base
* Any, AnyValue, TCError, U, ...
* runtime features => clojure.core.typed.rt
* pred, contract, cast
* Gilardi scenario custom type rules??
* e.g. deftype
# [WIP] Upgrading from 0.5.x to 0.6.x
- core.typed.common
- core.typed.jvm
- core.typed.js
- core.typed.lang.jvm
- core.typed.checker.jvm
- core.typed.analyzer.jvm
- core.typed.annotator.jvm
- core.typed.annotator.jvm
- Audiences
- End users of Clojure type checker
- Description: Full usage of JVM type checker, type collection. Lazily loaded type checker.
- Usage:
(ns ...
(:require [clojure.core.typed :as t]))
(t/ann foo t/Any)
;(t/check-ns)
- Contains:
- `clojure.core.typed.check.jvm`
- `clojure.core.typed.check.jvm.case`
- `clojure.core.typed.check.jvm.method`
- `clojure.core.typed.check.jvm.new`
- `clojure.core.typed.check.jvm.set-bang`
- `clojure.core.typed.check.jvm.constant-type`
- Dependency: [org.clojure/core.typed.check.jvm "version"]
- Transitive:
- `org.clojure/core.typed.check`
- `org.clojure/core.typed.ann.jvm`
- `org.clojure/core.typed.ann`
- End users of ClojureScript type checker
- Description: Full usage of JS type checker, type collection. Lazily loaded type checker.
- `org.clojure/core.typed.check.js`
- Transitive:
- `org.clojure/core.typed.check`
- `org.clojure/core.typed.ann.js`
- `org.clojure/core.typed.ann`
- Author of new checker (e.g. clr)
- `org.clojure/core.typed.check`
- Transitive:
- `org.clojure/core.typed.ann`
- End users of Clojure runtime type inferencer
- `org.clojure/core.typed.infer.jvm`
- Transitive:
- `org.clojure/core.typed.infer`
- `org.clojure/core.typed.analyzer.jvm`
- End users of ClojureScript runtime type inferencer
- `org.clojure/core.typed.infer.js`
- Transitive:
- `org.clojure/core.typed.infer`
- Author of new runtime type inferencer (e.g. clr)
- `org.clojure/core.typed.infer`
- End users of single-pass Clojure analyzer
- `org.clojure/core.typed.analyzer.jvm`
- Transitive:
- `org.clojure/core.typed.analyzer`
- End users of single-pass ClojureScript analyzer
- `org.clojure/core.typed.analyzer.js`
- Transitive:
- `org.clojure/core.typed.analyzer`
- Author of new extension to single-pass analyzer (eg. clr)
- `org.clojure/core.typed.analyzer`
- Library annotators (platform agnostic annotations)
- `org.clojure/core.typed.ann`
- Library annotators (+ JVM specific annotations)
- `org.clojure/core.typed.ann.jvm`
- Library annotators (+ JS specific annotations)
- `org.clojure/core.typed.ann.js`
- New `org.clojure/core.typed.ann` jar for annotation only
- contains `registry`, `ann`, `defalias`, `ann-{datatype,record,protocol,many}`,
`override-method`, `nilable-param`, `non-nil-return`
- delete?
- declare-datatypes, declare-names, declare-protocols,
`org.clojure/core.typed.ann`
- clojure.core.typed.ann
`org.clojure/core.typed.ann.jvm`
- clojure.core.typed.ann.jvm
`org.clojure/core.typed.ann.js`
- clojure.core.typed.ann.js
`org.clojure/core.typed.check`
`org.clojure/core.typed.check.jvm`
`org.clojure/core.typed.check.js`
`org.clojure/core.typed.infer`
`org.clojure/core.typed.check.jvm`
`org.clojure/core.typed.check.js`
`org.clojure/core.typed`
`org.clojure/core.typed.jvm`
`org.clojure/core.typed.js`
`org.clojure/core.typed.analyzer.jvm`
- need home:
- tc-ignore, ann-form,
## (Temporary) clojure.core.typed2 namespace
- `clojure.core.typed/{def,fn,loop,let,defprotocol,defn,atom,ref}` moved to `clojure.core.typed.ann.base`
- `clojure.core.typed/when-let-fail` removed