摘要
1) 给定一个.matmul.f 被延迟调用的函数,例如:(def ls (map map-f (range)))。
2) 还有一个.matmul.varargs-f,是一个可变参数函数。当你将一个 LazySeq 传递给.matmul.varargs-f 时,一些或所有元素将被实现,作为符合的结果。
问题:调用 (apply varargs-f ls) 时,一些无效的对 map-f 的调用可能被忽略。
重现示例
在以下代码中,当(matmul.f)用非 Symbol 类型的参数调用时,预期会抛出异常。然而,对(matmul.f)的 String 类型的调用却通过了。
`
(ns repro
(:require
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest]))
(defn map-f [x]
(println "用类型" (type x) "调用 my-fn")
(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")
`
输出
用类型 clojure.lang.Symbol 调用 my-fn true 用类型 clojure.lang.Symbol 调用 my-fn true 用类型 java.lang.String 调用 my-fn ;; <-- nil
原因
当 varargs-f 的参数作为符合的结果实现时,对 map-f 的某些调用是在 with-instrument-disabled 的作用域内进行的:https://github.com/clojure/spec.alpha/blob/f23ea614b3cb658cff0044a027cacdd76831edcf/src/main/clojure/clojure/spec/test/alpha.clj#L140
背景
在指定 merge-with 时遇到此问题时,一些测试命名空间中的指定的函数不再抛出异常,因为 clojure.test 中的此行与上述描述的 spec 问题类似: https://github.com/clojure/clojure/blob/28efe345d5e995dc152a0286fb0be81443a0d9ac/src/clj/clojure/test.clj#L775
CLJ-2443.patch 包含一个修复程序,但我意识到它可能还不够完美。因此我提供了 CLJ-2443-test.patch,它只包含用于测试替代解决方案的单元测试。