clojure.core.typed

This namespace contains typed wrapper macros, type aliases
and functions for type checking Clojure code. check-ns is the interface
for checking namespaces, cf for checking individual forms.

ann

macro

(ann varsym typesyn)
Annotate varsym with type. If unqualified, qualify in the current namespace.
If varsym has metadata {:no-check true}, ignore definitions of varsym 
while type checking. Supports namespace aliases and fully qualified namespaces
to annotate vars in other namespaces.

eg. ; annotate the var foo in this namespace
    (ann foo [Number -> Number])

    ; annotate a var in another namespace
    (ann another.ns/bar [-> nil])
 
    ; don't check this var
    (ann ^:no-check foobar [Integer -> String])

ann-datatype

macro

(ann-datatype & args)
Annotate datatype Class name dname with expected fields.
If unqualified, qualify in the current namespace.
Takes an optional type variable binder before the name.

Fields must be specified in the same order as presented 
in deftype, with exactly the same field names.

Also annotates datatype factories and constructors.

Binder is a vector of specs. Each spec is a vector
with the variable name as the first entry, followed by
keyword arguments:
- :variance (mandatory)
  The declared variance of the type variable. Possible
  values are :covariant, :contravariant and :invariant.
- :< (optional)
  The upper type bound of the type variable. Defaults to
  Any, or the most general type of the same rank as the
  lower bound.
- :> (optional)
  The lower type bound of the type variable. Defaults to
  Nothing, or the least general type of the same rank as the
  upper bound.

eg. ; a datatype in the current namespace
    (ann-datatype MyDatatype [a :- Number,
                              b :- Long])

    ; a datatype in another namespace
    (ann-datatype another.ns.TheirDatatype
                  [str :- String,
                   vec :- (Vec Number)])

    ; a datatype, polymorphic in a
    (ann-datatype [[a :variance :covariant]]
                  MyPolyDatatype
                  [str :- String,
                   vec :- (Vec Number)
                   ply :- (Set a)])

ann-form

macro

(ann-form form ty)
Annotate a form with an expected type.

ann-interface

macro

(ann-interface & args)
Annotate a possibly polymorphic interface (created with definterface) with method types.

Note: Unlike ann-protocol, omit the target ('this') argument in the method signatures.

eg. (ann-interface IFoo
      bar
      (Fn [-> Any]
          [Number Symbol -> Any])
      baz
      [Number -> Number])
    (definterface IFoo
      (bar [] [n s])
      (baz [n]))

    ; polymorphic protocol
    ; x is scoped in the methods
    (ann-protocol [[x :variance :covariant]]
      IFooPoly
      bar
      (Fn [-> Any]
          [Number Symbol -> Any])
      baz
      [Number -> Number])
    (definterface IFooPoly
      (bar [] [n s])
      (baz [n]))

ann-many

macro

(ann-many t & vs)
Annotate several vars with type t.

eg. (ann-many FakeSearch
              web1 web2 image1 image2 video1 video2)

ann-protocol

macro

(ann-protocol & args)
Annotate a possibly polymorphic protocol var with method types.

eg. (ann-protocol IFoo
      bar
      (IFn [IFoo -> Any]
           [IFoo Number Symbol -> Any])
      baz
      [IFoo Number -> Number])
    (t/tc-ignore
      (defprotocol IFoo
        (bar [this] [this n s])
        (baz [this n])))

    ; polymorphic protocol
    ; x is scoped in the methods
    (ann-protocol [[x :variance :covariant]]
      IFooPoly
      bar
      (IFn [(IFooPoly x) -> Any]
           [(IFooPoly x) Number Symbol -> Any])
      baz
      [(IFooPoly x) Number -> Number])
    (t/tc-ignore
      (defprotocol IFooPoly
        (bar [this] [this n s])
        (baz [this n])))

ann-record

macro

(ann-record & args)
Annotate record Class name dname with expected fields.
If unqualified, qualify in the current namespace.
Takes an optional type variable binder before the name.

Fields must be specified in the same order as presented 
in defrecord, with exactly the same field names.

Also annotates record factories and constructors.

Binder is a vector of specs. Each spec is a vector
with the variable name as the first entry, followed by
keyword arguments:
- :variance (mandatory)
  The declared variance of the type variable. Possible
  values are :covariant, :contravariant and :invariant.
- :< (optional)
  The upper type bound of the type variable. Defaults to
  Any, or the most general type of the same rank as the
  lower bound.
- :> (optional)
  The lower type bound of the type variable. Defaults to
  Nothing, or the least general type of the same rank as the
  upper bound.

eg. ; a record in the current namespace
    (ann-record MyRecord [a :- Number,
                          b :- Long])

    ; a record in another namespace
    (ann-record another.ns.TheirRecord
                [str :- String,
                 vec :- (Vec Number)])

    ; a record, polymorphic in a
    (ann-record [[a :variance :covariant]]
                MyPolyRecord
                [str :- String,
                 vec :- (Vec Number)
                 ply :- (Set a)])

atom

macro

(atom & args)
Like atom, but with optional type annotations.

Same as (atom (ann-form init t) args*)

eg. (atom 1) : (Atom (Value 1))
    (atom :- Num, 1) : (Atom Num)

cast

macro

(cast t x)(cast t x opt)
Cast a value to a type. Returns a new value that conforms
to the given type, otherwise throws an error with blame.

eg. (cast Int 1)
    ;=> 1

    (cast Int nil)
    ; Fail, <blame positive ...>

    ((cast [Int -> Int] identity)
     1)
    ;=> 1

    ((cast [Int -> Int] identity)
     nil)
    ; Fail, <blame negative ...>

    (cast [Int -> Int] nil)
    ; Fail, <blame positive ...>

(defalias Options
  (HMap :optional {:positive (U Sym Str),
                   :negative (U Sym Str)
                   :file (U Str nil)
                   :line (U Int nil)
                   :column (U Int nil)}))

(IFn [Contract Any -> Any]
     [Contract Any Options -> Any])

Options:
- :positive   positive blame, (U Sym Str)
- :negative   negative blame, (U Sym Str)
- :file       file name where contract is checked, (U Str nil)
- :line       line number where contract is checked, (U Int nil)
- :column     column number where contract is checked, (U Int nil)

cf

macro

(cf form)(cf form expected)
Takes a form and an optional expected type and
returns a human-readable inferred type for that form.
Throws an exception if type checking fails.

Do not use cf inside a typed namespace. cf is intended to be
used at the REPL or within a unit test. Note that testing for
truthiness is not sufficient to unit test a call to cf, as nil
and false are valid type syntax.

cf preserves annotations from previous calls to check-ns or cf,
and keeps any new ones collected during a cf. This is useful for
debugging and experimentation. cf may be less strict than check-ns
with type checker warnings.

eg. (cf 1) 
    ;=> Long

    (cf #(inc %) [Number -> Number])
    ;=> [Number -> Number]

check-form*

(check-form* form)(check-form* form expected)(check-form* form expected type-provided? & opt)
Function that takes a form and optional expected type syntax and
type checks the form. If expected is provided, type-provided?
must be true.

Takes same options as check-form-info, except 2nd argument is :expected,
3rd argument is :type-provided?, and subsequent keys in opt will be merged over
them.

check-form-info

(check-form-info form & {:as opt})
Function that type checks a form and returns a map of results from type checking the
form.

Options
- :expected        Type syntax representing the expected type for this form
                   type-provided? option must be true to utilise the type.
- :type-provided?  If true, use the expected type to check the form.
- :file-mapping    If true, return map provides entry :file-mapping, a hash-map
                   of (Map '{:line Int :column Int :file Str} Str).
- :checked-ast     Returns the entire AST for the given form as the :checked-ast entry,
                   annotated with the static types inferred after checking.
                   If a fatal error occurs, mapped to nil.
- :beta-limit      A natural integer which denotes the maximum number of beta reductions
                   the type system can perform on a single top-level form (post Gilardi-scenario).
- :check-config    Configuration map for the type checker. (See corresponding option for `check-ns`)

Default return map
- :ret             TCResult inferred for the current form
- :out-form        The macroexpanded result of type-checking, if successful. 
- :result          The evaluated result of :out-form, if any.
- :ex              If an exception was thrown during evaluation, this key will be present
                   with the exception as the value.
DEPRECATED
- :delayed-errors  A sequence of delayed errors (ex-info instances)
- :profile         Use Timbre to profile the type checker. Timbre must be
                   added as a dependency. Must use the "slim" JAR.

check-ns

(check-ns)(check-ns ns-or-syms & {:as opt})
Type check a namespace/s (a symbol or Namespace, or collection).
If not provided default to current namespace.
Returns a true value if type checking is successful, otherwise
throws an Exception.

Do not use check-ns within a checked namespace.
It is intended to be used at the REPL or within a unit test.
Suggested idiom for clojure.test: (is (check-ns 'your.ns))

Keyword arguments:
- :trace         If true, print some basic tracing of the type checker
                 Default: nil
- :check-config   Configuration map for the type checker.
  - :check-ns-dep  If `:recheck`, always check dependencies.
                   If `:never`, ns dependencies are ignored.
                   #{:recheck :never}
                   Default: :recheck
  - :unannotated-def   If `:unchecked`, unannotated `def`s are ignored
                       and their type is not recorded.
                       If `:infer`, unannotated `def`s are inferred by their
                       root binding and the type is recorded in the type environment.
                       #{:unchecked :infer}
                       Also applies to `defmethod`s on unannotated `defmulti`s.
                       Default: :infer
  - :unannotated-var   If `:unchecked`, unannotated vars are given an *unsound*
                       annotation that is used to statically infer its type
                       based on usages/definition (see `infer-unannotated-vars`).
                       If `:any`, usages of unannotated vars are given type `Any` (sound).
                       If `:error`, unannotated vars are a type error (sound).
                       #{:unchecked :any :error}
                       Default: :error
  - :unannotated-arg   (Not Yet Implemented)
                       If `:unchecked`, unannotated fn arguments are given an *unsound*
                       annotation that is used to statically infer its argument types
                       based on definition.
                       If `:any`, unannotated fn arguments are give type `Any` (sound).
                       #{:unchecked :any}
                       Default: :any

Removed:
- :profile       If true, use Timbre to profile the type checker. Timbre must be
                 added as a dependency. Must use the "slim" JAR.
                 Default: nil


If providing keyword arguments, the namespace to check must be provided
as the first argument.

Bind clojure.core.typed.util-vars/*verbose-types* to true to print fully qualified types.
Bind clojure.core.typed.util-vars/*verbose-forms* to print full forms in error messages.

eg. (check-ns 'myns.typed)
    ;=> :ok
   
    ; implicitly check current namespace
    (check-ns)
    ;=> :ok

check-ns-info

(check-ns-info)(check-ns-info ns-or-syms & opt)
Same as check-ns, but returns a map of results from type checking the
namespace.

Options
- :type-provided?  If true, use the expected type to check the form
- :profile         Use Timbre to profile the type checker. Timbre must be
added as a dependency. Must use the "slim" JAR.
- :file-mapping    If true, return map provides entry :file-mapping, a hash-map
of (Map '{:line Int :column Int :file Str} Str).
- :check-deps      If true, recursively type check namespace dependencies.
Default: true

Default return map
- :delayed-errors  A sequence of delayed errors (ex-info instances)

check-ns2

(check-ns2)(check-ns2 ns-or-syms & {:as opt})

declare-alias-kind

macro

(declare-alias-kind sym ty)
Declare a kind for an alias, similar to declare but on the kind level.

declare-datatypes

macro

(declare-datatypes & syms)
Declare datatypes, similar to declare but on the type level.

declare-names

macro

(declare-names & syms)
Declare names, similar to declare but on the type level.

declare-protocols

macro

(declare-protocols & syms)
Declare protocols, similar to declare but on the type level.

def

macro

(def name & fdecl)
Like clojure.core/def with optional type annotations. Registers
annotations like t/ann.

NB: in Clojure it not useful refer a macro called `def` as it is a
special form. Use an alias prefix (eg., `t/def`).

eg. ;same as clojure.core/def
    (def vname 1)
    
    ;with Number `ann`
    (def vname :- Number 1)

    ;doc
    (def vname
      "Docstring"
      :- Long
      1)

defalias

macro

(defalias sym doc-str t)(defalias sym t)
Define a recursive type alias on a qualified symbol. Takes an optional doc-string as a second
argument.

Updates the corresponding var with documentation.

eg. (defalias MyAlias
      "Here is my alias"
      (U nil String))

    ;; recursive alias
    (defalias Expr
      (U '{:op ':if :test Expr :then Expr :else Expr}
         '{:op ':const :val Any}))

default-check-config

(default-check-config)

defn

macro

(defn & args)
Like defn, but registers annotation with t/ann.

eg. (defn fname [a :- Number, b :- (U Symbol nil)] :- Integer ...)

;annotate return
(defn fname [a :- String] :- String ...)

;multi-arity
(defn fname 
  ([a :- String] :- String ...)
  ([a :- String, b :- Number] :- Long ...))

;polymorphic function
(defn :forall [x y]
  fname 
  ([a :- x] :- (Coll y) ...)
  ([a :- Str, b :- y] :- y ...))

defprotocol

macro

(defprotocol & body)
Like defprotocol, but with optional type annotations.

Omitted annotations default to Any. The first argument
of a protocol cannot be annotated.

Add a binder before the protocol name to define a polymorphic
protocol. A binder before the method name defines a polymorphic
method, however a method binder must not shadow type variables
introduced by a protocol binder.

Return types for each method arity can be annotated.

Unlike clojure.core/defprotocol, successive methods can
have the same arity. Semantically, providing multiple successive
methods of the same arity is the same as just providing the left-most
method. However the types for these methods will be accumulated into
a Fn type.

eg. ;annotate single method
(defprotocol MyProtocol
  (a [this a :- Integer] :- Number))

;polymorphic protocol
(defprotocol [[x :variance :covariant]]
  MyProtocol
  (a [this a :- Integer] :- Number))

;multiple types for the same method
(defprotocol [[x :variance :covariant]]
  MyProtocol
  (a [this a :- Integer] :- Integer
     [this a :- Long] :- Long
     [this a :- Number] :- Number))

;polymorphic method+protocol
(defprotocol [[x :variance :covariant]]
  MyProtocol
  ([y] a [this a :- x, b :- y] :- y))

dotimes

macro

(dotimes bindings & body)
Like clojure.core/dotimes, but with optional annotations.

If annotation for binding is omitted, defaults to Int.

eg. (dotimes [_ 100]
      (println "like normal"))

    (dotimes [x :- Num, 100.123]
      (println "like normal" x))

envs

(envs)
Returns a map of type environments, according to the current state of the
type checker.

Output map:
- :vars      map from var symbols to their verbosely printed types
- :aliases   map from alias var symbols (made with defalias) to their verbosely printed types
- :special-types  a set of Vars that are special to the type checker (like Any, U, I)

fn

macro

(fn & forms)
Like clojure.core/fn, but with optional annotations.

eg. ;these forms are equivalent
    (fn [a] b)
    (fn [a :- Any] b)
    (fn [a :- Any] :- Any b)
    (fn [a] :- Any b)

    ;annotate return
    (fn [a :- String] :- String body)

    ;named fn
    (fn fname [a :- String] :- String body)

    ;rest parameter
    (fn [a :- String & b :- Number *] body)

    ;dotted rest parameter
    (fn [a :- String & b :- Number ... x] body)

    ;multi-arity
    (fn fname 
      ([a :- String] :- String ...)
      ([a :- String, b :- Number] :- String ...))

    ; polymorphic binder
    (fn :forall [x y z]
      fname 
      ([a :- String] :- String ...)
      ([a :- String, b :- Number] :- String ...))

infer-unannotated-vars

(infer-unannotated-vars)(infer-unannotated-vars nsym-or-ns)
EXPERIMENTAL

Return a vector of potential var annotations in the given
namespace, or the current namespace.

To enable for the current namespace, add the :infer-vars
:experimental feature to the ns metadata like so:

  (ns infer-me
    {:lang :core.typed
     :core.typed {:experimental #{:infer-vars
                                  :infer-locals}}}
    ...)

Then run check-ns like usual, and infer-unannotated-vars
will return the inferred vars without annotations.

(t/infer-unannotated-vars)
=> [(t/ann u/bar t/Int)
    (t/ann u/foo (t/U [t/Any -> t/Any] Int))]
                              

inst

macro

(inst inst-of & types)
Instantiate a polymorphic type with a number of types.

eg. (inst foo-fn t1 t2 t3 ...)

inst-ctor

macro

(inst-ctor inst-of & types)
Instantiate a call to a constructor with a number of types.
First argument must be an immediate call to a constructor.
Returns exactly the instantiatee (the first argument).

eg. (inst-ctor (PolyCtor. a b c)
               t1 t2 ...)

install

(install)(install features)
Install the :core.typed :lang. Takes an optional set of features
to install, defaults to `:all`, which is equivalent to the set of
all features.

Features:
  - :load    Installs typed `load` over `clojure.core/load`, which type checks files
             on the presence of a {:lang :core.typed} metadata entry in the `ns` form.
             The metadata must be inserted in the actual `ns` form saved to disk,
             as it is read directly from the file instead of the current Namespace
             metadata.
  - :eval    Installs typed `eval` over `clojure.core/eval`.
             If `(= :core.typed (:lang (meta *ns*)))` is true, the form will be implicitly
             type checked. The syntax save to disk is ignored however.

eg. (install)            ; installs `load` and `eval`
eg. (install :all)       ; installs `load` and `eval`
eg. (install #{:eval})   ; installs `eval`
eg. (install #{:load})   ; installs `load`

into-array>

macro

(into-array> cljt coll)(into-array> javat cljt coll)(into-array> into-array-syn javat cljt coll)
Make a Java array with Java class javat and Typed Clojure type
cljt. Resulting array will be of type javat, but elements of coll must be under
cljt. cljt should be a subtype of javat (the same or more specific).

*Temporary hack*
into-array-syn is exactly the syntax to put as the first argument to into-array.
Calling resolve on this syntax should give the correct class.

let

macro

(let bvec & forms)
Like clojure.core/let but supports optional type annotations.

eg. (let [a :- Type, b
          a2 1.2]
      body)

letfn>

macro

(letfn> fn-specs-and-annotations & body)
Like letfn, but each function spec must be annotated.

eg. (letfn> [a :- [Number -> Number]
             (a [b] 2)

             c :- [Symbol -> nil]
             (c [s] nil)]
      ...)

load-if-needed

(load-if-needed)
Load and initialize all of core.typed if not already

loop

macro

(loop bindings & exprs)
Like clojure.core/loop, and supports optional type annotations.
Arguments default to a generalised type based on the initial value.

eg. (loop [a :- Number 1
           b :- (U nil Number) nil]
      ...)

method-type

(method-type mname)
Given a method symbol, print the core.typed types assigned to it.
Intended for use at the REPL.

nilable-param

macro

(nilable-param msym mmap)
Override which parameters in qualified method msym may accept
nilable values. If the parameter is a parameterised type or
an Array, this also declares the parameterised types and the Array type as nilable.

mmap is a map mapping arity parameter number to a set of parameter
positions (integers). If the map contains the key :all then this overrides
other entries. The key can also be :all, which declares all parameters nilable.

non-nil-return

macro

(non-nil-return msym arities)
Override the return type of fully qualified method msym to be non-nil.
Takes a set of relevant arities,
represented by the number of parameters it takes (rest parameter counts as one),
or :all which overrides all arities.

eg. ; must use full class name
    (non-nil-return java.lang.Class/getDeclaredMethod :all)

override-constructor

macro

(override-constructor ctorsym typesyn)
Override all constructors for Class ctorsym with type.

override-method

macro

(override-method methodsym typesyn)
Override type for qualified method methodsym.

methodsym identifies the method to override and should be a
namespace-qualified symbol in the form <class>/<method-name>.
The class name needs to be fully qualified.

typesyn uses the same annotation syntax as functions.

Use non-nil-return instead of override-method if you want to
declare that a method can never return nil.

Example:

  (override-method java.util.Properties/stringPropertyNames
                   [-> (java.util.Set String)])

This overrides the return type of method stringPropertyNames
of class java.util.Properties to be (java.util.Set String).

pred

macro

(pred t)
Generate a flat (runtime) predicate for type that returns true if the
argument is a subtype of the type, otherwise false.

The current type variable and dotted type variable scope is cleared before parsing.

eg. ((pred Number) 1)
    ;=> true

prepare-infer-ns

(prepare-infer-ns & {:keys [ns strategy], :as config, :or {strategy :compile, ns *ns*}})
Instruments the current namespace to prepare for runtime type
or spec inference.

Optional keys:
  :ns     The namespace to infer types for. (Symbol/Namespace)
          Default: *ns*
  :strategy  Choose which inference preparation strategy to use.
             - :compile      recompile the namespace and wrap at compilation-time.
                             Supports local annotation inference. Source is analyzed
                             via core.typed's custom analyzer.
             - :instrument   wrap top-level vars without recompilation.
                             No support for local annotations, but the default
                             Clojure analyzer is used.
             Default: :compile
  :track-strategy  Choose which track strategy to use.
                   - :lazy    wrap hash maps and possibly other data structures, and
                              lazily track values as they are used.
                   - :eager   eagerly walk over all values, a la clojure.spec checking.
                   Default: :lazy

print-env

(print-env debug-str)
During type checking, print the type environment to *out*,
preceeded by literal string debug-str.

print-filterset

(print-filterset debug-string frm)
During type checking, print the filter set attached to form, 
preceeded by literal string debug-string.
Returns nil.

eg. (let [s (seq (get-a-seqable))]
      (print-filterset "Here now" s))

ref

macro

(ref & args)
Like ref, but with optional type annotations.

Same as (ref (ann-form init t) args*)

eg. (ref 1) : (Ref (Value 1))
    (ref :- Num, 1) : (Ref Num)

refresh-runtime-infer

(refresh-runtime-infer)
Clean the current state of runtime inference.
Will forget the results of any tests on instrumented code.

register!

(register!)
Internal -- Do not use

reset-caches

(reset-caches)
Reset internal type caches.

runtime-infer

(runtime-infer & kws)
Infer and insert annotations for a given namespace.

There are two ways to instrument your namespace.

Call `prepare-infer-ns` function on the namespace
of your choosing.

Alternatively, use the :runtime-infer
feature in your namespace metadata. Note: core.typed
must be installed via `clojure.core.typed/install`.

eg. (ns my-ns
      {:lang :core.typed
       :core.typed {:features #{:runtime-infer}}}
      (:require [clojure.core.typed :as t]))

After your namespace is instrumented, run your tests
and/or exercise the functions in your namespace.

Then call `runtime-infer` to populate the namespace's
corresponding file with these generated annotations.

Optional keys:
  :ns     The namespace to infer types for. (Symbol/Namespace)
          Default: *ns*
  :fuel   Number of iterations to perform in inference algorithm
          (integer)
          Default: nil (don't restrict iterations)
  :debug  Perform print debugging. (:all/:iterations/nil)
          Default: nil
  :track-depth   Maximum nesting depth data will be tracked.
                 Default: nil (don't restrict nestings)
  :track-count   Maximum number of elements of a single collection
                 will be tracked.
                 Default: nil (don't restrict elements)
  :root-results  Maximum number of inference results collected per top-level
                 root form, from the perspective of the tracker (eg. vars, local functions).
                 Default: nil (don't restrict)
  :preserve-unknown  If true, output the symbol `?` where inference was cut off
                     or never reached.
                     Default: nil (convert to unknown to `clojure.core.typed/Any`)
  :out-dir       A classpath-relative directory (string) to which to dump changes to files,
                 instead of modifying the original file.
                 Default: nil (modify original file)
  :no-squash-vertically     If true, disable the `squash-vertically` pass.
                            Default: nil

eg. (runtime-infer) ; infer for *ns*

    (runtime-infer :ns 'my-ns) ; infer for my-ns

    (runtime-infer :fuel 0) ; iterations in type inference algorithm
                            ; (higher = smaller types + more recursive)

    (runtime-infer :debug :iterations) ; enable iteration debugging

spec-infer

(spec-infer & kws)
Infer and insert specs for a given namespace.

There are two ways to instrument your namespace.

Call `prepare-infer-ns` function on the namespace
of your choosing.

Alternatively, use the :runtime-infer
feature in your namespace metadata. Note: core.typed
must be installed via `clojure.core.typed/install`.

eg. (ns my-ns
      {:lang :core.typed
       :core.typed {:features #{:runtime-infer}}}
      (:require [clojure.core.typed :as t]))

After your namespace is instrumented, run your tests
and/or exercise the functions in your namespace.

Then call `spec-infer` to populate the namespace's
corresponding file with these generated specs.

Optional keys:
  :ns     The namespace to infer specs for. (Symbol/Namespace)
          Default: *ns*
  :fuel   Number of iterations to perform in inference algorithm
          (integer)
          Default: nil (don't restrict iterations)
  :debug  Perform print debugging. (:all/:iterations/nil)
          Default: nil
  :track-depth   Maximum nesting depth data will be tracked.
                 Default: nil (don't restrict nestings)
  :track-count   Maximum number of elements of a single collection
                 will be tracked.
                 Default: nil (don't restrict elements)
  :root-results  Maximum number of inference results collected per top-level
                 root form, from the perspective of the tracker (eg. vars, local functions).
                 Default: nil (don't restrict)
  :preserve-unknown  If true, output the symbol `?` where inference was cut off
                     or never reached.
                     Default: nil (convert to unknown to `clojure.core/any?`)
  :higher-order-fspec   If true, generate higher-order fspecs.
                        Default: false
  :out-dir       A classpath-relative directory (string) to which to dump changes to files,
                 instead of modifying the original file.
                 Default: nil (modify original file)
  :no-squash-vertically     If true, disable the `squash-vertically` pass.
                            Default: nil
  :spec-macros   If true, output specs for macros.
                 Default: nil (elide macro specs)

eg. (spec-infer) ; infer for *ns*

    (spec-infer :ns 'my-ns) ; infer for my-ns

    (spec-infer :fuel 0) ; iterations in spec inference algorithm
                         ; (higher = smaller specs + more recursive)

    (spec-infer :debug :iterations) ; enable iteration debugging

statistics

(statistics nsyms)
Takes a collection of namespace symbols and returns a map mapping the namespace
symbols to a map of data

tc-ignore

macro

(tc-ignore & body)
Ignore forms in body during type checking

typed-deps

macro

(typed-deps & args)
Declare namespaces which should be checked before the current namespace.
Accepts any number of symbols. Only has effect via check-ns.

eg. (typed-deps clojure.core.typed.holes
                myns.types)

untyped-var

macro

(untyped-var varsym typesyn)
Check a given var has the specified type at runtime.

var-coverage

(var-coverage)(var-coverage nsyms-or-nsym)
Summarises annotated var coverage statistics to *out*
for namespaces nsyms, a collection of symbols or a symbol/namespace.
Defaults to the current namespace if no argument provided.

var>

macro

(var> sym)
Like var, but resolves at runtime like ns-resolve and is understood by
the type checker. sym must be fully qualified (without aliases).

eg. (var> clojure.core/+)

warn-on-unannotated-vars

macro

(warn-on-unannotated-vars)
Allow unannotated vars in the current namespace. 

Emits a warning instead of a type error when checking
a def without a corresponding expected type.

Disables automatic inference of `def` expressions.

eg. (warn-on-unannotated-vars)

when-let-fail

macro

(when-let-fail b & body)
Like when-let, but fails if the binding yields a false value.