[CLJ-1492] PersistentQueue objects are improperly eval'd and compiled Created: 06/Aug/14 Updated: 07/Aug/14
|Affects Version/s:||Release 1.6, Release 1.7|
OS X 10.9.4
|Patch:||Code and Test|
PersistentQueue objects do not follow the correct evaluation path in the Compiler.
The simplest case:
user=> (def q (conj clojure.lang.PersistentQueue/EMPTY 1 2 3))
And you get the same exception when embedding a PersistentQueue:
user=> (eval `(fn  ~q))
Instead of the expected:
CompilerException java.lang.RuntimeException: Can't embed unreadable object in code: #<PersistentQueue clojure.lang.PersistentQueue@7861>, compiling:(NO_SOURCE_PATH:3:1)
Since PersistentQueue implements IPersistentCollection and IPersistentList, and is not called out explicitly in the compiler, it is falling into the same compile path as a list. The exception comes from the call to emitValue inside the emitConstants portion of the FnExpr emit path. PersistentQueue does not implement java.util.List and thus the cast in emitListAsObjectArray (Compiler.java:4479) throws. Implementing List would NOT, however, resolve this issue, but would mask it by causing all eval'd PersistedQueues to be compiled as PersistentLists.
The first case is resolved by adding `&& !(form instanceof PersistentQueue)` to the IPersistentCollection branch of Compiler.eval() (Compiler.java:6695-8), allowing the PersistentQueue to fall through to the ConstantExpr case in analyze (Compiler.java:6459). The embedding case is resolved by adding `&& !(value instanceof PersistentQueue)` to the IPersistentList branch in ObjExpr's emitValue (Compiler.java:4639).
This bug also precludes definition of data-readers for PersistentQueue as the read object throws an exception when it is passed to the Compiler.
The attached patch includes the two changes mentioned above, and tests for each case that illustrates the bug.
Clojure-dev thread: https://groups.google.com/forum/#!topic/clojure-dev/LDUQfqjFg9w