2024 Clojure 状态调查!中分享您的观点。

欢迎!请在关于页面查看更多关于该功能的信息。

0
Spec

摘要

1) 假设有一个名为 {{map-f}} 的仪器化函数,它是通过懒调用调用的,例如 {{(def ls (map map-f (range)))}}。
2) 还有一个名为 {{varargs-f}} 的可变参数函数。当你将一个 {{LazySeq}} 传递给 {{varargs-f}} 时,一些或所有元素会因为适配而变为实际的。
3) 问题:当调用 {{(apply varargs-f ls)}} 时,一些对 {{map-f}} 的无效调用可能会被忽视。

复现示例

在以下代码中,{{map-f}} 应该在用除异常类型以外的类型调用时抛出异常。然而,对于 {{String}} 调用 {{map-f}} 的调用却穿过了。

`
(ns repro
(:require
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest]))

(defn map-f [x]
(println "调用 my-fn 的类型" (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")
`

输出

调用 my-fn 的类型 clojure.lang.Symbol true 调用 my-fn 的类型 clojure.lang.Symbol true 调用 my-fn 的类型 java.lang.String ;;<-- nil

原因

当 {{varargs-f}} 的参数因为适配而实际化时,一些对 {{map-fn}} 的调用是在 {{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,它只包含了一个单元测试,可以用来测试替代方案。

4 个回答

0

评论由:borkdude发布

CLJ-2443.patch通过在外部范围内形成Cons类型参数来解决这个问题。
已提供测试。此补丁与推测性(https://github.com/slipset/speculative)兼容。

0

评论由:borkdude发布

CLJ-2443-test只包含测试,不包括实际修复。

0

评论由:borkdude发布

使用CLJ-2443-test.patch更新描述

0
参考:https://clojure.atlassian.net/browse/CLJ-2443(由borkdude报告)
...