Invalid defrecord results in exception attributed to namespace that imports namespace with defrecord

Description

I was introducing a namespace that included a defrecord.

My defrecord was wrong; it used a keyword to define a field, not a symbol. Minimal test case:

1 2 3 4 % cat src/useclj16/init.clj (ns useclj16.init) (defrecord Application [:shutdown-fn])
1 2 3 % cat src/useclj16/app.clj (ns useclj16.app (:require [useclj16.init :as init]))

However, the exception was perplexing:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 % java -cp clojure-1.6.0-master-SNAPSHOT.jar:src clojure.main user=> (require 'useclj16.app) ClassCastException clojure.lang.Keyword cannot be cast to clojure.lang.IObj clojure.core/with-meta (core.clj:214) user=> (pst *e 100) ClassCastException clojure.lang.Keyword cannot be cast to clojure.lang.IObj clojure.core/with-meta (core.clj:214) clojure.core/defrecord/fn--147 (core_deftype.clj:362) clojure.core/map/fn--4210 (core.clj:2494) clojure.lang.LazySeq.sval (LazySeq.java:42) clojure.lang.LazySeq.seq (LazySeq.java:60) clojure.lang.RT.seq (RT.java:484) clojure.lang.LazilyPersistentVector.create (LazilyPersistentVector.java:31) clojure.core/vec (core.clj:354) clojure.core/defrecord (core_deftype.clj:362) clojure.lang.Var.invoke (Var.java:427) clojure.lang.Var.applyTo (Var.java:532) clojure.lang.Compiler.macroexpand1 (Compiler.java:6483) clojure.lang.Compiler.macroexpand (Compiler.java:6544) clojure.lang.Compiler.eval (Compiler.java:6618) clojure.lang.Compiler.load (Compiler.java:7079) clojure.lang.RT.loadResourceScript (RT.java:370) clojure.lang.RT.loadResourceScript (RT.java:361) clojure.lang.RT.load (RT.java:440) clojure.lang.RT.load (RT.java:411) clojure.core/load/fn--5024 (core.clj:5546) clojure.core/load (core.clj:5545) clojure.core/load-one (core.clj:5352) clojure.core/load-lib/fn--4973 (core.clj:5391) clojure.core/load-lib (core.clj:5390) clojure.core/apply (core.clj:619) clojure.core/load-libs (core.clj:5429) clojure.core/apply (core.clj:619) clojure.core/require (core.clj:5512) useclj16.app/eval322/loading--4916--auto----323 (app.clj:1) useclj16.app/eval322 (app.clj:1) clojure.lang.Compiler.eval (Compiler.java:6634) clojure.lang.Compiler.eval (Compiler.java:6623) clojure.lang.Compiler.load (Compiler.java:7079) clojure.lang.RT.loadResourceScript (RT.java:370) clojure.lang.RT.loadResourceScript (RT.java:361) clojure.lang.RT.load (RT.java:440) clojure.lang.RT.load (RT.java:411) clojure.core/load/fn--5024 (core.clj:5546) clojure.core/load (core.clj:5545) clojure.core/load-one (core.clj:5352) clojure.core/load-lib/fn--4973 (core.clj:5391) clojure.core/load-lib (core.clj:5390) clojure.core/apply (core.clj:619) clojure.core/load-libs (core.clj:5429) clojure.core/apply (core.clj:619) clojure.core/require (core.clj:5512) user/eval318 (NO_SOURCE_FILE:1) clojure.lang.Compiler.eval (Compiler.java:6634) clojure.lang.Compiler.eval (Compiler.java:6597) clojure.core/eval (core.clj:2864) clojure.main/repl/read-eval-print--6594/fn--6597 (main.clj:260) clojure.main/repl/read-eval-print--6594 (main.clj:260) clojure.main/repl/fn--6603 (main.clj:278) clojure.main/repl (main.clj:278) clojure.main/repl-opt (main.clj:344) clojure.main/main (main.clj:442) clojure.lang.Var.invoke (Var.java:411) clojure.lang.Var.applyTo (Var.java:532) clojure.main.main (main.java:37) nil

The error was attributed to app.clj (useclj16.app), a namespace which requires useclj16.init, the namespace containing the defrecord.

No indication that this concerned a defrecord, or even what namespace contained the error, was present in the exception.

Patch: clj-1261-5.diff

Approach: Check explicitly that the fields are all symbols, for both defrecord and deftype, and throw a CompilerException with file, line, and column number if not. Example of exception after patch is applied, in the case give above:

1 2 user=> (require 'useclj16.app) CompilerException java.lang.AssertionError: defrecord and deftype fields must be symbols, useclj16.init.Application had: :shutdown-fn, compiling:(useclj16/init.clj:3:1)

Screened by: Alex Miller

Environment

None

Status

Assignee

Unassigned

Reporter

Howard Lewis Ship

Labels

Approval

Ok

Patch

Code and Test

Fix versions

Affects versions

Release 1.5

Priority

Minor