Macroexpanded case statement throws `java.lang.NegativeArraySizeException`


The result of the following macroexpansion cannot be evaluated throwing `java.lang.NegativeArraySizeException`

If you remove any of the options in the case above the macroexpansion can be evaluated correctly.

The reason behind this is that `case*` chokes on `clojure.lang.PersistentArrayMap` which `{...}` produces at the REPL. The original type is `clojure.lang.PersistentTreeMap`

The consequence of this is that the macro-expanded lists cannot be freely manipulated in code without checking explicitly for the concrete types of the maps. Particularly, `clojure.walk/walk` will produce un-evaluable results.

Original issue:


Java 11.0.2, ubuntu linux


Andy Fingerhut
May 29, 2019, 11:50 PM

I have tried on an Ubuntu 16.04 Linux system, running OpenJDK 11.0.1, Clojure 1.10.0, in a Leiningen REPL, and also with the `clj` tool run with these command line options to use Clojure 1.10.0:

clj -Sdeps "{:deps {org.clojure/clojure {:mvn/version \"1.10.0\"}}}"
When I try to evaluate this expression:

(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)))
I do not get a java.lang.NegativeArraySizeException. Instead I get the same exception as I get from trying to evaluate the (case :a ...) expression without the macroexpand-1 and eval calls, which is an IllegalArgumentException because there is "No matching clause: :a", which is expected here.

Can you say more about what you are doing that causes the java.lang.NegativeArraySizeException exception to be thrown?

Andy Fingerhut
May 31, 2019, 8:51 PM

I hope this link to the original Cider issue is easier to follow than the one above, which looks like it got concatenated with another URL:

I do not typically use Cider, so not terribly interested in trying to reproduce the issue there, but if it can only be reproduced within Cider, it sounds like perhaps the problem may lie there?

Alex Miller
June 3, 2019, 1:28 PM

I can't reproduce this. In a Clojure 1.10.0 repl:

What am I missing?

Nicola Mometto
June 13, 2019, 12:37 PM

One way to trigger this is to copy the macroexpanded code from manually. This forces the literal to be read as a normal map rather than a sorted map.

I would not consider this a bug: the contract of the `case*` special form requires the map to be sorted, if there's any bug at all it's upstream, in whatever code is responsible for traversing and transforming the macroexpanded form and converting the sorted map into a regular map.

This has caught me offguard a few times in the past, my proposal (as implemented in the attached patch) is to simply add a check at analysis time and throw if the map is not sorted.




Vitalie Spinu







Affects versions