请在2024年Clojure状态调查!中分享您的想法。

欢迎!请查看关于页面以获取更多关于如何操作的信息。

0
Spec
当函数发生配置失败时,explain-data中会包含" caller"信息。但是,如果为宏发生配置失败,则该信息将缺失。

这条评论使我相信预期行为应该是让explain-data包含这些信息,以供第三方错误打印显示。

在下面的复现中,我设置了一个自定义打印机来仅捕获原始explain-data(它不是一个有用的打印机,只是用来显示发生的情况)

复现


  (require '[clojure.spec.alpha :as s])
  (require '[clojure.spec.test.alpha :as st])
  (require '[clojure.specs.alpha :as s])


  (s/fdef my-fn
          :args (s/cat :x int?))
  (defn my-fn [x]
    x)

  (s/fdef my-macro
          :args (s/cat :x int?))
  (defmacro my-macro [x]
    x)

  (st/instrument)
  (def !ed (atom nil))
  (set! s/*explain-out* (fn [ed]
                          (reset! !ed ed)))
  (my-fn "")
  @!ed
  ;; {:clojure.spec.alpha/problems [{:path [:args :x], :pred clojure.core/int?, :val "", :via [], :in [0]}], :clojure.spec.alpha/spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x72029b0e "clojure.spec.alpha$regex_spec_impl$reify__2436@72029b0e"], :clojure.spec.alpha/value (""), :clojure.spec.alpha/args (""), :clojure.spec.alpha/failure :instrument, :clojure.spec.test.alpha/caller {:file "form-init8333540581183382896.clj", :line 548, :var-scope expound.alpha/eval27394}}

  ;; ^--- 注意这里有一个关于 :clojure.spec.test.alpha/caller 的条目

  (my-macro "")
  @!ed

  ;; #:clojure.spec.alpha{:problems [{:path [:args :x], :pred clojure.core/int?, :val "", :via [], :in [0]}], :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x479a6a73 "clojure.spec.alpha$regex_spec_impl$reify__2436@479a6a73"], :value (""), :args ("")}

  ;; ^--- 没有caller信息

10 个答案

0

评论者:alexmiller

你不能对宏进行配置,所以该报告的项目不适用于目前的描述。但我想你可能指的是宏扩展期间的规格检查。

在宏检查用例中,调用者信息为编译器所知,并包含在包装器 CompilerException 中。我认为这些信息可以从编译器传递给 s/macroexpand-check,并且可能会产生与被测函数调用类似的结果。

0
by

评论者:bbrinck

啊,你说得对,感谢澄清。

如果添加了调用者信息,那么为在宏展开期间失败的规范添加特定的 :clojure.spec.alpha/failure 值也将非常有用。这将允许第三方工具在宏展开失败时显示特定类型的错误消息。

0
by

评论者:bbrinck

此外,访问宏名称的符号将有助于错误报告。

0
by

评论者:sohta

在我看来,对于仪器失效和宏规范错误,应在 CLJ-2218 中之前提出的建议中包含函数(或宏)的 fspec。

一个 {{fspec}} 在其元数据中包含有关规范函数的一些有用信息(例如,ns-qualified 名称符号和行号等),因此规范错误报告器可以使用它们为仪器失效和宏规范错误提供更丰富和更精确的错误消息,并保持一致性。

0
by

评论者:alexmiller

在 CLJ-2373 之后,规范宏失败的计算者信息将通过包装器 CompilerException 传达(就像其他编译器和宏展开错误一样)。应当考虑是否已将此问题真正解决。

0
by

评论者:bbrinck

我很高兴听到这将被包含在 CompilerException 中,但我认为将其包含在 spec explain-data 中仍然有用。

当打印规范错误时,如果能以类似格式打印宏展开规范错误和工具错误会更好(如果用户选择了自定义规范打印机)。查找宏展开错误和工具错误的调用者信息可能会产生干扰。

此外,规范打印机可以选择使用这个调用者信息做一些新颖的事情,比如在输出中添加颜色或者打印实际代码而不是行号。如果所有这些信息都可以供规范打印机自定义,那就更好了。

0

评论者:alexmiller

问题在于,当创建宏规范错误时,我们没有任何方法知道正确的调用者信息。那时的调用栈是编译器宏展开,而不是调用代码。宏展开知道这个上下文,这就是它添加编译器异常的原因(这就是编译器异常的主要目的)。

我认为要改变这一点,我们需要在规范检查中通过带外方式传达这个信息。好吧,也许这是可能的。我会再看看。

0

评论者:bbrinck

在最近的错误消息工作中(非常好的工作!),符号似乎可用,但它目前没有传递到“explain-out”函数:[链接](https://github.com/clojure/clojure/blob/b182982007df934394f0bc68b3a238ca9f200dd1/src/clj/clojure/main.clj#L268-L279)

有没有可能“assoc”这个信息到传递给“spec/explain-out”的“spec”?这将允许自定义打印机引用规范名称,这将非常有用。

另一种方法是为用户提供在REPL中设置自定义错误处理程序,但这比设置第三个方的“explain-out”实现要复杂得多

0
_由:alexmiller_ 发表评论

我不想把它限制为只能由clojure主REPL使用的功能 — 如果在其它REPL中使用情况会更好,最好在构建时完成。我现在对如何做到这一点有了更好的掌握,但不知道是否为1.10版本做此修改已经太迟。
0
参考:https://clojure.atlassian.net/browse/CLJ-2271(由bbrinck报告)
...