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.cons.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添加

无法对宏进行工具化,因此,按照目前的规定,这部分工单看起来不合理。但我猜你是想指在宏扩展过程中的规范检查。

在宏检查的情况下,调用者的信息由编译器知道,并包含在Wrapper CompilerException中。我猜这些信息可以被传递到s/macroexpand-check,并且可能与已工具化功能调用产生类似的结果。

0

评论者:bbrinck

啊,你说得对,感谢解释。

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

0

评论者:bbrinck

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

0

评论者:sohta

据我观察,对于工具化失败和宏规范错误,{{explain-data}}应包含函数(或宏)的fspec,正如我在CLJ-2218之前所建议的。

{{fspec}}在其元数据中包含一些有用的信息(如ns-qualified名称符号和行号等),规范错误报告器可以使用它们以统一的方式在工具化失败和宏规范错误中提供更丰富、更精确的错误信息。

0

评论由:alexmiller添加

在CLJ-2373之后,对于规范宏失败的调用者信息将通过包装器CompilerException传达(与其他编译器和宏扩展错误相同)。应考虑是否有效解决了此问题。

0

评论者:bbrinck

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

当打印 spec 错误时,如果宏展开 spec 错误和工具错误能以类似的格式(如果用户选择自定义 spec 打印器)打印,那么会更容易理解。寻找宏展开错误和工具错误调用者的信息可能在不同地方,可能会造成干扰。

此外,spec 打印器可能选择利用这个调用者信息做一些新颖的事情,比如给输出添加颜色或打印实际的代码而不是行号。如果能将这些信息都提供给 spec 打印器来自定义,那就太好了。

0

评论由:alexmiller添加

这里的问题是在宏 spec 错误创建的这个点,我们无法知道合适的调用者信息。那时的调用栈是编译器宏展开,而不是调用代码。宏展开确实知道那个上下文,在加入 CompilerException 时它就会添加这个上下文(这就是 CompilerException 的主要目的)。

我认为改变这个可能会有必要将信息以带外方式传达给 spec 检查。嗯,也许可能是这样的。我会再看看。

0

评论者:bbrinck

在最近的错误消息工作中(杰出的工作!),符号似乎可用,但当前并未将其传递给 "explain-out" 函数: https://github.com/clojure/clojure/blob/b182982007df934394f0bc68b3a238ca9f200dd1/src/clj/clojure/main.clj#L268-L279

是否有将这个“assoc”到传递给 "spec/explain-out" 的 "spec" 中?这将允许自定义打印器引用 spec 名称,这将非常有用。

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

0
_Comment made by: alexmiller_

我不想只让 clj 主 repl 使用这一点 - 如果使用其他 repl,最好总能实现这一点,最好在构建时完成。现在我有了更好的处理方法,但不清楚是否还来得及为 1.10 版本实现。
0
by
参考: https://clojure.atlassian.net/browse/CLJ-2271(由bbrinck报告)
...