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

欢迎!请查看关于页面以了解有关此功能的一些更多信息。

0
Clojure
以下宏展开的结果无法评估,抛出`java.lang.NegativeArraySizeException`


(macroexpand-1 '(case :a
                  (:a-36 :b-36) 36
                  (:a-37 :b-37) 37
                  (:a-38 :b-38) 38
                  (:a-39 :b-39) 39
                  (:a-40 :b-40) 40
                  (:a-42 :b-42) 42))

;; =>

(clojure.core/let
    [G__8112 :a]
  (case*
    G__8112
    0
    31
    (throw
      (java.lang.IllegalArgumentException.
        (clojure.core/str "No matching clause: " G__8112)))
    {3 [:b-36 36],
     4 [:b-37 37],
     6 [:b-40 40],
     13 [:b-39 39],
     14 [:b-38 38],
     18 [:a-42 42],
     20 [:a-40 40],
     21 [:a-38 38],
     22 [:a-37 37],
     24 [:a-39 39],
     27 [:b-42 42],
     28 [:a-36 36]}
    :compact
    :hash-identity
    nil))



如果您从上面的case中删除任何选项,宏展开可以正确评估。

原因是`case*`在REPL产生的`clojure.lang.PersistentArrayMap`(`{...}`)上阻塞。原始类型是`clojure.lang.PersistentTreeMap`。

结果是,宏展开的列表不能在没有显式检查映射的具体类型的情况下在代码中自由操作。特别是,`clojure.walk/walk`将产生无法评估的结果。

原始问题:https://github.com/clojure-emacs/cider/issues/2335

5 个回答

0
评论由:jafingerhut

我曾在Ubuntu 16.04 Linux系统上尝试,运行OpenJDK 11.0.1,Clojure 1.10.0,在Leiningen REPL中运行,也使用与这些命令行选项一起运行的`clj`工具来使用Clojure 1.10.0

{{
clj -Sdeps "{:deps {org.clojure/clojure {:mvn/version \"1.10.0\"}}}"
}}
当我尝试评估这个表达式时

{{
(eval (macroexpand-1 '(case :a
                  (:a-36 :b-36) 36
                  (:a-37 :b-37) 37
                  (:a-38 :b-38) 38
                  (:a-39 :b-39) 39
                  (:a-40 :b-40) 40
                  (:a-42 :b-42) 42)))
}}
我没有得到一个java.lang.NegativeArraySizeException。相反,我得到与尝试评估不带macroexpand-1和eval调用的(case :a ...)表达式相同的异常,这是一个IllegalArgumentException,因为这里预期没有匹配的分支: :a。

你能说更多关于你做了什么导致抛出java.lang.NegativeArraySizeException异常吗?
0

评论由:jafingerhut

我希望这个指向原始Cider问题的链接比上面的链接更容易理解,上面的链接看起来像是被另一个URL拼接:https://github.com/clojure-emacs/cider/issues/2335

我通常不使用Cider,所以对尝试重现该问题并不感兴趣,但如果它只能在Cider中重现,那么这个问题可能就出在那里?

0

评论由:admin

我无法重现这个问题。在Clojure 1.10.0 repl中。

user=> (case :a (:a-36 :b-36) 36 (:a-37 :b-37) 37 (:a-38 :b-38) 38 (:a-39 :b-39) 39 (:a-40 :b-40) 40 (:a-42 :b-42) 42) 运行时错误 (IllegalArgumentException) 在 user/eval145 (REPL:1) 处。没有匹配的分支: :a (eval (macroexpand-1 '(case :a (:a-36 :b-36) 36 (:a-37 :b-37) 37 (:a-38 :b-38) 38 (:a-39 :b-39) 39 (:a-40 :b-40) 40 (:a-42 :b-42) 42))) 运行时错误 (IllegalArgumentException) 在 user/eval150 (REPL:1) 处。没有匹配的分支: :a

我在哪里丢失了呢?

0
_评论由:bronsa_

触发这个问题的一种方法是手动复制宏展开的代码。这会将文字强制读取为普通映射而不是有序映射。


user=> (clojure.core/let
    [G__8112 :a]
  (case*
    G__8112
    0
    31
    (throw
      (java.lang.IllegalArgumentException.
        (clojure.core/str "No matching clause: " G__8112)))
    {3 [:b-36 36],
     4 [:b-37 37],
     6 [:b-40 40],
     13 [:b-39 39],
     14 [:b-38 38],
     18 [:a-42 42],
     20 [:a-40 40],
     21 [:a-38 38],
     22 [:a-37 37],
     24 [:a-39 39],
     27 [:b-42 42],
     28 [:a-36 36]}
    :compact
    :hash-identity
    nil))
Syntax error (NegativeArraySizeException) 编译 fn* 在 (REPL:1:1)。
null


我不会把这个当作一个bug:`case*`特殊形式的要求是映射必须排序,如果真的有bug,则在上游,在负责遍历和转换展开形式并将排序后的映射转换为常规映射的代码中。

这以前几次让我措手不及,我提出的方案(如在附件的补丁中实现)是简单地添加分析时的检查,并在映射未排序时抛出异常。
0
参考:https://clojure.atlassian.net/browse/CLJ-2511(由vitoshska报告)
...