Summary:
1) Given instrumented function {{map-f}} that is called lazily, e.g. as {{(def ls (map map-f (range)))}}.
2) Also given instrumented function {{varargs-f}}, a varargs function. When you pass a {{LazySeq}} to {{varargs-f}} some or all elements are realized as a consequence of conforming.
3) The problem: when calling {{(apply varargs-f ls)}} some invalid calls to {{map-f}} can go unnoticed.
Repro example:
In the following code {{map-f}} is expected to throw when called with something else than a {{Symbol}}. However the call to {{map-f}} with a {{String}} slips through.
`
(ns repro
(:require
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest]))
(defn map-f [x]
(println "called my-fn with type" (type x))
(println (deref #'clojure.spec.test.alpha/instrument-enabled))
{x 1})
(s/fdef map-f :args (s/cat :x symbol?))
(defn varargs-f [& maps]
true)
(s/fdef varargs-f :args (s/cat :maps (s/* map?)))
(defn repro [& args]
(apply varargs-f (map map-f args)))
(stest/instrument)
(repro 'foo 'bar "baz")
`
Output:
called my-fn with type clojure.lang.Symbol
true
called my-fn with type clojure.lang.Symbol
true
called my-fn with type java.lang.String ;; <--
nil
Cause:
When {{varargs-f}}'s arguments are realized as a result of conforming, some calls to {{map-fn}} are made in the scope of {{with-instrument-disabled}}: https://github.com/clojure/spec.alpha/blob/f23ea614b3cb658cff0044a027cacdd76831edcf/src/main/clojure/clojure/spec/test/alpha.clj#L140
Background:
I ran into this issue when spec'ing {{merge-with}}. Spec'ed fns in some test namespaces didn't throw anymore, because this line in clojure.test has a similar problem with regards to spec as described above: https://github.com/clojure/clojure/blob/28efe345d5e995dc152a0286fb0be81443a0d9ac/src/clj/clojure/test.clj#L775
CLJ-2443.patch contains a fix, but I realize it may not be perfect yet. Therefore I provided CLJ-2443-test.patch that only contains the unit test which can be used to test an alternative solution.