(defn parse-invoke*
[env [f & args :as form]]
(let [enve (assoc env :context :expr)
fexpr (analyze enve f)
argc (count args)
fn-var? (-> fexpr :info :fn-var)
kw? (= 'cljs.core/Keyword (:tag fexpr))
cur-ns (-> env :ns :name)
HO-invoke? (and (boolean *cljs-static-fns*)
(not fn-var?)
(not kw?)
(not (analyzed? f)))
;; function expressions, eg: ((deref m) x) or ((:x m) :a)
bind-f-expr? (and HO-invoke?
(not (symbol? f)))
;; Higher order invokes with (some) argument expressions. Bind the arguments
;; to avoid exponential complexity that is created by the IFn arity check branch.
bind-args? (and HO-invoke?
(not (all-values? args)))]
(when ^boolean fn-var?
(let [{:keys [^boolean variadic max-fixed-arity method-params name ns macro]} (:info fexpr)]
;; don't warn about invalid arity when when compiling a macros namespace
;; that requires itself, as that code is not meant to be executed in the
;; `$macros` ns - António Monteiro
(when (and #?(:cljs (not (and (gstring/endsWith (str cur-ns) "$macros")
(symbol-identical? cur-ns ns)
(true? macro))))
(not (valid-arity? argc method-params))
(or (not variadic)
(and variadic (< argc max-fixed-arity))))
(warning :fn-arity env {:name name :argc argc}))))
(when (and kw? (not (or (== 1 argc) (== 2 argc))))
(warning :fn-arity env {:name (first form) :argc argc}))
(let [deprecated? (-> fexpr :info :deprecated)
no-warn? (-> form meta :deprecation-nowarn)]
(when (and (boolean deprecated?)
(not (boolean no-warn?)))
(warning :fn-deprecated env {:fexpr fexpr})))
(when (some? (-> fexpr :info :type))
(warning :invoke-ctor env {:fexpr fexpr}))
(if (or bind-args? bind-f-expr?)
(let [arg-syms (when bind-args? (take argc (repeatedly gensym)))
f-sym (when bind-f-expr? (gensym "fexpr__"))
bindings (cond-> []
bind-args? (into (interleave arg-syms args))
bind-f-expr? (conj f-sym (analyzed f)))]
(analyze env
`(let [~@bindings]
(~(analyzed (if bind-f-expr? f-sym f))
~@(if bind-args? arg-syms args)))))
(let [ana-expr #(analyze enve %)
argexprs (map ana-expr args)]
{:env env :op :invoke :form form :f fexpr :args (vec argexprs)
:children (into [fexpr] argexprs)}))))