Clojure

Error when calling primitive functions with destructuring in the arg vector

Details

  • Type: Defect Defect
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Completed
  • Affects Version/s: Release 1.6, Release 1.7
  • Fix Version/s: Release 1.7
  • Component/s: None
  • Labels:
  • Patch:
    Code
  • Approval:
    Ok

Description

If one defines a primitive-taking function with destructuring, calling that function will result in a ClassCastException, IFF the primitive return-type hint is present.

Clojure 1.4.0-master-SNAPSHOT
user=> (defn foo [[a b] ^long x ^long y] 0)
#'user/foo
user=> (foo [1 2] 3 4)
0
user=> (defn foo ^long [[a b] ^long x ^long y] 0)
#'user/foo
user=> (foo [1 2] 3 4)
ClassCastException user$foo cannot be cast to clojure.lang.IFn$OLLL  user/eval9 (NO_SOURCE_FILE:4)
user=> (pst)
ClassCastException user$foo cannot be cast to clojure.lang.IFn$OLLL
	user/eval9 (NO_SOURCE_FILE:4)
	clojure.lang.Compiler.eval (Compiler.java:6493)
	clojure.lang.Compiler.eval (Compiler.java:6459)
	clojure.core/eval (core.clj:2796)
	clojure.main/repl/read-eval-print--5967 (main.clj:244)
	clojure.main/repl/fn--5972 (main.clj:265)
	clojure.main/repl (main.clj:265)
	clojure.main/repl-opt (main.clj:331)
	clojure.main/main (main.clj:427)
	clojure.lang.Var.invoke (Var.java:397)
	clojure.lang.Var.applyTo (Var.java:518)
	clojure.main.main (main.java:37)
nil

Cause: This was happening because maybe-destructured returned the arg vector without the type hint, so the function was getting compiled to a IFn$OLLO rather than a IFn$OLLL but the :arglists vector in the var meta was still tagged, so the compiler thought that foo was a IFn$OLLL.

Approach: This patch addresses this by preserving the original meta on the fn arglist.

Patch: 0001-don-t-remove-meta-from-arg-vector-in-maybe-destructu.patch

Screened by: Alex Miller

Activity

Alexander Taggart made changes -
Field Original Value New Value
Description If one defines a primitive-taking function with destructuring, calling that function will result in a ClassCastException, IFF the primitive return-type hint is present.

{noformat}
Clojure 1.4.0-master-SNAPSHOT
user=> (defn foo [[a b] ^long x ^long y])
#'user/foo
user=> (foo [1 2] 3 4)
nil
user=> (defn foo ^long [[a b] ^long x ^long y])
#'user/foo
user=> (foo [1 2] 3 4)
ClassCastException user$foo cannot be cast to clojure.lang.IFn$OLLL user/eval9 (NO_SOURCE_FILE:4)
user=> (pst)
ClassCastException user$foo cannot be cast to clojure.lang.IFn$OLLL
user/eval9 (NO_SOURCE_FILE:4)
clojure.lang.Compiler.eval (Compiler.java:6493)
clojure.lang.Compiler.eval (Compiler.java:6459)
clojure.core/eval (core.clj:2796)
clojure.main/repl/read-eval-print--5967 (main.clj:244)
clojure.main/repl/fn--5972 (main.clj:265)
clojure.main/repl (main.clj:265)
clojure.main/repl-opt (main.clj:331)
clojure.main/main (main.clj:427)
clojure.lang.Var.invoke (Var.java:397)
clojure.lang.Var.applyTo (Var.java:518)
clojure.main.main (main.java:37)
nil
{noformat}
If one defines a primitive-taking function with destructuring, calling that function will result in a ClassCastException, IFF the primitive return-type hint is present.

{noformat}
Clojure 1.4.0-master-SNAPSHOT
user=> (defn foo [[a b] ^long x ^long y] 0)
#'user/foo
user=> (foo [1 2] 3 4)
0
user=> (defn foo ^long [[a b] ^long x ^long y] 0)
#'user/foo
user=> (foo [1 2] 3 4)
ClassCastException user$foo cannot be cast to clojure.lang.IFn$OLLL user/eval9 (NO_SOURCE_FILE:4)
user=> (pst)
ClassCastException user$foo cannot be cast to clojure.lang.IFn$OLLL
user/eval9 (NO_SOURCE_FILE:4)
clojure.lang.Compiler.eval (Compiler.java:6493)
clojure.lang.Compiler.eval (Compiler.java:6459)
clojure.core/eval (core.clj:2796)
clojure.main/repl/read-eval-print--5967 (main.clj:244)
clojure.main/repl/fn--5972 (main.clj:265)
clojure.main/repl (main.clj:265)
clojure.main/repl-opt (main.clj:331)
clojure.main/main (main.clj:427)
clojure.lang.Var.invoke (Var.java:397)
clojure.lang.Var.applyTo (Var.java:518)
clojure.main.main (main.java:37)
nil
{noformat}
Nicola Mometto made changes -
Nicola Mometto made changes -
Patch Code [ 10001 ]
Affects Version/s Release 1.3 [ 10038 ]
Affects Version/s Release 1.7 [ 10250 ]
Affects Version/s Release 1.6 [ 10157 ]
Alex Miller made changes -
Approval Triaged [ 10120 ]
Labels compiler
Rich Hickey made changes -
Fix Version/s Release 1.7 [ 10250 ]
Approval Triaged [ 10120 ] Vetted [ 10003 ]
Alex Miller made changes -
Approval Vetted [ 10003 ] Screened [ 10004 ]
Description If one defines a primitive-taking function with destructuring, calling that function will result in a ClassCastException, IFF the primitive return-type hint is present.

{noformat}
Clojure 1.4.0-master-SNAPSHOT
user=> (defn foo [[a b] ^long x ^long y] 0)
#'user/foo
user=> (foo [1 2] 3 4)
0
user=> (defn foo ^long [[a b] ^long x ^long y] 0)
#'user/foo
user=> (foo [1 2] 3 4)
ClassCastException user$foo cannot be cast to clojure.lang.IFn$OLLL user/eval9 (NO_SOURCE_FILE:4)
user=> (pst)
ClassCastException user$foo cannot be cast to clojure.lang.IFn$OLLL
user/eval9 (NO_SOURCE_FILE:4)
clojure.lang.Compiler.eval (Compiler.java:6493)
clojure.lang.Compiler.eval (Compiler.java:6459)
clojure.core/eval (core.clj:2796)
clojure.main/repl/read-eval-print--5967 (main.clj:244)
clojure.main/repl/fn--5972 (main.clj:265)
clojure.main/repl (main.clj:265)
clojure.main/repl-opt (main.clj:331)
clojure.main/main (main.clj:427)
clojure.lang.Var.invoke (Var.java:397)
clojure.lang.Var.applyTo (Var.java:518)
clojure.main.main (main.java:37)
nil
{noformat}
If one defines a primitive-taking function with destructuring, calling that function will result in a ClassCastException, IFF the primitive return-type hint is present.

{noformat}
Clojure 1.4.0-master-SNAPSHOT
user=> (defn foo [[a b] ^long x ^long y] 0)
#'user/foo
user=> (foo [1 2] 3 4)
0
user=> (defn foo ^long [[a b] ^long x ^long y] 0)
#'user/foo
user=> (foo [1 2] 3 4)
ClassCastException user$foo cannot be cast to clojure.lang.IFn$OLLL user/eval9 (NO_SOURCE_FILE:4)
user=> (pst)
ClassCastException user$foo cannot be cast to clojure.lang.IFn$OLLL
user/eval9 (NO_SOURCE_FILE:4)
clojure.lang.Compiler.eval (Compiler.java:6493)
clojure.lang.Compiler.eval (Compiler.java:6459)
clojure.core/eval (core.clj:2796)
clojure.main/repl/read-eval-print--5967 (main.clj:244)
clojure.main/repl/fn--5972 (main.clj:265)
clojure.main/repl (main.clj:265)
clojure.main/repl-opt (main.clj:331)
clojure.main/main (main.clj:427)
clojure.lang.Var.invoke (Var.java:397)
clojure.lang.Var.applyTo (Var.java:518)
clojure.main.main (main.java:37)
nil
{noformat}

*Cause:* This was happening because maybe-destructured returned the arg vector without the type hint, so the function was getting compiled to a IFn$OLLO rather than a IFn$OLLL but the :arglists vector in the var meta was still tagged, so the compiler thought that foo was a IFn$OLLL.

*Approach:* This patch addresses this by preserving the original meta on the fn arglist.

*Patch:* 0001-don-t-remove-meta-from-arg-vector-in-maybe-destructu.patch

*Screened by:* Alex Miller
Rich Hickey made changes -
Approval Screened [ 10004 ] Ok [ 10007 ]
Stuart Halloway made changes -
Resolution Completed [ 1 ]
Status Open [ 1 ] Closed [ 6 ]

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: