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

欢迎!请参阅 关于 页面以获取更多关于如何使用本站的信息。

0
Spec
当一个函数的宏操作器失效时,explain-data 会包含 "调用者" 信息。然而,如果宏操作器失效,则此信息会丢失。

这条评论让我相信,预期行为是 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 ("")}

          ^--- 没有调用者信息

10 答案

0

评论由: alexmiller 发布

无法对宏进行 Instrument,因此关于此票的说明是不合逻辑的。但我认为你的意思是宏扩展期间的规格检查。

在宏检查的情况下,调用者信息由编译器知道,并包含在包装后的 CompilerException 中。我想这个信息可以被传递到 s/macroexpand-check,并且可能与 Instrumented 函数调用产生类似的结果。

0

评论者:bbrinck

啊,你是对的,感谢澄清。

如果在调用者信息中添加了特定于 :clojure.spec.alpha/failure 的值,在宏扩展期间失败的规格将会非常有用。这将允许第三方工具在宏扩展失败时展示特定类型的错误信息。

0

评论者:bbrinck

此外,访问宏名称的符号也会对错误报告有所帮助。

0

评论者:sohta

我认为,对于 Instrument 失败和宏规范错误,应该包含函数(或宏)的 fspec,正如我在 CLJ-2218 中之前建议的那样。

一个 {{fspec}} 有一些有用的信息(例如指定函数的 ns-qualified 名称符号和行号等),这些都在其元数据中,因此规格错误报告者可以使用它们为 Instrument 失败和宏规范错误提供更丰富、更精确的错误信息,并对两者进行统一。

0

评论由: alexmiller 发布

在 CLJ-2373 之后,规格宏失败的调用者信息将通过包装的 CompilerException 传达(就像其他编译器和宏扩展错误那样)。应考虑该问题是否因此得到有效解决。

0

评论者:bbrinck

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

当打印规范错误时,如果能够将宏扩展规范错误和工具错误以类似格式打印(如果用户选择自定义规范打印机),则可能更清晰。在一个地方查找宏扩展错误的调用者信息,而在另一个地方查找工具错误的信息,可能会造成干扰。

此外,规范打印机可能会选择对这些调用者信息进行新颖的处理,例如在输出中添加颜色或打印实际代码而不是行号。如果能将这些信息全部提供给规范打印机进行自定义,那就太好了。

0

评论由: alexmiller 发布

问题是,在宏规范错误创建的点上,我们无法知道正确的调用者信息。此时的堆栈是编译器宏展开,而不是调用代码。宏展开确实知道该上下文,这就是它在使用CompilerException(这是CompilerException的主要目的)包装时添加的信息。

我认为要改变这一点,我们需要将此信息通过副本来传递到规范检查中。好吧,也许这是可能的。我会再次看一下。

0

评论者:bbrinck

最近对错误消息的工作(出色的工作!)似乎表明,符号现在是可以使用的,但它目前并没有传递到"explain-out"函数中:https://github.com/clojure/clojure/blob/b182982007df934394f0bc68b3a238ca9f200dd1/src/clj/clojure/main.clj#L268-L279

能否将此关联到传递给"spec/explain-out"的"spec"中?这将允许自定义打印机引用规范名称,这将非常有用。

另一种方法是为用户设置REPL中的自定义错误处理器,但这比设置"explain-out"的第三方实现更复杂。

0
评论者:alexmiller

我不想使这变成只有clojure主REPL可用的东西——如果能用在任何其他REPL上,那就更好了;最好在构建时完成。我现在对如何做到这一点有了更好的把握,但是不知道是否还为1.10版本太晚了。
0
参考:https://clojure.atlassian.net/browse/CLJ-2271(由bbrinck提交)
...