From f25f3e297817803528e6c0ea46242c45a8d8e6fe Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 25 Sep 2020 08:58:20 -0500 Subject: [PATCH 001/285] CLJ-2564 Improve error message for `case` Signed-off-by: Stuart Halloway --- src/clj/clojure/core.clj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 8d29cd3862..3caf962296 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -6696,6 +6696,9 @@ fails, attempts to require sym's namespace and retries." (into1 #{} (map #(shift-mask shift mask %) skip-check)))] [shift mask case-map switch-type skip-check])))) +(defn case-fallthrough-err-impl + [val] + (IllegalArgumentException. (str "No matching clause: " (pr-str val)))) (defmacro case "Takes an expression, and a set of clauses. @@ -6726,7 +6729,7 @@ fails, attempts to require sym's namespace and retries." (let [ge (with-meta (gensym) {:tag Object}) default (if (odd? (count clauses)) (last clauses) - `(throw (IllegalArgumentException. (str "No matching clause: " ~ge))))] + `(throw (case-fallthrough-err-impl ~ge)))] (if (> 2 (count clauses)) `(let [~ge ~e] ~default) (let [pairs (partition 2 clauses) From fb341d3edff0c201ca7a32df5a9f1a13c9c3f779 Mon Sep 17 00:00:00 2001 From: Ghadi Shayban Date: Fri, 18 Sep 2020 13:11:41 -0400 Subject: [PATCH 002/285] CLJ-2580 correct case expr branch analysis Signed-off-by: Stuart Halloway --- src/jvm/clojure/lang/Compiler.java | 2 ++ test/clojure/test_clojure/compilation.clj | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index abac2251a2..51a9372e95 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1375,6 +1375,8 @@ static Class maybeJavaClass(Collection exprs){ if (!e.hasJavaClass()) return null; Class c = e.getJavaClass(); + if (c == null) + return null; if (match == null) match = c; else if (match != c) diff --git a/test/clojure/test_clojure/compilation.clj b/test/clojure/test_clojure/compilation.clj index 8a5fd84233..999d33f91b 100644 --- a/test/clojure/test_clojure/compilation.clj +++ b/test/clojure/test_clojure/compilation.clj @@ -438,3 +438,8 @@ (is (= 42 (compilation.JDK8InterfaceMethods/staticMethod0 42))) (is (= "test" (compilation.JDK8InterfaceMethods/staticMethod1 "test"))) (is (= 1 (if (compilation.JDK8InterfaceMethods/staticMethod2 true) 1 2))))) + +(deftest CLJ-2580 + (testing "CLJ-2580 Correctly calculate exit branches of case" + (is (zero? (let [d (case nil :x nil 0)] d))) + (is (nil? (let [d (case nil :x 0 nil)] d))))) From 51261641817005f872f9b6a752c5aef0bb7a5be4 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 28 Aug 2020 12:54:34 -0500 Subject: [PATCH 003/285] CLJ-2469 Make fewer assumptions about maps when printing them Signed-off-by: Stuart Halloway --- src/clj/clojure/core_print.clj | 24 +++++++------- test/clojure/test_clojure/printer.clj | 48 +++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/src/clj/clojure/core_print.clj b/src/clj/clojure/core_print.clj index b4992aadae..18c5101c1d 100644 --- a/src/clj/clojure/core_print.clj +++ b/src/clj/clojure/core_print.clj @@ -226,14 +226,14 @@ (print-meta v w) (print-sequential "[" pr-on " " "]" v w)) -(defn- print-prefix-map [prefix m print-one w] +(defn- print-prefix-map [prefix kvs print-one w] (print-sequential (str prefix "{") - (fn [e ^Writer w] - (do (print-one (key e) w) (.append w \space) (print-one (val e) w))) + (fn [[k v] ^Writer w] + (do (print-one k w) (.append w \space) (print-one v w))) ", " "}" - (seq m) w)) + kvs w)) (defn- print-map [m print-one w] (print-prefix-map nil m print-one w)) @@ -245,26 +245,26 @@ (keyword nil (name named)))) (defn- lift-ns - "Returns [lifted-ns lifted-map] or nil if m can't be lifted." + "Returns [lifted-ns lifted-kvs] or nil if m can't be lifted." [m] (when *print-namespace-maps* (loop [ns nil [[k v :as entry] & entries] (seq m) - lm {}] + kvs []] (if entry - (when (or (keyword? k) (symbol? k)) + (when (qualified-ident? k) (if ns (when (= ns (namespace k)) - (recur ns entries (assoc lm (strip-ns k) v))) + (recur ns entries (conj kvs [(strip-ns k) v]))) (when-let [new-ns (namespace k)] - (recur new-ns entries (assoc lm (strip-ns k) v))))) - [ns (apply conj (empty m) lm)])))) + (recur new-ns entries (conj kvs [(strip-ns k) v]))))) + [ns kvs])))) (defmethod print-method clojure.lang.IPersistentMap [m, ^Writer w] (print-meta m w) - (let [[ns lift-map] (lift-ns m)] + (let [[ns lift-kvs] (lift-ns m)] (if ns - (print-prefix-map (str "#:" ns) lift-map pr-on w) + (print-prefix-map (str "#:" ns) lift-kvs pr-on w) (print-map m pr-on w)))) (defmethod print-dup java.util.Map [m, ^Writer w] diff --git a/test/clojure/test_clojure/printer.clj b/test/clojure/test_clojure/printer.clj index 3d9cc65f8f..e5b3796699 100644 --- a/test/clojure/test_clojure/printer.clj +++ b/test/clojure/test_clojure/printer.clj @@ -14,7 +14,8 @@ ;; Created 29 October 2008 (ns clojure.test-clojure.printer - (:use clojure.test)) + (:use clojure.test) + (:require [clojure.pprint :refer [pprint]])) (deftest print-length-empty-seq (let [coll () val "()"] @@ -135,8 +136,49 @@ {:with "even" :more 'data}))))))) (deftest print-ns-maps - (is (= "#:user{:a 1}" (binding [*print-namespace-maps* true] (pr-str {:user/a 1})))) - (is (= "{:user/a 1}" (binding [*print-namespace-maps* false] (pr-str {:user/a 1})))) + (are [m s-on pp-on s-off] + (and (= s-on (binding [*print-namespace-maps* true] (pr-str m))) + (= pp-on (binding [*print-namespace-maps* true] (with-out-str (pprint m)))) + (= s-off (binding [*print-namespace-maps* false] (pr-str m)))) + {} "{}" "{}\n" "{}" + {:a 1, :b 2} "{:a 1, :b 2}" "{:a 1, :b 2}\n" "{:a 1, :b 2}" + {:user/a 1} "#:user{:a 1}" "#:user{:a 1}\n" "{:user/a 1}" + {:user/a 1, :user/b 2} "#:user{:a 1, :b 2}" "#:user{:a 1, :b 2}\n" "{:user/a 1, :user/b 2}" + {:user/a 1, :b 2} "{:user/a 1, :b 2}" "{:user/a 1, :b 2}\n" "{:user/a 1, :b 2}" + {:user/a 1, 'user/b 2} "#:user{:a 1, b 2}" "#:user{:a 1, b 2}\n" "{:user/a 1, user/b 2}" + {:user/a 1, :foo/b 2} "{:user/a 1, :foo/b 2}" "{:user/a 1, :foo/b 2}\n" "{:user/a 1, :foo/b 2}" + + {:user/a 1, :user/b 2, 100 200} + "{:user/a 1, :user/b 2, 100 200}" + "{:user/a 1, :user/b 2, 100 200}\n" + "{:user/a 1, :user/b 2, 100 200}" + + ;; CLJ-2469 + (struct (create-struct :q/a :q/b :q/c) 1 2 3) + "#:q{:a 1, :b 2, :c 3}" + "#:q{:a 1, :b 2, :c 3}\n" + "{:q/a 1, :q/b 2, :q/c 3}" + + ;; CLJ-2537 + {:x.y/a {:rem 0}, :x.y/b {:rem 1}} + "#:x.y{:a {:rem 0}, :b {:rem 1}}" + "#:x.y{:a {:rem 0}, :b {:rem 1}}\n" + "{:x.y/a {:rem 0}, :x.y/b {:rem 1}}" + + (into (sorted-map-by (fn [k1 k2] + (when-not (every? qualified-ident? [k1 k2]) + (throw (RuntimeException. (str "Invalid keys:" [k1 k2])))) + (compare k1 k2)) + :x.y/a {:rem 0}, :x.y/b {:rem 1})) + "#:x.y{:a {:rem 0}, :b {:rem 1}}" + "#:x.y{:a {:rem 0}, :b {:rem 1}}\n" + "{:x.y/a {:rem 0}, :x.y/b {:rem 1}}" + + (sorted-map-by #(compare %2 %1) :k/a 1 :k/b 2 :k/c 3 :k/d 4 :k/e 5 :k/f 6 :k/g 7 :k/h 8 :k/i 9) + "#:k{:i 9, :h 8, :g 7, :f 6, :e 5, :d 4, :c 3, :b 2, :a 1}" + "#:k{:i 9, :h 8, :g 7, :f 6, :e 5, :d 4, :c 3, :b 2, :a 1}\n" + "{:k/i 9, :k/h 8, :k/g 7, :k/f 6, :k/e 5, :k/d 4, :k/c 3, :k/b 2, :k/a 1}") + (let [date-map (bean (java.util.Date. 0))] (is (= (binding [*print-namespace-maps* true] (pr-str date-map)) (binding [*print-namespace-maps* false] (pr-str date-map)))))) From 995dd1d6bd9f6a704bc60ccc317710bd5b04c825 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Fri, 25 Sep 2020 14:00:35 -0500 Subject: [PATCH 004/285] [maven-release-plugin] prepare release clojure-1.10.2-alpha2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 78784d3a4d..bc4ecb790d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.2-master-SNAPSHOT + 1.10.2-alpha2 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.10.2-alpha2 From cbb3fdf787a00d3c1443794b97ed7fe4bef8e888 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Fri, 25 Sep 2020 14:00:36 -0500 Subject: [PATCH 005/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index bc4ecb790d..78784d3a4d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.2-alpha2 + 1.10.2-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.10.2-alpha2 + HEAD From c70828bb27bf9d0f9e11a00f634d824f98df4ab9 Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Thu, 22 Aug 2019 18:23:45 -0500 Subject: [PATCH 006/285] CLJ-1187 Support retrieval of metadata from quoted empty literals Signed-off-by: Stuart Halloway --- src/jvm/clojure/lang/Compiler.java | 4 +++- test/clojure/test_clojure/metadata.clj | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 51a9372e95..aba95f19f1 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -2022,7 +2022,9 @@ else if(v == Boolean.FALSE) return NumberExpr.parse((Number)v); else if(v instanceof String) return new StringExpr((String) v); - else if(v instanceof IPersistentCollection && ((IPersistentCollection) v).count() == 0) + else if(v instanceof IPersistentCollection + && (((IPersistentCollection) v).count() == 0) + && (!(v instanceof IObj) || ((IObj) v).meta() == null)) return new EmptyExpr(v); else return new ConstantExpr(v); diff --git a/test/clojure/test_clojure/metadata.clj b/test/clojure/test_clojure/metadata.clj index d0158ab2a7..e0e4fe58e6 100644 --- a/test/clojure/test_clojure/metadata.clj +++ b/test/clojure/test_clojure/metadata.clj @@ -51,6 +51,13 @@ (def ^{:a 1} foo 0) #'foo)] (is (= 1 (-> v meta :a))))) + (testing "const vars preserve metadata" + (let [[v1 v2] (eval-in-temp-ns + (def ^:const foo ^:foo []) + (def ^:const bar ^:foo [:bar]) + [(meta foo) (meta bar)])] + (is (= {:foo true} v1)) + (is (= {:foo true} v2)))) #_(testing "subsequent declare doesn't overwrite metadata" (let [v (eval-in-temp-ns (def ^{:b 2} bar 0) From dd3075f0feaf69ad5089c478ae9562049f5335a8 Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Sun, 29 Dec 2019 00:13:38 -0800 Subject: [PATCH 007/285] CLJ-2549: Make class VecSeq implement interface IObj Signed-off-by: Stuart Halloway --- src/clj/clojure/gvec.clj | 18 +++++++++++++----- test/clojure/test_clojure/sequences.clj | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/clj/clojure/gvec.clj b/src/clj/clojure/gvec.clj index 6208f55390..9fec72640d 100644 --- a/src/clj/clojure/gvec.clj +++ b/src/clj/clojure/gvec.clj @@ -55,7 +55,7 @@ (recur ret (inc i)))) ret)))) -(deftype VecSeq [^clojure.core.ArrayManager am ^clojure.core.IVecImpl vec anode ^int i ^int offset] +(deftype VecSeq [^clojure.core.ArrayManager am ^clojure.core.IVecImpl vec anode ^int i ^int offset ^clojure.lang.IPersistentMap _meta] :no-print true clojure.core.protocols.InternalReduce @@ -82,7 +82,7 @@ (first [_] (.aget am anode offset)) (next [this] (if (< (inc offset) (.alength am anode)) - (new VecSeq am vec anode i (inc offset)) + (new VecSeq am vec anode i (inc offset) nil) (.chunkedNext this))) (more [this] (let [s (.next this)] @@ -120,10 +120,18 @@ (chunkedNext [_] (let [nexti (+ i (.alength am anode))] (when (< nexti (count vec)) - (new VecSeq am vec (.arrayFor vec nexti) nexti 0)))) + (new VecSeq am vec (.arrayFor vec nexti) nexti 0 nil)))) (chunkedMore [this] (let [s (.chunkedNext this)] - (or s (clojure.lang.PersistentList/EMPTY))))) + (or s (clojure.lang.PersistentList/EMPTY)))) + + clojure.lang.IMeta + (meta [_] + _meta) + + clojure.lang.IObj + (withMeta [_ m] + (new VecSeq am vec anode i offset m))) (defmethod print-method ::VecSeq [v w] ((get (methods print-method) clojure.lang.ISeq) v w)) @@ -296,7 +304,7 @@ (seq [this] (if (zero? cnt) nil - (VecSeq. am this (.arrayFor this 0) 0 0))) + (VecSeq. am this (.arrayFor this 0) 0 0 nil))) clojure.lang.Sequential ;marker, no methods diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj index e568b52557..54d640f72d 100644 --- a/test/clojure/test_clojure/sequences.clj +++ b/test/clojure/test_clojure/sequences.clj @@ -1368,3 +1368,19 @@ (deftest test-sort-retains-meta (is (= {:a true} (meta (sort (with-meta (range 10) {:a true}))))) (is (= {:a true} (meta (sort-by :a (with-meta (seq [{:a 5} {:a 2} {:a 3}]) {:a true})))))) + +(deftest test-seqs-implements-iobj + (doseq [coll [[1 2 3] + (vector-of :long 1 2 3) + {:a 1 :b 2 :c 3} + (sorted-map :a 1 :b 2 :c 3) + #{1 2 3} + (sorted-set 1 2 3) + (into clojure.lang.PersistentQueue/EMPTY [1 2 3])]] + (is (= true (instance? clojure.lang.IMeta coll))) + (is (= {:a true} (meta (with-meta coll {:a true})))) + (is (= true (instance? clojure.lang.IMeta (seq coll)))) + (is (= {:a true} (meta (with-meta (seq coll) {:a true})))) + (when (reversible? coll) + (is (= true (instance? clojure.lang.IMeta (rseq coll)))) + (is (= {:a true} (meta (with-meta (rseq coll) {:a true}))))))) From 3b6c31bc503afe8f25d01d6d7d05ebc960095abd Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Fri, 16 Oct 2020 15:28:47 -0500 Subject: [PATCH 008/285] CLJ-2534: Use correct Java module name in javadoc URLs Signed-off-by: Stuart Halloway --- src/clj/clojure/java/javadoc.clj | 19 +++++++++++++++++-- test/clojure/test_clojure/java/javadoc.clj | 7 ++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/clj/clojure/java/javadoc.clj b/src/clj/clojure/java/javadoc.clj index 2e9e0fbb89..c36acc3de6 100644 --- a/src/clj/clojure/java/javadoc.clj +++ b/src/clj/clojure/java/javadoc.clj @@ -23,7 +23,11 @@ "1.8" "http://docs.oracle.com/javase/8/docs/api/" "9" "http://docs.oracle.com/javase/9/docs/api/" "10" "http://docs.oracle.com/javase/10/docs/api/" - "11" "https://docs.oracle.com/en/java/javase/11/docs/api/java.base/" + "11" "https://docs.oracle.com/en/java/javase/11/docs/api/%s/" + "12" "https://docs.oracle.com/en/java/javase/12/docs/api/%s/" + "13" "https://docs.oracle.com/en/java/javase/13/docs/api/%s/" + "14" "https://docs.oracle.com/en/java/javase/14/docs/api/%s/" + "15" "https://docs.oracle.com/en/java/javase/15/docs/api/%s/" "http://docs.oracle.com/javase/8/docs/api/")) (def ^:dynamic *remote-javadocs* @@ -53,6 +57,16 @@ [package-prefix url] (dosync (commute *remote-javadocs* assoc package-prefix url))) +(defn- fill-in-module-name [^String url ^String classname] + ;; The getModule method was introduced in JDK 9, and did not exist + ;; in earlier JDK versions. Avoid calling it unless its result is + ;; needed. + (if (.contains url "%s") + (let [klass (Class/forName classname) + module-name (.getName (.getModule klass))] + (format url module-name)) + url)) + (defn- javadoc-url "Searches for a URL for the given class name. Tries *local-javadocs* first, then *remote-javadocs*. Returns a string." @@ -69,7 +83,8 @@ ;; If no local file, try remote URLs: (or (some (fn [[prefix url]] (when (.startsWith classname prefix) - (str url url-path ".html"))) + (str (fill-in-module-name url classname) + url-path ".html"))) @*remote-javadocs*) ;; if *feeling-lucky* try a web search (when *feeling-lucky* (str *feeling-lucky-url* url-path ".html")))))) diff --git a/test/clojure/test_clojure/java/javadoc.clj b/test/clojure/test_clojure/java/javadoc.clj index 575314cfa6..4ef665121f 100644 --- a/test/clojure/test_clojure/java/javadoc.clj +++ b/test/clojure/test_clojure/java/javadoc.clj @@ -9,14 +9,19 @@ (ns clojure.test-clojure.java.javadoc (:use clojure.test [clojure.java.javadoc :as j]) + (:require [clojure.string :as str]) (:import (java.io File))) +(defn correct-url [url-pattern-str module-name url-suffix] + (str (format url-pattern-str module-name) url-suffix)) + (deftest javadoc-url-test (testing "for a core api" (binding [*feeling-lucky* false] (are [x y] (= x (#'j/javadoc-url y)) nil "foo.Bar" - (str *core-java-api* "java/lang/String.html") "java.lang.String"))) + (correct-url *core-java-api* "java.base" "java/lang/String.html") "java.lang.String" + (correct-url *core-java-api* "java.sql" "java/sql/Connection.html") "java.sql.Connection"))) (testing "for a remote javadoc" (binding [*remote-javadocs* (ref (sorted-map "java." "http://example.com/"))] (is (= "http://example.com/java/lang/Number.html" (#'j/javadoc-url "java.lang.Number")))))) From 05c193c031aa3a825ebb824b4135e36a79693f51 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 19 Mar 2019 16:14:19 -0500 Subject: [PATCH 009/285] CLJ-2492 Fix use of deprecated Class.newInstance() method Signed-off-by: Stuart Halloway --- src/jvm/clojure/lang/Compiler.java | 2 +- src/jvm/clojure/lang/FnLoaderThunk.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index aba95f19f1..041786e888 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -4997,7 +4997,7 @@ public Object eval() { return null; try { - return getCompiledClass().newInstance(); + return getCompiledClass().getDeclaredConstructor().newInstance(); } catch(Exception e) { diff --git a/src/jvm/clojure/lang/FnLoaderThunk.java b/src/jvm/clojure/lang/FnLoaderThunk.java index 337ba2558c..692e45c752 100644 --- a/src/jvm/clojure/lang/FnLoaderThunk.java +++ b/src/jvm/clojure/lang/FnLoaderThunk.java @@ -51,7 +51,7 @@ private void load() { { try { - fn = (IFn) Class.forName(fnClassName,true,loader).newInstance(); + fn = (IFn) Class.forName(fnClassName,true,loader).getDeclaredConstructor().newInstance(); } catch(Exception e) { From 833c924239a818ff1a2563ae88af6dc266b35a61 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 19 Oct 2020 10:36:07 -0500 Subject: [PATCH 010/285] CLJ-1364 Add hash and equality methods for primitive vec seqs Signed-off-by: Stuart Halloway --- src/clj/clojure/gvec.clj | 35 +++++++++++++++++-- src/jvm/clojure/lang/MySeq.java | 18 ++++++++++ test/clojure/test_clojure/data_structures.clj | 17 +++++++-- 3 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 src/jvm/clojure/lang/MySeq.java diff --git a/src/clj/clojure/gvec.clj b/src/clj/clojure/gvec.clj index 9fec72640d..5123e1b32e 100644 --- a/src/clj/clojure/gvec.clj +++ b/src/clj/clojure/gvec.clj @@ -10,7 +10,8 @@ (in-ns 'clojure.core) -(import '(clojure.lang Murmur3)) +(import '(clojure.lang Murmur3 IHashEq Sequential Util SeqIterator) + '(java.util List)) (set! *warn-on-reflection* true) @@ -131,7 +132,37 @@ clojure.lang.IObj (withMeta [_ m] - (new VecSeq am vec anode i offset m))) + (new VecSeq am vec anode i offset m)) + +Object + (hashCode [this] + (loop [hash 1 + s (seq this)] + (if s + (let [v (first s)] + (if (nil? v) + (recur (unchecked-multiply-int 31 hash) (next s)) + (recur (unchecked-add-int (unchecked-multiply-int 31 hash) (.hashCode v)) (next s)))) + hash))) + (equals [this other] + (cond (identical? this other) true + (or (instance? Sequential other) (instance? List other)) + (loop [s this + os (seq other)] + (if (nil? s) + (nil? os) + (if (Util/equals (first s) (first os)) + (recur (next s) (next os)) + false))) + :else false)) + + IHashEq + (hasheq [this] + (Murmur3/hashOrdered this)) + + Iterable + (iterator [this] + (SeqIterator. this))) (defmethod print-method ::VecSeq [v w] ((get (methods print-method) clojure.lang.ISeq) v w)) diff --git a/src/jvm/clojure/lang/MySeq.java b/src/jvm/clojure/lang/MySeq.java new file mode 100644 index 0000000000..d9abf8908b --- /dev/null +++ b/src/jvm/clojure/lang/MySeq.java @@ -0,0 +1,18 @@ +package clojure.lang; + +public class MySeq extends ASeq { + @Override + public Object first() { + return null; + } + + @Override + public ISeq next() { + return null; + } + + @Override + public Obj withMeta(IPersistentMap meta) { + return null; + } +} diff --git a/test/clojure/test_clojure/data_structures.clj b/test/clojure/test_clojure/data_structures.clj index 580e30b073..69baf137c6 100644 --- a/test/clojure/test_clojure/data_structures.clj +++ b/test/clojure/test_clojure/data_structures.clj @@ -14,7 +14,8 @@ [clojure.test.generative :exclude (is)]) (:require [clojure.test-clojure.generators :as cgen] [clojure.data.generators :as gen] - [clojure.string :as string])) + [clojure.string :as string]) + (:import [java.util Collection])) ;; *** Helper functions *** @@ -1107,7 +1108,11 @@ (defn is-same-collection [a b] (let [msg (format "(class a)=%s (class b)=%s a=%s b=%s" (.getName (class a)) (.getName (class b)) a b)] - (is (= (count a) (count b) (.size a) (.size b)) msg) + (is (= (count a) (count b)) msg) + (when (instance? Collection a) + (is (= (count a) (.size a)) msg)) + (when (instance? Collection b) + (is (= (count b) (.size b)) msg)) (is (= a b) msg) (is (= b a) msg) (is (.equals ^Object a b) msg) @@ -1133,7 +1138,13 @@ (sequence (map identity) [-3 :a "7th"]) ]] (doseq [c1 colls1, c2 colls1] (is-same-collection c1 c2))) - (is-same-collection [-3 1 7] (vector-of :long -3 1 7))) + (let [long-colls [ [2 3 4] + '(2 3 4) + (vector-of :long 2 3 4) + (seq (vector-of :long 2 3 4)) + (range 2 5)]] + (doseq [c1 long-colls, c2 long-colls] + (is-same-collection c1 c2)))) (defn case-indendent-string-cmp [s1 s2] (compare (string/lower-case s1) (string/lower-case s2))) From 96dd8fa0deca4b1f500b34cd555d21f3180a33e9 Mon Sep 17 00:00:00 2001 From: Stuart Halloway Date: Mon, 2 Nov 2020 07:55:48 -0500 Subject: [PATCH 011/285] remove spurious file --- src/jvm/clojure/lang/MySeq.java | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 src/jvm/clojure/lang/MySeq.java diff --git a/src/jvm/clojure/lang/MySeq.java b/src/jvm/clojure/lang/MySeq.java deleted file mode 100644 index d9abf8908b..0000000000 --- a/src/jvm/clojure/lang/MySeq.java +++ /dev/null @@ -1,18 +0,0 @@ -package clojure.lang; - -public class MySeq extends ASeq { - @Override - public Object first() { - return null; - } - - @Override - public ISeq next() { - return null; - } - - @Override - public Obj withMeta(IPersistentMap meta) { - return null; - } -} From 03d34d327753dfeb0e0c3951bc9f8fc28d1fcf52 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Mon, 2 Nov 2020 09:39:16 -0600 Subject: [PATCH 012/285] [maven-release-plugin] prepare release clojure-1.10.2-alpha3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 78784d3a4d..c989a4ae71 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.2-master-SNAPSHOT + 1.10.2-alpha3 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.10.2-alpha3 From 7baa5b2f79f05c56a04e1d5c90129972cd962df3 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Mon, 2 Nov 2020 09:39:16 -0600 Subject: [PATCH 013/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c989a4ae71..78784d3a4d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.2-alpha3 + 1.10.2-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.10.2-alpha3 + HEAD From 79ac8b88f83c818314790449dda6ace7db275b56 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 5 Nov 2020 08:46:21 -0600 Subject: [PATCH 014/285] CLJ-2587 Fix reflection in gvec Signed-off-by: Stuart Halloway --- src/clj/clojure/gvec.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clj/clojure/gvec.clj b/src/clj/clojure/gvec.clj index 5123e1b32e..52075c420e 100644 --- a/src/clj/clojure/gvec.clj +++ b/src/clj/clojure/gvec.clj @@ -142,7 +142,7 @@ Object (let [v (first s)] (if (nil? v) (recur (unchecked-multiply-int 31 hash) (next s)) - (recur (unchecked-add-int (unchecked-multiply-int 31 hash) (.hashCode v)) (next s)))) + (recur (unchecked-add-int (unchecked-multiply-int 31 hash) (.hashCode ^Object v)) (next s)))) hash))) (equals [this other] (cond (identical? this other) true From 36f0c14e179a1f5a67f112724856e7a6a504a488 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Thu, 5 Nov 2020 11:41:41 -0600 Subject: [PATCH 015/285] [maven-release-plugin] prepare release clojure-1.10.2-alpha4 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 78784d3a4d..a4df4c2825 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.2-master-SNAPSHOT + 1.10.2-alpha4 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.10.2-alpha4 From f47c139e20970ee0852166f48ee2a4626632b86e Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Thu, 5 Nov 2020 11:41:41 -0600 Subject: [PATCH 016/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a4df4c2825..78784d3a4d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.2-alpha4 + 1.10.2-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.10.2-alpha4 + HEAD From f22f02b5549c552a9d7452e2027b4957de8595b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Marczyk?= Date: Wed, 30 May 2012 09:44:43 +0200 Subject: [PATCH 017/285] CLJ-1005: use transient map in zipmap Signed-off-by: Stuart Halloway --- src/clj/clojure/core.clj | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 3caf962296..caf79327de 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -3068,22 +3068,6 @@ (reduce1 merge-entry (or m1 {}) (seq m2)))] (reduce1 merge2 maps)))) - - -(defn zipmap - "Returns a map with the keys mapped to the corresponding vals." - {:added "1.0" - :static true} - [keys vals] - (loop [map {} - ks (seq keys) - vs (seq vals)] - (if (and ks vs) - (recur (assoc map (first ks) (first vs)) - (next ks) - (next vs)) - map))) - (defn line-seq "Returns the lines of text from rdr as a lazy sequence of strings. rdr must implement java.io.BufferedReader." @@ -6581,6 +6565,19 @@ fails, attempts to require sym's namespace and retries." ([a b c] (f (if (nil? a) x a) (if (nil? b) y b) (if (nil? c) z c))) ([a b c & ds] (apply f (if (nil? a) x a) (if (nil? b) y b) (if (nil? c) z c) ds))))) +(defn zipmap + "Returns a map with the keys mapped to the corresponding vals." + {:added "1.0" + :static true} + [keys vals] + (loop [map (transient {}) + ks (seq keys) + vs (seq vals)] + (if (and ks vs) + (recur (assoc! map (first ks) (first vs)) + (next ks) + (next vs)) + (persistent! map)))) ;;;;;;; case ;;;;;;;;;;;;; (defn- shift-mask [shift mask x] From af9f2ed34326a5f590f245155c73958e7a2dc17f Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 22 Oct 2020 14:34:35 -0500 Subject: [PATCH 018/285] CLJ-1445 pprint should print collection metadata when *print-meta* is true Signed-off-by: Stuart Halloway --- src/clj/clojure/pprint/dispatch.clj | 25 +++++++++++++++- .../test_clojure/pprint/test_pretty.clj | 29 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/clj/clojure/pprint/dispatch.clj b/src/clj/clojure/pprint/dispatch.clj index 1ef9a578b6..965c0b255a 100644 --- a/src/clj/clojure/pprint/dispatch.clj +++ b/src/clj/clojure/pprint/dispatch.clj @@ -62,8 +62,19 @@ ;;; are a little easier on the stack. (Or, do "real" compilation, a ;;; la Common Lisp) +(declare pprint-map) + +(defn- pprint-meta [obj] + (when *print-meta* + (when-let [m (meta obj)] + (.write ^java.io.Writer *out* "^") + (pprint-map m) + (.write ^java.io.Writer *out* " ") + (pprint-newline :linear)))) + ;;; (def pprint-simple-list (formatter-out "~:<~@{~w~^ ~_~}~:>")) (defn- pprint-simple-list [alis] + (pprint-meta alis) (pprint-logical-block :prefix "(" :suffix ")" (print-length-loop [alis (seq alis)] (when alis @@ -79,6 +90,7 @@ ;;; (def pprint-vector (formatter-out "~<[~;~@{~w~^ ~_~}~;]~:>")) (defn- pprint-vector [avec] + (pprint-meta avec) (pprint-logical-block :prefix "[" :suffix "]" (print-length-loop [aseq (seq avec)] (when aseq @@ -92,6 +104,7 @@ ;;; (def pprint-map (formatter-out "~<{~;~@{~<~w~^ ~_~w~:>~^, ~_~}~;}~:>")) (defn- pprint-map [amap] + (pprint-meta amap) (let [[ns lift-map] (when (not (record? amap)) (#'clojure.core/lift-ns amap)) amap (or lift-map amap) @@ -110,7 +123,17 @@ (pprint-newline :linear) (recur (next aseq)))))))) -(def ^{:private true} pprint-set (formatter-out "~<#{~;~@{~w~^ ~:_~}~;}~:>")) +;;; (def ^{:private true} pprint-set (formatter-out "~<#{~;~@{~w~^ ~:_~}~;}~:>")) +(defn- pprint-set [aset] + (pprint-meta aset) + (pprint-logical-block :prefix "#{" :suffix "}" + (print-length-loop [aseq (seq aset)] + (when aseq + (write-out (first aseq)) + (when (next aseq) + (.write ^java.io.Writer *out* " ") + (pprint-newline :linear) + (recur (next aseq))))))) (def ^{:private true} type-map {"core$future_call" "Future", diff --git a/test/clojure/test_clojure/pprint/test_pretty.clj b/test/clojure/test_clojure/pprint/test_pretty.clj index c9b321fdff..abdbcf1744 100644 --- a/test/clojure/test_clojure/pprint/test_pretty.clj +++ b/test/clojure/test_clojure/pprint/test_pretty.clj @@ -384,3 +384,32 @@ It is implemented with a number of custom enlive templates.\" ["#inst \"2014-04-29T14:00:00.000+00:00\""]) "calendar object pretty prints"))) +(deftest test-print-meta + (let [r (with-meta (range 25) {:b 2})] + (are [expected val] (= expected (with-out-str (binding [*print-meta* true] (pprint val)))) + "^{:a 1, :b 2} {:x 1, :y 2}\n" + ^{:a 1 :b 2} {:x 1 :y 2} + + "^{:a 1, :b 2}\n{:x\n ^{:b 2}\n (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24),\n :y 1}\n" + ^{:a 1 :b 2} {:x r :y 1} + + "^{:a 1} {:x ^{:foo true} {:y 2}}\n" + ^{:a 1} {:x ^:foo {:y 2}} + + "^{:a 1} [1 2 3 4]\n" + ^{:a 1} [1 2 3 4] + + "^{:a 1} [^{:b 2} [1 2]]\n" + ^{:a 1} [^{:b 2} [1 2]] + + "^{:a 1}\n[[[1\n ^{:b 2}\n (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24)]]]\n" + ^{:a 1} [[[1 ^{:b 2} r]]] + + "^{:line 409, :column 16} (1 2 3 4)\n" + ^{:a 1} '(1 2 3 4) + + "^{:a 1} (0 1 2 3)\n" + ^{:a 1} (with-meta (range 4) {:a 1}) + + "^{:a 1} #{1 4 3 2}\n" + ^{:a 1} #{1 2 3 4}))) \ No newline at end of file From 7529bc90a35eba940581311d7dfed21fec22b4f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Marczyk?= Date: Fri, 11 Dec 2020 10:45:41 -0600 Subject: [PATCH 019/285] CLJ-2169: add nullary, unary overloads of conj to its :arglists Signed-off-by: Stuart Halloway --- src/clj/clojure/core.clj | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index caf79327de..cf70fbecf6 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -73,10 +73,12 @@ rest (fn ^:static rest [x] (. clojure.lang.RT (more x)))) (def - ^{:arglists '([coll x] [coll x & xs]) + ^{:arglists '([] [coll] [coll x] [coll x & xs]) :doc "conj[oin]. Returns a new collection with the xs - 'added'. (conj nil item) returns (item). The 'addition' may - happen at different 'places' depending on the concrete type." + 'added'. (conj nil item) returns (item). + (conj coll) returns coll. (conj) returns []. + The 'addition' may happen at different 'places' depending + on the concrete type." :added "1.0" :static true} conj (fn ^:static conj From 2691ed3c04404ff87853b8eb1d7c4226b8a36634 Mon Sep 17 00:00:00 2001 From: Piotrek Zygielo Date: Thu, 20 Dec 2018 20:12:50 +0100 Subject: [PATCH 020/285] CLJ-2459 Set manifest.mainClass only in jar built in local profile Signed-off-by: Stuart Halloway --- pom.xml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/pom.xml b/pom.xml index 78784d3a4d..9e6d00231d 100644 --- a/pom.xml +++ b/pom.xml @@ -175,11 +175,6 @@ src/assembly/slim.xml - - - clojure.main - - @@ -187,13 +182,6 @@ maven-jar-plugin 2.3.1 - - - - clojure.main - - - maven-source-plugin From fed73d7737548883160cf73bd393a935047a8426 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 11 Dec 2020 10:40:32 -0600 Subject: [PATCH 021/285] CLJ-2495 Correct prepl docstring for exception :ret messages Signed-off-by: Stuart Halloway --- src/clj/clojure/core/server.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/core/server.clj b/src/clj/clojure/core/server.clj index c103888c7b..5808a45a74 100644 --- a/src/clj/clojure/core/server.clj +++ b/src/clj/clojure/core/server.clj @@ -195,11 +195,11 @@ Calls out-fn with data, one of: {:tag :ret - :val val ;;eval result + :val val ;;eval result, or Throwable->map data if exception thrown :ns ns-name-string :ms long ;;eval time in milliseconds :form string ;;iff successfully read - :clojure.error/phase (:execution et al per clojure.main/ex-triage) ;;iff error occurred + :exception true ;;iff exception thrown } {:tag :out :val string} ;chars from during-eval *out* From e0ac2d705e6bc365039952331750de27350bdc36 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 30 Oct 2020 13:45:59 -0500 Subject: [PATCH 022/285] CLJ-2585 - Fix index check in nth with not-found for regex matcher Signed-off-by: Stuart Halloway --- src/jvm/clojure/lang/RT.java | 3 ++- test/clojure/test_clojure/other_functions.clj | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index 997b525922..74399cf15f 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -965,7 +965,8 @@ else if(coll instanceof RandomAccess) { } else if(coll instanceof Matcher) { Matcher m = (Matcher) coll; - if(n < m.groupCount()) + int groups = m.groupCount(); + if(groups > 0 && n <= m.groupCount()) return m.group(n); return notFound; } diff --git a/test/clojure/test_clojure/other_functions.clj b/test/clojure/test_clojure/other_functions.clj index 958df5eca8..0f3093d183 100644 --- a/test/clojure/test_clojure/other_functions.clj +++ b/test/clojure/test_clojure/other_functions.clj @@ -348,6 +348,19 @@ ; Regex Support ; re-matcher re-find re-matches re-groups re-seq +(deftest test-regex-matcher + (let [matcher (re-matcher #"(\d{2})/(\d{2})/(\d{4})" "12/02/1975")] + (is (= ["12/02/1975" "12" "02" "1975"] (re-find matcher))) + (is (= ["12/02/1975" "12" "02" "1975"] (re-groups matcher))) + (is (= "12/02/1975" (nth matcher 0) (nth matcher 0 :foo))) + (is (= "12" (nth matcher 1) (nth matcher 1 :foo))) + (is (= "02" (nth matcher 2) (nth matcher 2 :foo))) + (is (= "1975" (nth matcher 3) (nth matcher 3 :foo))) + (is (thrown? IndexOutOfBoundsException (nth matcher -1))) + (is (= :foo (nth matcher -1 :foo))) + (is (thrown? IndexOutOfBoundsException (nth matcher 4))) + (is (= :foo (nth matcher 4 :foo))))) + ; update (deftest test-update From 0754746f476c4ddf6a6b699d9547830b2fdad17c Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 11 Dec 2020 11:32:53 -0600 Subject: [PATCH 023/285] changelog updates for 1.10.2 Signed-off-by: Stuart Halloway --- changes.md | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/changes.md b/changes.md index 9d041066d1..19cdae737a 100644 --- a/changes.md +++ b/changes.md @@ -1,5 +1,64 @@ +# Changes to Clojure in Version 1.10.2 + +## 1 Fixes + +## 1.1 Interop / JVM + +* [CLJ-1472](https://clojure.atlassian.net/browse/CLJ-1472) + Ensure monitor object is on stack, for verifiers +* [CLJ-2517](https://clojure.atlassian.net/browse/CLJ-2517) + More fixes for invocation of static interface methods with primitive args +* [CLJ-2492](https://clojure.atlassian.net/browse/CLJ-2492) + Remove uses of deprecated Class.newInstance() +* [CLJ-2534](https://clojure.atlassian.net/browse/CLJ-2534) + Fix javadoc urls for JDK 11+ +* [CLJ-2571](https://clojure.atlassian.net/browse/CLJ-2571) + Add Throwable return type hint to ex-cause +* [CLJ-2572](https://clojure.atlassian.net/browse/CLJ-2572) + Avoid reflection in clojure.data +* [CLJ-2502](https://clojure.atlassian.net/browse/CLJ-2502) + Fix reflection warnings in clojure.stacktrace/print-stack-trace + +## 1.2 Core + +* [CLJ-2580](https://clojure.atlassian.net/browse/CLJ-2580) + Fix case expression branch analysis that resulted in compilation error +* [CLJ-2564](https://clojure.atlassian.net/browse/CLJ-2564) + Improve error message for case +* [CLJ-2585](https://clojure.atlassian.net/browse/CLJ-2585) + nth with not-found on regex matcher returns not-found on last group index +* [CLJ-1364](https://clojure.atlassian.net/browse/CLJ-1364) + vector-of does not implement equals or hashing methods +* [CLJ-2549](https://clojure.atlassian.net/browse/CLJ-2549) + vector-of does not implement IObj for metadata +* [CLJ-1187](https://clojure.atlassian.net/browse/CLJ-1187) + quoted metadata on empty literal colls is lost +* [CLJ-2459](https://clojure.atlassian.net/browse/CLJ-2459) + ExceptionInInitializerError if jars executed with java -jar + +## 1.3 Printing + +* [CLJ-2469](https://clojure.atlassian.net/browse/CLJ-2469) + Fix errors in printing some maps with namespace syntax +* [CLJ-1445](https://clojure.atlassian.net/browse/CLJ-1445) + pprint doesn't print collection metadata when `*print-meta*` is true + +## 1.4 Docstrings + +* [CLJ-2295](https://clojure.atlassian.net/browse/CLJ-2295) + Eliminate duplicate doc string printing for special forms +* [CLJ-2495](https://clojure.atlassian.net/browse/CLJ-2495) + prepl docstring is incorrect +* [CLJ-2169](https://clojure.atlassian.net/browse/CLJ-2169) + conj has out-of-date :arglists + +## 2 Performance + +* [CLJ-1005](https://clojure.atlassian.net/browse/CLJ-1005) + Use transient map in zipmap + # Changes to Clojure in Version 1.10.1 ## 1 Features and Major Changes From 2a43b08fffc657aeb93a7afd6bc1d52d7942fcb8 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Fri, 11 Dec 2020 13:12:23 -0600 Subject: [PATCH 024/285] [maven-release-plugin] prepare release clojure-1.10.2-rc1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9e6d00231d..98c9ee8cac 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.2-master-SNAPSHOT + 1.10.2-rc1 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.10.2-rc1 From 0df3d8e2e27fb06fa53398754cac2be4878b12d1 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Fri, 11 Dec 2020 13:12:24 -0600 Subject: [PATCH 025/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 98c9ee8cac..9e6d00231d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.2-rc1 + 1.10.2-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.10.2-rc1 + HEAD From 675779bab430ad4d207c7384d007aa6ff4163141 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 4 Jan 2021 10:05:47 -0600 Subject: [PATCH 026/285] CLJ-2597 Proxy should emit Java 1.8 bytecode Signed-off-by: Stuart Halloway --- src/clj/clojure/core_proxy.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/core_proxy.clj b/src/clj/clojure/core_proxy.clj index cacd2dce52..c7f35774e6 100644 --- a/src/clj/clojure/core_proxy.clj +++ b/src/clj/clojure/core_proxy.clj @@ -46,7 +46,7 @@ [(Integer/toHexString (hash inames))]))))) (defn- generate-proxy [^Class super interfaces] - (let [cv (new ClassWriter (. ClassWriter COMPUTE_MAXS)) + (let [cv (clojure.lang.Compiler/classWriter) pname (proxy-name super interfaces) cname (.replace pname \. \/) ;(str "clojure/lang/" (gensym "Proxy__")) ctype (. Type (getObjectType cname)) @@ -131,7 +131,7 @@ (. gen (endMethod))))] ;start class definition - (. cv (visit (. Opcodes V1_5) (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_SUPER)) + (. cv (visit (. Opcodes V1_8) (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_SUPER)) cname nil (iname super) (into-array (map iname (cons IProxy interfaces))))) ;add field for fn mappings From 62b5f3687941d53699004849d6699495e7b89439 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 5 Jan 2021 10:30:45 -0600 Subject: [PATCH 027/285] Update deps to spec.alpha 0.2.194 and core.specs.alpha 0.2.56 Signed-off-by: Stuart Halloway --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9e6d00231d..5d2057e0b2 100644 --- a/pom.xml +++ b/pom.xml @@ -41,12 +41,12 @@ org.clojure spec.alpha - 0.2.187 + 0.2.194 org.clojure core.specs.alpha - 0.2.44 + 0.2.56 org.clojure From 6234c09f991dceaeeb039e7db93b460646b02980 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 5 Jan 2021 11:03:48 -0600 Subject: [PATCH 028/285] 1.10.2-rc2 changelog updates Signed-off-by: Stuart Halloway --- changes.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/changes.md b/changes.md index 19cdae737a..daab2c3478 100644 --- a/changes.md +++ b/changes.md @@ -2,9 +2,16 @@ # Changes to Clojure in Version 1.10.2 -## 1 Fixes +## 1 Dependencies -## 1.1 Interop / JVM +Updated dependencies: + +* spec.alpha dependency to 0.2.194 - [changes](https://github.com/clojure/spec.alpha/blob/master/CHANGES.md) +* core.specs.alpha dependency to 0.2.56 - [changes](https://github.com/clojure/core.specs.alpha/blob/master/CHANGES.md) + +## 2 Fixes + +## 2.1 Interop / JVM * [CLJ-1472](https://clojure.atlassian.net/browse/CLJ-1472) Ensure monitor object is on stack, for verifiers @@ -20,8 +27,10 @@ Avoid reflection in clojure.data * [CLJ-2502](https://clojure.atlassian.net/browse/CLJ-2502) Fix reflection warnings in clojure.stacktrace/print-stack-trace +* [CLJ-2597](https://clojure.atlassian.net/browse/CLJ-2597) + proxy should emit Java 1.8 bytecode -## 1.2 Core +## 2.2 Core * [CLJ-2580](https://clojure.atlassian.net/browse/CLJ-2580) Fix case expression branch analysis that resulted in compilation error @@ -38,14 +47,14 @@ * [CLJ-2459](https://clojure.atlassian.net/browse/CLJ-2459) ExceptionInInitializerError if jars executed with java -jar -## 1.3 Printing +## 2.3 Printing * [CLJ-2469](https://clojure.atlassian.net/browse/CLJ-2469) Fix errors in printing some maps with namespace syntax * [CLJ-1445](https://clojure.atlassian.net/browse/CLJ-1445) pprint doesn't print collection metadata when `*print-meta*` is true -## 1.4 Docstrings +## 2.4 Docstrings * [CLJ-2295](https://clojure.atlassian.net/browse/CLJ-2295) Eliminate duplicate doc string printing for special forms @@ -54,7 +63,7 @@ * [CLJ-2169](https://clojure.atlassian.net/browse/CLJ-2169) conj has out-of-date :arglists -## 2 Performance +## 3 Performance * [CLJ-1005](https://clojure.atlassian.net/browse/CLJ-1005) Use transient map in zipmap From 9939292fc04d69440b329c13d17646fed415bc7e Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Wed, 6 Jan 2021 11:54:49 -0600 Subject: [PATCH 029/285] [maven-release-plugin] prepare release clojure-1.10.2-rc2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5d2057e0b2..f244ee159a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.2-master-SNAPSHOT + 1.10.2-rc2 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.10.2-rc2 From 57ac70c904e8250f0bd4e084272659aeeb8749c6 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Wed, 6 Jan 2021 11:54:50 -0600 Subject: [PATCH 030/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f244ee159a..5d2057e0b2 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.2-rc2 + 1.10.2-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.10.2-rc2 + HEAD From 1f2cc45f77bb981f82d36177790477d21d8e9f79 Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Sun, 10 Jan 2021 13:46:06 -0800 Subject: [PATCH 031/285] CLJ-TBD: Modify tests slightly to pass with Windows newlines Signed-off-by: Andy Fingerhut Signed-off-by: Stuart Halloway --- test/clojure/test_clojure/main.clj | 2 +- test/clojure/test_clojure/pprint/test_pretty.clj | 8 ++++---- test/clojure/test_clojure/printer.clj | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/test/clojure/test_clojure/main.clj b/test/clojure/test_clojure/main.clj index 31bec96659..5909672c8c 100644 --- a/test/clojure/test_clojure/main.clj +++ b/test/clojure/test_clojure/main.clj @@ -56,7 +56,7 @@ (.setStackTrace (into-array java.lang.StackTraceElement nil))) tr-data (-> e Throwable->map main/ex-triage)] (is (= tr-data #:clojure.error{:phase :execution, :class 'java.lang.Error, :cause "xyz"})) - (is (= (main/ex-str tr-data) "Execution error (Error) at (REPL:1).\nxyz\n")))) + (is (= (main/ex-str tr-data) (platform-newlines "Execution error (Error) at (REPL:1).\nxyz\n"))))) (defn s->lpr [s] diff --git a/test/clojure/test_clojure/pprint/test_pretty.clj b/test/clojure/test_clojure/pprint/test_pretty.clj index abdbcf1744..4d31a21396 100644 --- a/test/clojure/test_clojure/pprint/test_pretty.clj +++ b/test/clojure/test_clojure/pprint/test_pretty.clj @@ -385,12 +385,12 @@ It is implemented with a number of custom enlive templates.\" "calendar object pretty prints"))) (deftest test-print-meta - (let [r (with-meta (range 25) {:b 2})] - (are [expected val] (= expected (with-out-str (binding [*print-meta* true] (pprint val)))) + (let [r (with-meta (range 24) {:b 2})] + (are [expected val] (= (platform-newlines expected) (with-out-str (binding [*print-meta* true] (pprint val)))) "^{:a 1, :b 2} {:x 1, :y 2}\n" ^{:a 1 :b 2} {:x 1 :y 2} - "^{:a 1, :b 2}\n{:x\n ^{:b 2}\n (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24),\n :y 1}\n" + "^{:a 1, :b 2}\n{:x\n ^{:b 2}\n (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23),\n :y 1}\n" ^{:a 1 :b 2} {:x r :y 1} "^{:a 1} {:x ^{:foo true} {:y 2}}\n" @@ -402,7 +402,7 @@ It is implemented with a number of custom enlive templates.\" "^{:a 1} [^{:b 2} [1 2]]\n" ^{:a 1} [^{:b 2} [1 2]] - "^{:a 1}\n[[[1\n ^{:b 2}\n (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24)]]]\n" + "^{:a 1}\n[[[1\n ^{:b 2}\n (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23)]]]\n" ^{:a 1} [[[1 ^{:b 2} r]]] "^{:line 409, :column 16} (1 2 3 4)\n" diff --git a/test/clojure/test_clojure/printer.clj b/test/clojure/test_clojure/printer.clj index e5b3796699..ffb3007138 100644 --- a/test/clojure/test_clojure/printer.clj +++ b/test/clojure/test_clojure/printer.clj @@ -14,7 +14,8 @@ ;; Created 29 October 2008 (ns clojure.test-clojure.printer - (:use clojure.test) + (:use clojure.test + [clojure.test-helper :only [platform-newlines]]) (:require [clojure.pprint :refer [pprint]])) (deftest print-length-empty-seq @@ -138,7 +139,7 @@ (deftest print-ns-maps (are [m s-on pp-on s-off] (and (= s-on (binding [*print-namespace-maps* true] (pr-str m))) - (= pp-on (binding [*print-namespace-maps* true] (with-out-str (pprint m)))) + (= (platform-newlines pp-on) (binding [*print-namespace-maps* true] (with-out-str (pprint m)))) (= s-off (binding [*print-namespace-maps* false] (pr-str m)))) {} "{}" "{}\n" "{}" {:a 1, :b 2} "{:a 1, :b 2}" "{:a 1, :b 2}\n" "{:a 1, :b 2}" From 3da30b145f8843c9502f75718f4dfc374d14a7e0 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Fri, 15 Jan 2021 12:50:54 -0600 Subject: [PATCH 032/285] [maven-release-plugin] prepare release clojure-1.10.2-rc3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5d2057e0b2..9840eff495 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.2-master-SNAPSHOT + 1.10.2-rc3 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.10.2-rc3 From c1ede7899d8d7dd4dcd6072d5c0f072b9b2be391 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Fri, 15 Jan 2021 12:50:54 -0600 Subject: [PATCH 033/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9840eff495..5d2057e0b2 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.2-rc3 + 1.10.2-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.10.2-rc3 + HEAD From 5d19d0ecc2265b6b2e7b4e4895b316af8407a27c Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Tue, 26 Jan 2021 12:54:43 -0600 Subject: [PATCH 034/285] [maven-release-plugin] prepare release clojure-1.10.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5d2057e0b2..ceca6d5e84 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.2-master-SNAPSHOT + 1.10.2 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.10.2 From 140ed11e905de46331de705e955c50c0ef79095b Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Tue, 26 Jan 2021 12:54:43 -0600 Subject: [PATCH 035/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ceca6d5e84..5a584bc3c0 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.2 + 1.11.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.10.2 + HEAD From d782811a32aeb21df50580435801f17803af1e94 Mon Sep 17 00:00:00 2001 From: Oliver Caldwell Date: Wed, 19 Dec 2018 09:20:59 +0000 Subject: [PATCH 036/285] CLJ-2453 Allow reader conditionals in prepl Signed-off-by: Stuart Halloway --- src/clj/clojure/core/server.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clj/clojure/core/server.clj b/src/clj/clojure/core/server.clj index 5808a45a74..f343aa76fe 100644 --- a/src/clj/clojure/core/server.clj +++ b/src/clj/clojure/core/server.clj @@ -226,7 +226,7 @@ (add-tap tapfn) (loop [] (when (try - (let [[form s] (read+string in-reader false EOF)] + (let [[form s] (read+string {:eof EOF :read-cond :allow} in-reader)] (try (when-not (identical? form EOF) (let [start (System/nanoTime) From 17ae75eadbb93152e460cd156adeb7876e616631 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 11 Feb 2021 11:12:13 -0600 Subject: [PATCH 037/285] Revert "CLJ-2564 Improve error message for `case`" This reverts commit f25f3e297817803528e6c0ea46242c45a8d8e6fe. Signed-off-by: Stuart Halloway --- src/clj/clojure/core.clj | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index cf70fbecf6..2c7334febc 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -6695,9 +6695,6 @@ fails, attempts to require sym's namespace and retries." (into1 #{} (map #(shift-mask shift mask %) skip-check)))] [shift mask case-map switch-type skip-check])))) -(defn case-fallthrough-err-impl - [val] - (IllegalArgumentException. (str "No matching clause: " (pr-str val)))) (defmacro case "Takes an expression, and a set of clauses. @@ -6728,7 +6725,7 @@ fails, attempts to require sym's namespace and retries." (let [ge (with-meta (gensym) {:tag Object}) default (if (odd? (count clauses)) (last clauses) - `(throw (case-fallthrough-err-impl ~ge)))] + `(throw (IllegalArgumentException. (str "No matching clause: " ~ge))))] (if (> 2 (count clauses)) `(let [~ge ~e] ~default) (let [pairs (partition 2 clauses) From 7ce8f29069b598bd979ed7d8c3ff95a6762e3372 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 11 Feb 2021 11:18:16 -0600 Subject: [PATCH 038/285] changelog for 1.10.3 Signed-off-by: Stuart Halloway --- changes.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/changes.md b/changes.md index daab2c3478..4df7e28540 100644 --- a/changes.md +++ b/changes.md @@ -1,5 +1,17 @@ +# Changes to Clojure in Version 1.10.3 + +## 1 Changes reverted + +* [CLJ-2564](https://clojure.atlassian.net/browse/CLJ-2564) + Improve error message for case + +## 2 Fixes + +* [CLJ-2453](https://clojure.atlassian.net/browse/CLJ-2453) + Enable reader conditionals in Clojure prepl + # Changes to Clojure in Version 1.10.2 ## 1 Dependencies From 671bfee2819bc9c53c699d232413e22135007ea7 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Tue, 16 Feb 2021 08:57:59 -0600 Subject: [PATCH 039/285] [maven-release-plugin] prepare release clojure-1.10.3-rc1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5a584bc3c0..3f20b7f319 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.11.0-master-SNAPSHOT + 1.10.3-rc1 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.10.3-rc1 From ecd5ff59e07de649a9f9affb897d02165fe7e553 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Tue, 16 Feb 2021 08:57:59 -0600 Subject: [PATCH 040/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3f20b7f319..5a584bc3c0 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.3-rc1 + 1.11.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.10.3-rc1 + HEAD From aaf73b12467df80f5db3e086550a33fee0e1b39e Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Thu, 4 Mar 2021 09:41:25 -0600 Subject: [PATCH 041/285] [maven-release-plugin] prepare release clojure-1.10.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5a584bc3c0..300eaff009 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.11.0-master-SNAPSHOT + 1.10.3 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.10.3 From 57f7c6ea164271d92cec5a12d22043c7029e3de2 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Thu, 4 Mar 2021 09:41:25 -0600 Subject: [PATCH 042/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 300eaff009..675fcd196d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.10.3 + 1.11.1-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.10.3 + HEAD From 3c9307e27479d450e3f1cdf7903458b83ebf52d7 Mon Sep 17 00:00:00 2001 From: Fogus Date: Thu, 18 Mar 2021 08:06:18 -0400 Subject: [PATCH 043/285] CLJ-2603: Added support for trailing, conj-able element in map-destructuring support for seqs. Moved to use of PersistentArrayMap/createAsIfByAssoc in map destructuring context. Modified docstrings for let and fn to add mention of destructuring forms. Finally, added seq-to-map-for-destructuring to help developers get the same behavior in their own macros. Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 37 +++++++++--- src/jvm/clojure/lang/ArraySeq.java | 7 +++ src/jvm/clojure/lang/PersistentArrayMap.java | 56 ++++++++++++++++++- test/clojure/test_clojure/data_structures.clj | 31 ++++++++++ 4 files changed, 122 insertions(+), 9 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 2c7334febc..b27dff8145 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -4371,7 +4371,19 @@ :static true} ([] (. clojure.lang.PersistentArrayMap EMPTY)) ([& keyvals] - (clojure.lang.PersistentArrayMap/createAsIfByAssoc (to-array keyvals)))) + (let [ary (to-array keyvals)] + (if (odd? (alength ary)) + (throw (IllegalArgumentException. (str "No value supplied for key: " (last keyvals)))) + (clojure.lang.PersistentArrayMap/createAsIfByAssoc ary))))) + +(defn seq-to-map-for-destructuring + "Builds a map from a seq as described in + https://clojure.org/reference/special_forms#keyword-arguments" + {:added "1.11"} + [s] + (if (next s) + (clojure.lang.PersistentArrayMap/createAsIfByAssoc (to-array s)) + (if (seq s) (first s) clojure.lang.PersistentArrayMap/EMPTY))) ;;redefine let and loop with destructuring (defn destructure [bindings] @@ -4419,7 +4431,11 @@ gmapseq (with-meta gmap {:tag 'clojure.lang.ISeq}) defaults (:or b)] (loop [ret (-> bvec (conj gmap) (conj v) - (conj gmap) (conj `(if (seq? ~gmap) (clojure.lang.PersistentHashMap/create (seq ~gmapseq)) ~gmap)) + (conj gmap) (conj `(if (seq? ~gmap) + (if (next ~gmapseq) + (clojure.lang.PersistentArrayMap/createAsIfByAssoc (to-array ~gmapseq)) + (if (seq ~gmapseq) (first ~gmapseq) clojure.lang.PersistentArrayMap/EMPTY)) + ~gmap)) ((fn [ret] (if (:as b) (conj ret (:as b) gmap) @@ -4468,10 +4484,15 @@ (defmacro let "binding => binding-form init-expr + binding-form => name, or destructuring-form + destructuring-form => map-destructure-form, or seq-destructure-form Evaluates the exprs in a lexical context in which the symbols in the binding-forms are bound to their respective init-exprs or parts - therein." + therein. + + See https://clojure.org/reference/special_forms#binding-forms for + more information about destructuring." {:added "1.0", :special-form true, :forms '[(let [bindings*] exprs*)]} [bindings & body] (assert-args @@ -4499,12 +4520,14 @@ ;redefine fn with destructuring and pre/post conditions (defmacro fn - "params => positional-params* , or positional-params* & next-param + "params => positional-params*, or positional-params* & rest-param positional-param => binding-form - next-param => binding-form - name => symbol + rest-param => binding-form + binding-form => name, or destructuring-form + + Defines a function. - Defines a function" + See https://clojure.org/reference/special_forms#fn for more information" {:added "1.0", :special-form true, :forms '[(fn name? [params* ] exprs*) (fn name? ([params* ] exprs*)+)]} [& sigs] diff --git a/src/jvm/clojure/lang/ArraySeq.java b/src/jvm/clojure/lang/ArraySeq.java index 597a5410de..49a74b660d 100644 --- a/src/jvm/clojure/lang/ArraySeq.java +++ b/src/jvm/clojure/lang/ArraySeq.java @@ -142,6 +142,13 @@ public int lastIndexOf(Object o) { return -1; } +public Object[] toArray(){ + int sz = this.array.length - this.i; + Object[] ret = new Object[sz]; + System.arraycopy(this.array, i, ret, 0, sz); + return ret; +} + //////////////////////////////////// specialized primitive versions /////////////////////////////// static public class ArraySeq_int extends ASeq implements IndexedSeq, IReduce{ diff --git a/src/jvm/clojure/lang/PersistentArrayMap.java b/src/jvm/clojure/lang/PersistentArrayMap.java index 27b860e5d5..1f86fd80aa 100644 --- a/src/jvm/clojure/lang/PersistentArrayMap.java +++ b/src/jvm/clojure/lang/PersistentArrayMap.java @@ -76,9 +76,61 @@ static public PersistentArrayMap createWithCheck(Object[] init){ return new PersistentArrayMap(init); } +/** + *

This method attempts to find resue the given array as the basis for an array map as quickly as possible.

+ * + *

If a trailing element exists in the array or it contains duplicate keys then it delegates to the complex path.

+ **/ static public PersistentArrayMap createAsIfByAssoc(Object[] init){ - if ((init.length & 1) == 1) - throw new IllegalArgumentException(String.format("No value supplied for key: %s", init[init.length-1])); + boolean complexPath, hasTrailing; + complexPath = hasTrailing = ((init.length & 1) == 1); + + for(int i=0;((i< init.length) && !complexPath);i += 2) + { + for(int j=0;jThis method handles the default case of an array containing alternating key/value pairs.

+ *

It will reallocate a smaller init array if duplicate keys are found.

+ * + *

If a trailing element is found then will attempt to add it to the resulting map as if by conj.

+ *

No guarantees about the order of the keys in the trailing element are made.

+ **/ +private static PersistentArrayMap createAsIfByAssocComplexPath(Object[] init, boolean hasTrailing){ + if(hasTrailing) + { + IPersistentCollection trailing = PersistentArrayMap.EMPTY.cons(init[init.length-1]); + init = growSeedArray(init, trailing); + } + // If this looks like it is doing busy-work, it is because it // is achieving these goals: O(n^2) run time like // createWithCheck(), never modify init arg, and only diff --git a/test/clojure/test_clojure/data_structures.clj b/test/clojure/test_clojure/data_structures.clj index 69baf137c6..854560466b 100644 --- a/test/clojure/test_clojure/data_structures.clj +++ b/test/clojure/test_clojure/data_structures.clj @@ -1330,3 +1330,34 @@ (is (= (hash (->Rec 1 1)) (hash (assoc r :a 1)))) (is (= (hash (->Rec 1 1)) (hash (dissoc r2 :c)))) (is (= (hash (->Rec 1 1)) (hash (dissoc (assoc r :c 1) :c)))))) + +(deftest singleton-map-in-destructure-context + (let [sample-map {:a 1 :b 2} + {:keys [a] :as m1} (list sample-map)] + (is (= m1 sample-map)) + (is (= a 1)))) + +(deftest trailing-map-destructuring + (let [sample-map {:a 1 :b 2} + add (fn [& {:keys [a b]}] (+ a b)) + addn (fn [n & {:keys [a b]}] (+ n a b))] + (testing "that kwargs are applied properly given a map in place of the key/val pairs" + (is (= 3 (add :a 1 :b 2))) + (is (= 3 (add {:a 1 :b 2}))) + (is (= 13 (addn 10 :a 1 :b 2))) + (is (= 13 (addn 10 {:a 1 :b 2}))) + (is (= 103 ((partial addn 100) :a 1 {:b 2}))) + (is (= 103 ((partial addn 100 :a 1) {:b 2}))) + (is (= 107 ((partial addn 100 :a 1) {:a 5 :b 2})))) + (testing "built maps" + (let [{:as m1} (list :a 1 :b 2) + {:as m2} (list :a 1 :b 2 {:c 3}) + {:as m3} (list :a 1 :b 2 {:a 0}) + {:keys [a4] :as m4} (list nil)] + (= m1 {:a 1 :b 2}) + (= m2 {:a 1 :b 2 :c 3}) + (= m3 {:a 0 :b 2}) + (= m1 (seq-to-map-for-destructuring (list :a 1 :b 2))) + (= m2 (seq-to-map-for-destructuring (list :a 1 :b 2 {:c 3}))) + (= m3 (seq-to-map-for-destructuring (list :a 1 :b 2 {:a 0}))) + (= a4 nil))))) From 9249412dbd7e761670c4f05b399a10460230707d Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 18 Mar 2021 13:57:21 -0500 Subject: [PATCH 044/285] update release plugin versions --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 675fcd196d..86f4c48ff8 100644 --- a/pom.xml +++ b/pom.xml @@ -207,7 +207,7 @@ instead, push SCM changes in Hudson configuration --> org.apache.maven.plugins maven-release-plugin - 2.4.1 + 2.5.3 false true @@ -227,7 +227,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.7 + 1.6.8 true From af60514c308abee051e3cb6e3ee16a69c6272ed5 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Thu, 18 Mar 2021 14:00:50 -0500 Subject: [PATCH 045/285] [maven-release-plugin] prepare release clojure-1.11.0-alpha1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 86f4c48ff8..00aaed878d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.11.1-master-SNAPSHOT + 1.11.0-alpha1 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.11.0-alpha1 From b1b88dd25373a86e41310a525a21b497799dbbf2 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Thu, 18 Mar 2021 14:00:50 -0500 Subject: [PATCH 046/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 00aaed878d..efb331d86a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.11.0-alpha1 + 1.11.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.11.0-alpha1 + HEAD From a29f9b911b569b0a4890f320ec8f946329bbe0fd Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 24 Jun 2021 13:35:59 -0500 Subject: [PATCH 047/285] refresh contributing and add pull request template --- .github/PULL_REQUEST_TEMPLATE | 5 ++++ CONTRIBUTING.md | 43 ++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 .github/PULL_REQUEST_TEMPLATE diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE new file mode 100644 index 0000000000..31b549a89c --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE @@ -0,0 +1,5 @@ +Hi! This project does not accept pull requests. + +Please see the guidelines for contribution on how to file issues or provide patches: + +https://github.com/clojure/clojure/blob/master/CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 06b2fc0581..84f0aee84b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1 +1,42 @@ -If you'd like to submit a patch, please follow the [contributing guidelines](http://clojure.org/contributing). +Hi! Thanks for your interest in Clojure! + +## I want to ask a question + +If you have a question about Clojure, please use the official Ask Clojure forum at https://ask.clojure.org. This forum is monitored by the Clojure maintainers. + +## I want to discuss an idea + +There are many interactive Clojure forums for discussion and you can find a list at [Clojure Discussion](https://clojure.org/community/resources#_clojure_discussion). + +## I want to file a bug / suggest an enhancement + +Please file it as a question on https://ask.clojure.org with the tag "problem" (possible bugs) or "request" (enhancements). + +## I want to provide a patch / PR + +If you would like to contribute patches, the Clojure dev process is described in detail at https://clojure.org/dev. + +In short, this process requires: + +- [Signing the Contributor Agreement](https://clojure.org/dev/contributor_agreement) +- [Requesting jira access](https://clojure.atlassian.net/servicedesk/customer/portal/1) + +This project does not accept pull requests. + +## I am looking for official documentation + +You can find official documentation on the Clojure web site: + +* Reference docs https://clojure.org/reference +* Tutorials and guides: https://clojure.org/guides +* API: https://clojure.org/api/api + +## What release should I use? + +Find the current release info here: + +https://clojure.org/releases/downloads + +A list of all releases can be found here: + +https://clojure.org/releases/downloads_older From f96eef2892eaef55dbbdbf7f3b4b818be06f6ddd Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 14 Sep 2021 08:24:35 -0500 Subject: [PATCH 048/285] CLJ-2123 Add :as-alias option to require like :as but does not load Signed-off-by: Alex Miller --- build.xml | 2 +- src/clj/clojure/core.clj | 35 +++++++++++------ test/clojure/test_clojure/ns_libs.clj | 38 +++++++++++++++++++ .../test_clojure/ns_libs_load_later.clj | 12 ++++++ 4 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 test/clojure/test_clojure/ns_libs_load_later.clj diff --git a/build.xml b/build.xml index 4d29bbf9a2..fd03afb417 100644 --- a/build.xml +++ b/build.xml @@ -113,7 +113,7 @@ unless="maven.test.skip"> + value="#{clojure.test-clojure.compilation.load-ns clojure.test-clojure.ns-libs-load-later}"/> diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index b27dff8145..8a94de15bf 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -5945,7 +5945,7 @@ (name lib) prefix) (let [lib (if prefix (symbol (str prefix \. lib)) lib) opts (apply hash-map options) - {:keys [as reload reload-all require use verbose]} opts + {:keys [as reload reload-all require use verbose as-alias]} opts loaded (contains? @*loaded-libs* lib) load (cond reload-all load-all @@ -5955,21 +5955,28 @@ filter-opts (select-keys opts '(:exclude :only :rename :refer)) undefined-on-entry (not (find-ns lib))] (binding [*loading-verbosely* (or *loading-verbosely* verbose)] - (if load - (try - (load lib need-ns require) - (catch Exception e - (when undefined-on-entry - (remove-ns lib)) - (throw e))) - (throw-if (and need-ns (not (find-ns lib))) - "namespace '%s' not found" lib)) + (if as-alias + (when (not (find-ns lib)) + (create-ns lib)) + (if load + (try + (load lib need-ns require) + (catch Exception e + (when undefined-on-entry + (remove-ns lib)) + (throw e))) + (throw-if (and need-ns (not (find-ns lib))) + "namespace '%s' not found" lib))) (when (and need-ns *loading-verbosely*) (printf "(clojure.core/in-ns '%s)\n" (ns-name *ns*))) (when as (when *loading-verbosely* (printf "(clojure.core/alias '%s '%s)\n" as lib)) (alias as lib)) + (when as-alias + (when *loading-verbosely* + (printf "(clojure.core/alias '%s '%s)\n" as-alias lib)) + (alias as-alias lib)) (when (or use (:refer filter-opts)) (when *loading-verbosely* (printf "(clojure.core/refer '%s" lib) @@ -5986,7 +5993,7 @@ opts (interleave flags (repeat true)) args (filter (complement keyword?) args)] ; check for unsupported options - (let [supported #{:as :reload :reload-all :require :use :verbose :refer} + (let [supported #{:as :reload :reload-all :require :use :verbose :refer :as-alias} unsupported (seq (remove supported flags))] (throw-if unsupported (apply str "Unsupported option(s) supplied: " @@ -6050,6 +6057,9 @@ Recognized options: :as takes a symbol as its argument and makes that symbol an alias to the lib's namespace in the current namespace. + :as-alias takes a symbol as its argument and aliases like :as, however + the lib will not be loaded. If the lib has not been loaded, a new + empty namespace will be created (as with create-ns). :refer takes a list of symbols to refer from the namespace or the :all keyword to bring in all public vars. @@ -6066,9 +6076,10 @@ A flag is a keyword. Recognized flags: :reload, :reload-all, :verbose :reload forces loading of all the identified libs even if they are - already loaded + already loaded (has no effect on libspecs using :as-alias) :reload-all implies :reload and also forces loading of all libs that the identified libs directly or indirectly load via require or use + (has no effect on libspecs using :as-alias) :verbose triggers printing information about each load, alias, and refer Example: diff --git a/test/clojure/test_clojure/ns_libs.clj b/test/clojure/test_clojure/ns_libs.clj index 0e470d7394..a9f4f97f71 100644 --- a/test/clojure/test_clojure/ns_libs.clj +++ b/test/clojure/test_clojure/ns_libs.clj @@ -103,3 +103,41 @@ (is (thrown-with-cause-msg? clojure.lang.Compiler$CompilerException #"defrecord and deftype fields must be symbols, user\.MyType had: :key1" (eval '(deftype MyType [:key1]))))) + +(deftest require-as-alias + ;; :as-alias does not load + (require '[not.a.real.ns [foo :as-alias foo] + [bar :as-alias bar]]) + (let [aliases (ns-aliases *ns*) + foo-ns (get aliases 'foo) + bar-ns (get aliases 'bar)] + (is (= 'not.a.real.ns.foo (ns-name foo-ns))) + (is (= 'not.a.real.ns.bar (ns-name bar-ns)))) + + (is (= :not.a.real.ns.foo/baz (read-string "::foo/baz"))) + + ;; can use :as-alias in use + (use '[dummy.example1 :as-alias e1]) + (let [aliases (ns-aliases *ns*)] + (is (= 'dummy.example1 (ns-name (get aliases 'e1))))) + + ;; can use both :as and :as-alias + (require '[clojure.set :as n1 :as-alias n2]) + (let [aliases (ns-aliases *ns*)] + (is (= 'clojure.set (ns-name (get aliases 'n1)))) + (is (= 'clojure.set (ns-name (get aliases 'n2)))))) + +(deftest require-as-alias-then-load-later + ;; alias but don't load + (require '[clojure.test-clojure.ns-libs-load-later :as-alias alias-now]) + (is (contains? (ns-aliases *ns*) 'alias-now)) + (is (not (nil? (find-ns 'clojure.test-clojure.ns-libs-load-later)))) + + ;; not loaded! + (is (nil? (resolve 'alias-now/example))) + + ;; load + (require 'clojure.test-clojure.ns-libs-load-later) + + ;; now loaded! + (is (not (nil? (resolve 'alias-now/example))))) \ No newline at end of file diff --git a/test/clojure/test_clojure/ns_libs_load_later.clj b/test/clojure/test_clojure/ns_libs_load_later.clj new file mode 100644 index 0000000000..2a45b86ab9 --- /dev/null +++ b/test/clojure/test_clojure/ns_libs_load_later.clj @@ -0,0 +1,12 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. + +;; used by clojure.test-clojure.ns-libs/require-as-alias-then-load-later +(ns clojure.test-clojure.ns-libs-load-later) + +(defn example [] true) From 709397c300b6d5a2258c9568dda898577e74ad0c Mon Sep 17 00:00:00 2001 From: Fogus Date: Tue, 7 Sep 2021 13:09:25 -0400 Subject: [PATCH 049/285] CLJ-2651: Added implementation of update-vals and tests. Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 16 ++++++++++++++++ test/clojure/test_clojure/other_functions.clj | 9 +++++++++ 2 files changed, 25 insertions(+) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 8a94de15bf..1b1da5c215 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -7926,3 +7926,19 @@ fails, attempts to require sym's namespace and retries." [x] (force tap-loop) (.offer tapq (if (nil? x) ::tap-nil x))) + +(defn update-vals + "m f => {k (f v) ...} + + Given a map m and a function f of 1-argument, returns a new map where the keys of m + are mapped to result of applying f to the corresponding values of m." + {:added "1.11"} + [m f] + (with-meta + (persistent! + (reduce-kv (fn [acc k v] (assoc! acc k (f v))) + (if (instance? clojure.lang.IEditableCollection m) + (transient m) + (transient {})) + m)) + (meta m))) diff --git a/test/clojure/test_clojure/other_functions.clj b/test/clojure/test_clojure/other_functions.clj index 0f3093d183..e0f7beede6 100644 --- a/test/clojure/test_clojure/other_functions.clj +++ b/test/clojure/test_clojure/other_functions.clj @@ -379,3 +379,12 @@ ;; rest arity {:a 5} (update {:a 1} :a + 1 1 1 1) {:a 6} (update {:a 1} :a + 1 1 1 1 1))) + +(deftest test-update-vals + (let [inm (with-meta {:a 1 :b 2} {:has :meta})] + (are [result expr] (= result expr) + {:a 2 :b 3} (update-vals inm inc) + {:has :meta} (meta (update-vals inm inc)) + {0 2 2 4} (update-vals (hash-map 0 1 2 3) inc) + {0 2 2 4} (update-vals (array-map 0 1 2 3) inc) + {0 2 2 4} (update-vals (sorted-map 2 3 0 1) inc)))) From b0ca4b8056b1718b16d31b89910a03be4b0187cd Mon Sep 17 00:00:00 2001 From: "Howard M. Lewis Ship" Date: Fri, 1 Apr 2016 14:36:24 -0700 Subject: [PATCH 050/285] CLJ-1098: Add clojure.test api to run single test with fixtures and report Signed-off-by: Alex Miller --- src/clj/clojure/test.clj | 35 +++++++++++++++++++ test/clojure/test_clojure/run_single_test.clj | 33 +++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 test/clojure/test_clojure/run_single_test.clj diff --git a/src/clj/clojure/test.clj b/src/clj/clojure/test.clj index fcb3224846..30aae631b2 100644 --- a/src/clj/clojure/test.clj +++ b/src/clj/clojure/test.clj @@ -793,3 +793,38 @@ [summary] (and (zero? (:fail summary 0)) (zero? (:error summary 0)))) + +(defn run-test-var + "Runs the tests for a single Var, with fixtures executed around the test, and summary output after." + {:added "1.9"} + [v] + (binding [*report-counters* (ref *initial-report-counters*)] + (let [ns-obj (-> v meta :ns) + summary (do + (do-report {:type :begin-test-ns + :ns ns-obj}) + (test-vars [v]) + (do-report {:type :end-test-ns + :ns ns-obj}) + (assoc @*report-counters* :type :summary))] + (do-report summary) + summary))) + +(defmacro run-test + "Runs a single test. + + Because the intent is to run a single test, there is no check for the namespace test-ns-hook." + {:added "1.9"} + [test-symbol] + (let [test-var (resolve test-symbol)] + (cond + (nil? test-var) + (binding [*out* *err*] + (println "Unable to resolve" test-symbol "to a test function.")) + + (not (-> test-var meta :test)) + (binding [*out* *err*] + (println test-symbol "is not a test.")) + + :else + `(run-test-var ~test-var)))) diff --git a/test/clojure/test_clojure/run_single_test.clj b/test/clojure/test_clojure/run_single_test.clj new file mode 100644 index 0000000000..abf1084c0a --- /dev/null +++ b/test/clojure/test_clojure/run_single_test.clj @@ -0,0 +1,33 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. + +(ns clojure.test-clojure.run-single-test + (:require [clojure.test :refer [is deftest run-test run-tests]] + [clojure.test-helper :refer [with-err-string-writer]] + [clojure.test-clojure.test-fixtures :as tf])) + +(defn not-a-test + []) + +(defmacro should-print-to-err + [re & body] + `(is (re-find ~re (with-err-string-writer ~@body)))) + +(deftest reports-missing-var + (should-print-to-err #"^Unable to resolve .*/function-missing to a test function.*" + (let [result (eval `(run-test function-missing))] + (is (nil? result))))) + +(deftest reports-non-test-var + (should-print-to-err #"^.*/not-a-test is not a test.*" + (let [result (eval `(run-test not-a-test))] + (is (nil? result))))) + +(deftest can-run-test-with-fixtures + (is (= {:test 1, :pass 2, :fail 0, :error 0, :type :summary} + (run-test tf/can-use-once-fixtures)))) From bd4c42dc7946cb015b8d0699596662aa68bcdc89 Mon Sep 17 00:00:00 2001 From: Marc O'Morain Date: Tue, 14 Sep 2021 08:29:33 -0500 Subject: [PATCH 051/285] CLJ-2350 Improve keyword aritiy exception message When calling a keyword with the wrong number of arguments (0, or more than 2), throw an ArityException rather than IllegalArgumentException. The ArityException class has improved error messages over the custom IllegalArgumentException thrown by Keyword.java. Signed-off-by: Alex Miller --- src/jvm/clojure/lang/Keyword.java | 50 +++++++++++++++----------- test/clojure/test_clojure/keywords.clj | 6 ++++ 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/jvm/clojure/lang/Keyword.java b/src/jvm/clojure/lang/Keyword.java index 02d21326a2..145df4f73b 100644 --- a/src/jvm/clojure/lang/Keyword.java +++ b/src/jvm/clojure/lang/Keyword.java @@ -93,13 +93,21 @@ public String toString(){ return _str; } +/** + * @deprecated CLJ-2350: This function is no longer called, but has not been + * removed to maintain the public interface. + */ public Object throwArity(){ throw new IllegalArgumentException("Wrong number of args passed to keyword: " + toString()); } +Object throwArity(int n) { + throw new ArityException(n, toString()); +} + public Object call() { - return throwArity(); + return throwArity(0); } public void run(){ @@ -107,7 +115,7 @@ public void run(){ } public Object invoke() { - return throwArity(); + return throwArity(0); } public int compareTo(Object o){ @@ -146,98 +154,98 @@ final public Object invoke(Object obj, Object notFound) { } public Object invoke(Object arg1, Object arg2, Object arg3) { - return throwArity(); + return throwArity(3); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4) { - return throwArity(); + return throwArity(4); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { - return throwArity(); + return throwArity(5); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) { - return throwArity(); + return throwArity(6); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) { - return throwArity(); + return throwArity(7); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8) { - return throwArity(); + return throwArity(8); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9) { - return throwArity(); + return throwArity(9); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10) { - return throwArity(); + return throwArity(10); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11) { - return throwArity(); + return throwArity(11); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12) { - return throwArity(); + return throwArity(12); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13) { - return throwArity(); + return throwArity(13); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14) { - return throwArity(); + return throwArity(14); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15) { - return throwArity(); + return throwArity(15); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16) { - return throwArity(); + return throwArity(16); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17) { - return throwArity(); + return throwArity(17); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18) { - return throwArity(); + return throwArity(18); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19) { - return throwArity(); + return throwArity(19); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20) { - return throwArity(); + return throwArity(20); } public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, @@ -245,7 +253,7 @@ public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object... args) { - return throwArity(); + return throwArity(20 + args.length); } diff --git a/test/clojure/test_clojure/keywords.clj b/test/clojure/test_clojure/keywords.clj index 9ef86d7dd2..614fbc14e2 100644 --- a/test/clojure/test_clojure/keywords.clj +++ b/test/clojure/test_clojure/keywords.clj @@ -23,3 +23,9 @@ (are [result lookup] (= result (find-keyword this-ns lookup)) ::foo "foo" nil (str absent-keyword-sym))))) + +(deftest arity-exceptions + (is (thrown-with-msg? IllegalArgumentException #"Wrong number of args \(0\) passed to: :kw" (:kw))) + (is (thrown-with-msg? IllegalArgumentException #"Wrong number of args \(20\) passed to: :foo/bar" (apply :foo/bar (range 20)))) + (is (thrown-with-msg? IllegalArgumentException #"Wrong number of args \(21\) passed to: :foo/bar" (apply :foo/bar (range 21)))) + (is (thrown-with-msg? IllegalArgumentException #"Wrong number of args \(22\) passed to: :foo/bar" (apply :foo/bar (range 22))))) From 383ed2adce7e7d09fccef0713a65f44242d74c8f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 23 Nov 2018 11:00:28 +0100 Subject: [PATCH 052/285] CLJ-2444: fix typo in test-vars docstring Signed-off-by: Alex Miller --- src/clj/clojure/test.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/test.clj b/src/clj/clojure/test.clj index 30aae631b2..ce6e025a0f 100644 --- a/src/clj/clojure/test.clj +++ b/src/clj/clojure/test.clj @@ -721,8 +721,8 @@ (do-report {:type :end-test-var, :var v})))) (defn test-vars - "Groups vars by their namespace and runs test-vars on them with - appropriate fixtures applied." + "Groups vars by their namespace and runs test-var on them with + appropriate fixtures applied." {:added "1.6"} [vars] (doseq [[ns vars] (group-by (comp :ns meta) vars)] From d56812cf2e9f7a317f9b603ef4c9f07bf1bed281 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 14 Sep 2021 09:57:09 -0500 Subject: [PATCH 053/285] CLJ-2600 Don't block realized? of delay on pending result Signed-off-by: Alex Miller --- src/jvm/clojure/lang/Delay.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/Delay.java b/src/jvm/clojure/lang/Delay.java index 262c9c1a43..ffd418962d 100644 --- a/src/jvm/clojure/lang/Delay.java +++ b/src/jvm/clojure/lang/Delay.java @@ -54,7 +54,7 @@ public Object deref() { return val; } -synchronized public boolean isRealized(){ +public boolean isRealized(){ return fn == null; } } From fba284a0da101791269ad7ae4cfd61219535631a Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 12 Feb 2019 11:14:58 -0600 Subject: [PATCH 054/285] CLJ-1509 AOT compile more Clojure namespaces Signed-off-by: Alex Miller --- build.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.xml b/build.xml index fd03afb417..80c40f69de 100644 --- a/build.xml +++ b/build.xml @@ -82,6 +82,9 @@ + + + From 894aec0078ff2b58ff12454978b79b163ecc9e4c Mon Sep 17 00:00:00 2001 From: Keyhan Vakil Date: Thu, 16 Aug 2018 21:56:46 -0400 Subject: [PATCH 055/285] CLJ-2387 fixed off-by-one in socket server port validation Signed-off-by: Alex Miller --- src/clj/clojure/core/server.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clj/clojure/core/server.clj b/src/clj/clojure/core/server.clj index f343aa76fe..48377d4127 100644 --- a/src/clj/clojure/core/server.clj +++ b/src/clj/clojure/core/server.clj @@ -51,7 +51,7 @@ "Validate server config options" [{:keys [name port accept] :as opts}] (doseq [prop [:name :port :accept]] (required opts prop)) - (when (or (not (integer? port)) (not (< -1 port 65535))) + (when (or (not (integer? port)) (not (<= 0 port 65535))) (throw (ex-info (str "Invalid socket server port: " port) opts)))) (defn- accept-connection From 69387c5e7d617ebe17ebaaa97344a1bb6a5f0817 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Fri, 11 Jun 2021 15:41:25 +0200 Subject: [PATCH 056/285] CLJ-2636: Get rid of reflection on java.util.Properties when defining *clojure-version* Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 1b1da5c215..99a967750c 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -7088,7 +7088,8 @@ fails, attempts to require sym's namespace and retries." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; clojure version number ;;;;;;;;;;;;;;;;;;;;;; -(let [properties (with-open [version-stream (.getResourceAsStream +(let [^java.util.Properties + properties (with-open [version-stream (.getResourceAsStream (clojure.lang.RT/baseLoader) "clojure/version.properties")] (doto (new java.util.Properties) From 736c7a05cc94716778b383b99eef1090d031ed2d Mon Sep 17 00:00:00 2001 From: Fogus Date: Wed, 8 Sep 2021 08:08:39 -0400 Subject: [PATCH 057/285] CLJ-1879: Make old slow path (clojure.lang.IPersistentMap) reduce over seq of Map.Entry instances and extended to Object -- this is the new slow path. This change makes it general enough to deal with 'seqs to Map.Entries', detaching it from any fully-enumerable set of types. Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 13 +++++++++---- test/clojure/test_clojure/protocols.clj | 8 ++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 99a967750c..9a2bf3d5b4 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -6870,13 +6870,18 @@ fails, attempts to require sym's namespace and retries." init) ;;slow path default - clojure.lang.IPersistentMap - (kv-reduce + java.lang.Object + (kv-reduce [amap f init] - (reduce (fn [ret [k v]] (f ret k v)) init amap)) + (reduce (fn [ret ^java.util.Map$Entry me] + (f ret + (.getKey me) + (.getValue me))) + init + amap)) clojure.lang.IKVReduce - (kv-reduce + (kv-reduce [amap f init] (.kvreduce amap f init))) diff --git a/test/clojure/test_clojure/protocols.clj b/test/clojure/test_clojure/protocols.clj index 3072915481..ff556dcaed 100644 --- a/test/clojure/test_clojure/protocols.clj +++ b/test/clojure/test_clojure/protocols.clj @@ -674,3 +674,11 @@ (deftest test-leading-dashes (is (= 10 (-do-dashed (Dashed.)))) (is (= [10] (map -do-dashed [(Dashed.)])))) + +;; see CLJ-1879 + +(deftest test-base-reduce-kv + (is (= {1 :a 2 :b} + (reduce-kv #(assoc %1 %3 %2) + {} + (seq {:a 1 :b 2}))))) From 42d713929e8f7ecd77efe23384238d29bde62aba Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 20 Aug 2021 16:25:54 -0500 Subject: [PATCH 058/285] CLJ-2649 Fix order of checks in some-fn and every-pred for 3 predicate case to match other unrollings Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 8 ++++---- test/clojure/test_clojure/other_functions.clj | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 9a2bf3d5b4..2ab8f59b30 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -7461,8 +7461,8 @@ fails, attempts to require sym's namespace and retries." (fn ep3 ([] true) ([x] (boolean (and (p1 x) (p2 x) (p3 x)))) - ([x y] (boolean (and (p1 x) (p2 x) (p3 x) (p1 y) (p2 y) (p3 y)))) - ([x y z] (boolean (and (p1 x) (p2 x) (p3 x) (p1 y) (p2 y) (p3 y) (p1 z) (p2 z) (p3 z)))) + ([x y] (boolean (and (p1 x) (p1 y) (p2 x) (p2 y) (p3 x) (p3 y)))) + ([x y z] (boolean (and (p1 x) (p1 y) (p1 z) (p2 x) (p2 y) (p2 z) (p3 x) (p3 y) (p3 z)))) ([x y z & args] (boolean (and (ep3 x y z) (every? #(and (p1 %) (p2 %) (p3 %)) args)))))) ([p1 p2 p3 & ps] @@ -7501,8 +7501,8 @@ fails, attempts to require sym's namespace and retries." (fn sp3 ([] nil) ([x] (or (p1 x) (p2 x) (p3 x))) - ([x y] (or (p1 x) (p2 x) (p3 x) (p1 y) (p2 y) (p3 y))) - ([x y z] (or (p1 x) (p2 x) (p3 x) (p1 y) (p2 y) (p3 y) (p1 z) (p2 z) (p3 z))) + ([x y] (or (p1 x) (p1 y) (p2 x) (p2 y) (p3 x) (p3 y))) + ([x y z] (or (p1 x) (p1 y) (p1 z) (p2 x) (p2 y) (p2 z) (p3 x) (p3 y) (p3 z))) ([x y z & args] (or (sp3 x y z) (some #(or (p1 %) (p2 %) (p3 %)) args))))) ([p1 p2 p3 & ps] diff --git a/test/clojure/test_clojure/other_functions.clj b/test/clojure/test_clojure/other_functions.clj index e0f7beede6..ec60e78ebb 100644 --- a/test/clojure/test_clojure/other_functions.clj +++ b/test/clojure/test_clojure/other_functions.clj @@ -277,7 +277,9 @@ ((some-fn number? odd? #(> % 0)) 2 4 6 8 -10) ;; 3 preds, short-circuiting ((some-fn number? odd? #(> % 0)) 1 :a) + ((some-fn number? odd? #(> % 0)) :a 1) ((some-fn number? odd? #(> % 0)) 1 3 :a) + ((some-fn number? odd? #(> % 0)) :a 1 3) ((some-fn number? odd? #(> % 0)) 1 3 5 :a) ((some-fn number? odd? #(> % 0)) 1 :a 3 5 7) ;; 4 preds From 1d271d7bc74f64831985f89be1d814df2c5f046f Mon Sep 17 00:00:00 2001 From: Fogus Date: Tue, 14 Sep 2021 10:56:58 -0400 Subject: [PATCH 059/285] CLJ-1959: Added implementation of update-keys and tests. Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 16 ++++++++++++++++ test/clojure/test_clojure/other_functions.clj | 9 +++++++++ 2 files changed, 25 insertions(+) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 2ab8f59b30..41094f0c4d 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -7948,3 +7948,19 @@ fails, attempts to require sym's namespace and retries." (transient {})) m)) (meta m))) + +(defn update-keys + "m f => {(f k) v ...} + + Given a map m and a function f of 1-argument, returns a new map whose + keys are the result of applying f to the keys of m, mapped to the + corresponding values of m. + f must return a unique key for each key of m, else the behavior is undefined." + {:added "1.11"} + [m f] + (let [ret (persistent! + (reduce-kv (fn [acc k v] (assoc! acc (f k) v)) + (transient {}) + m))] + (with-meta ret (meta m)))) + diff --git a/test/clojure/test_clojure/other_functions.clj b/test/clojure/test_clojure/other_functions.clj index ec60e78ebb..517f633fcc 100644 --- a/test/clojure/test_clojure/other_functions.clj +++ b/test/clojure/test_clojure/other_functions.clj @@ -390,3 +390,12 @@ {0 2 2 4} (update-vals (hash-map 0 1 2 3) inc) {0 2 2 4} (update-vals (array-map 0 1 2 3) inc) {0 2 2 4} (update-vals (sorted-map 2 3 0 1) inc)))) + +(deftest test-update-keys + (let [inm (with-meta {:a 1 :b 2} {:has :meta})] + (are [result expr] (= result expr) + {"a" 1 "b" 2} (update-keys inm name) + {:has :meta} (meta (update-keys inm name)) + {1 1 3 3} (update-keys (hash-map 0 1 2 3) inc) + {1 1 3 3} (update-keys (array-map 0 1 2 3) inc) + {1 1 3 3} (update-keys (sorted-map 2 3 0 1) inc)))) From 9a7d8035a0bb6850eaaf4e128e9ac6f2e3517942 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 14 Sep 2021 13:21:51 -0500 Subject: [PATCH 060/285] Fix :added metadata in new clojure.test fns --- src/clj/clojure/test.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/test.clj b/src/clj/clojure/test.clj index ce6e025a0f..0ab20a75a3 100644 --- a/src/clj/clojure/test.clj +++ b/src/clj/clojure/test.clj @@ -796,7 +796,7 @@ (defn run-test-var "Runs the tests for a single Var, with fixtures executed around the test, and summary output after." - {:added "1.9"} + {:added "1.11"} [v] (binding [*report-counters* (ref *initial-report-counters*)] (let [ns-obj (-> v meta :ns) @@ -814,7 +814,7 @@ "Runs a single test. Because the intent is to run a single test, there is no check for the namespace test-ns-hook." - {:added "1.9"} + {:added "1.11"} [test-symbol] (let [test-var (resolve test-symbol)] (cond From 4b46c4f6a0cee3e7a2db76dadbb99be2f64235f4 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 14 Sep 2021 14:59:48 -0500 Subject: [PATCH 061/285] Update dep core.specs.alpha 0.2.62 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index efb331d86a..3ec8bbb677 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,7 @@ org.clojure core.specs.alpha - 0.2.56 + 0.2.62 org.clojure From 3ec386a11c426bd3cacb128ea994e3b3a5f6052f Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Tue, 14 Sep 2021 15:04:02 -0500 Subject: [PATCH 062/285] [maven-release-plugin] prepare release clojure-1.11.0-alpha2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3ec8bbb677..c8a4a44dae 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.11.0-master-SNAPSHOT + 1.11.0-alpha2 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.11.0-alpha2 From b8132f92f3c3862aa6cdd8a72e4e74802a63f673 Mon Sep 17 00:00:00 2001 From: "Hudson @ build.clojure.org" Date: Tue, 14 Sep 2021 15:04:02 -0500 Subject: [PATCH 063/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c8a4a44dae..3ec8bbb677 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.11.0-alpha2 + 1.11.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.11.0-alpha2 + HEAD From 6e2ac1b2e29f89bca5dcd667c08a53d656bfef0c Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 23 Nov 2021 10:24:41 -0600 Subject: [PATCH 064/285] Update to spec.alpha 0.3.214 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3ec8bbb677..71c4378068 100644 --- a/pom.xml +++ b/pom.xml @@ -41,7 +41,7 @@ org.clojure spec.alpha - 0.2.194 + 0.3.214 org.clojure From bd507fac423ebd59a8f032369d75ce079ce88d40 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 22 Nov 2021 08:22:36 -0600 Subject: [PATCH 065/285] CLJ-2667 Add functions to parse a single long/double/uuid/boolean from a string Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 50 +++++++++++++++ test/clojure/test_clojure/parse.clj | 99 +++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 test/clojure/test_clojure/parse.clj diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 41094f0c4d..66e9f2655b 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -7964,3 +7964,53 @@ fails, attempts to require sym's namespace and retries." m))] (with-meta ret (meta m)))) +(defn- parsing-err + "Construct message for parsing for non-string parsing error" + ^String [val] + (str "Expected string, got " (if (nil? val) "nil" (-> val class .getName)))) + +(defn parse-long + {:doc "Parse string of decimal digits with optional leading -/+ and return a + Long value, or nil if parse fails" + :added "1.11"} + ^Long [^String s] + (if (string? s) + (try + (Long/valueOf s) + (catch NumberFormatException _ nil)) + (throw (IllegalArgumentException. (parsing-err s))))) + +(defn parse-double + {:doc "Parse string with floating point components and return a Double value, + or nil if parse fails. + + Grammar: https://docs.oracle.com/javase/8/docs/api/java/lang/Double.html#valueOf-java.lang.String-" + :added "1.11"} + ^Double [^String s] + (if (string? s) + (try + (Double/valueOf s) + (catch NumberFormatException _ nil)) + (throw (IllegalArgumentException. (parsing-err s))))) + +(defn parse-uuid + {:doc "Parse a string representing a UUID and return a java.util.UUID instance, + or nil if parse fails. + + Grammar: https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html#toString--" + :added "1.11"} + ^java.util.UUID [^String s] + (try + (java.util.UUID/fromString s) + (catch IllegalArgumentException _ nil))) + +(defn parse-boolean + {:doc "Parse strings \"true\" or \"false\" and return a boolean, or nil if invalid" + :added "1.11"} + [^String s] + (if (string? s) + (case s + "true" true + "false" false + nil) + (throw (IllegalArgumentException. (parsing-err s))))) \ No newline at end of file diff --git a/test/clojure/test_clojure/parse.clj b/test/clojure/test_clojure/parse.clj new file mode 100644 index 0000000000..953beefb4d --- /dev/null +++ b/test/clojure/test_clojure/parse.clj @@ -0,0 +1,99 @@ +(ns clojure.test-clojure.parse + (:require + [clojure.test :refer :all] + [clojure.test.check :as chk] + [clojure.test.check.generators :as gen] + [clojure.test.check.properties :as prop]) + (:import + [java.util UUID])) + +(deftest test-parse-long + (are [s expected] + (= expected (parse-long s)) + "100" 100 + "+100" 100 + "0" 0 + "+0" 0 + "-0" 0 + "-42" -42 + "9223372036854775807" Long/MAX_VALUE + "+9223372036854775807" Long/MAX_VALUE + "-9223372036854775808" Long/MIN_VALUE + "077" 77) ;; leading 0s are ignored! (not octal) + + (are [s] ;; do not parse + (nil? (parse-long s)) + "0.3" ;; no float + "9223372036854775808" ;; past max long + "-9223372036854775809" ;; past min long + "0xA0" ;; no hex + "2r010")) ;; no radix support + +;; generative test - gen long -> str -> parse, compare +(deftest test-gen-parse-long + (let [res (chk/quick-check + 100000 + (prop/for-all* [gen/large-integer] + #(= % (-> % str parse-long))))] + (if (:result res) + (is true) ;; pass + (is (:result res) (pr-str res))))) + +(deftest test-parse-double + (are [s expected] + (= expected (parse-double s)) + "1.234" 1.234 + "+1.234" 1.234 + "-1.234" -1.234 + "+0" +0.0 + "-0.0" -0.0 + "0.0" 0.0 + "5" 5.0 + "Infinity" Double/POSITIVE_INFINITY + "-Infinity" Double/NEGATIVE_INFINITY + "1.7976931348623157E308" Double/MAX_VALUE + "4.9E-324" Double/MIN_VALUE) + (is (Double/isNaN (parse-double "NaN"))) + (are [s] ;; nil on invalid string + (nil? (parse-long s)) + "1.7976931348623157E309" ;; past max double + "9.9E-324")) ;; past min double + +;; generative test - gen double -> str -> parse, compare +(deftest test-gen-parse-double + (let [res (chk/quick-check + 100000 + (prop/for-all* [gen/double] + #(let [parsed (-> % str parse-double)] + (if (Double/isNaN %) + (Double/isNaN parsed) + (= % parsed)))))] + (if (:result res) + (is true) ;; pass + (is (:result res) (pr-str res))))) + +(deftest test-parse-uuid + (is (parse-uuid (.toString (UUID/randomUUID)))) + (is (nil? (parse-uuid "BOGUS"))) ;; nil on invalid uuid string + (are [s] ;; throw on invalid type (not string) + (try (parse-uuid s) (is false) (catch Throwable _ (is true))) + 123 + nil)) + +(deftest test-parse-boolean + (is (identical? true (parse-boolean "true"))) + (is (identical? false (parse-boolean "false"))) + + (are [s] ;; nil on invalid string + (nil? (parse-boolean s)) + "abc" + "TRUE" + "FALSE" + " true ") + + (are [s] ;; throw on invalid type (not string) + (try (parse-boolean s) (is false) (catch Throwable _ (is true))) + nil + false + true + 100)) \ No newline at end of file From f227b4b619e865b7cb853fe140d62f3f24994c0a Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 23 Nov 2021 12:20:05 -0600 Subject: [PATCH 066/285] CLJ-2668 Add NaN? and infinite? predicates Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 19 ++++++++++++++++++- test/clojure/test_clojure/predicates.clj | 20 ++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 66e9f2655b..d4c677b541 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -8013,4 +8013,21 @@ fails, attempts to require sym's namespace and retries." "true" true "false" false nil) - (throw (IllegalArgumentException. (parsing-err s))))) \ No newline at end of file + (throw (IllegalArgumentException. (parsing-err s))))) + +(defn NaN? + {:doc "Returns true if num is NaN, else false" + :inline-arities #{1} + :inline (fn [num] `(Double/isNaN ~num)) + :added "1.11"} + + [^double num] + (Double/isNaN num)) + +(defn infinite? + {:doc "Returns true if num is negative or positive infinity, else false" + :inline-arities #{1} + :inline (fn [num] `(Double/isInfinite ~num)) + :added "1.11"} + [^double num] + (Double/isInfinite num)) diff --git a/test/clojure/test_clojure/predicates.clj b/test/clojure/test_clojure/predicates.clj index 7efdc6fe71..bb9074fb5f 100644 --- a/test/clojure/test_clojure/predicates.clj +++ b/test/clojure/test_clojure/predicates.clj @@ -172,3 +172,23 @@ (dotimes [i (count row)] (is (= ((resolve (nth preds i)) v) (nth row i)) (pr-str (list (nth preds i) v)))))))) + +;; Special double predicates + +(deftest test-double-preds + (is (NaN? ##NaN)) + (is (NaN? (Double/parseDouble "NaN"))) + (is (NaN? (Float/parseFloat "NaN"))) + (is (NaN? Float/NaN)) + (is (not (NaN? 5))) + (is (thrown? Throwable (NaN? nil))) + (is (thrown? Throwable (NaN? :xyz))) + + (is (infinite? ##Inf)) + (is (infinite? ##-Inf)) + (is (infinite? Double/POSITIVE_INFINITY)) + (is (infinite? Double/NEGATIVE_INFINITY)) + (is (infinite? Float/POSITIVE_INFINITY)) + (is (infinite? Float/NEGATIVE_INFINITY)) + (is (thrown? Throwable (infinite? nil))) + (is (thrown? Throwable (infinite? :xyz)))) \ No newline at end of file From 55c30c67b98bbf58b5589bbbd78fa236869f5b7d Mon Sep 17 00:00:00 2001 From: Fogus Date: Tue, 16 Nov 2021 10:26:27 -0600 Subject: [PATCH 067/285] CLJ-1925: Adds implementation of random-uuid Signed-off-by: Alex Miller --- src/clj/clojure/core.clj | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index d4c677b541..a3a32522b4 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -6843,6 +6843,13 @@ fails, attempts to require sym's namespace and retries." {:added "1.9"} [x] (instance? java.util.UUID x)) +(defn random-uuid + {:doc "Returns a pseudo-randomly generated java.util.UUID instance (i.e. type 4). + + See: https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html#randomUUID--" + :added "1.11"} + ^java.util.UUID [] (java.util.UUID/randomUUID)) + (defn reduce "f should be a function of 2 arguments. If val is not supplied, returns the result of applying f to the first 2 items in coll, then From e3ee18f6bcab950ecf51fb33306f503971784c87 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 21 Oct 2021 22:50:46 -0500 Subject: [PATCH 068/285] CLJ-2664 Add clojure.java.math access to java.lang.Math Signed-off-by: Alex Miller --- build.xml | 1 + src/clj/clojure/java/math.clj | 556 ++++++++++++++++++++++++++++++++++ 2 files changed, 557 insertions(+) create mode 100644 src/clj/clojure/java/math.clj diff --git a/build.xml b/build.xml index 80c40f69de..444b5d9603 100644 --- a/build.xml +++ b/build.xml @@ -76,6 +76,7 @@ + diff --git a/src/clj/clojure/java/math.clj b/src/clj/clojure/java/math.clj new file mode 100644 index 0000000000..2d54fb52d7 --- /dev/null +++ b/src/clj/clojure/java/math.clj @@ -0,0 +1,556 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. + +(ns + ^{:author "Alex Miller", + :doc "Clojure wrapper functions for java.lang.Math static methods. + + Function calls are inlined for performance, and type hinted for primitive + long or double parameters where appropriate. In general, Math methods are + optimized for performance and have bounds for error tolerance. If + greater precision is needed, use java.lang.StrictMath directly instead. + + For more complete information, see: + https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html"} + clojure.java.math + (:refer-clojure :exclude [min max])) + +(def + ^{:doc "Constant for e, the base for natural logarithms. + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#E" + :added "1.11" + :const true + :tag 'double} + E + Math/E) + +(def + ^{:doc "Constant for pi, the ratio of the circumference of a circle to its diameter. + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#PI" + :added "1.11" + :const true + :tag 'double} + PI + Math/PI) + +(defn sin + {:doc "Returns the sine of an angle. + If a is ##NaN, ##-Inf, ##Inf => ##NaN + If a is zero => zero with the same sign as a + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sin-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/sin ~a)) + :added "1.11"} + ^double [^double a] + (Math/sin a)) + +(defn cos + {:doc "Returns the cosine of an angle. + If a is ##NaN, ##-Inf, ##Inf => ##NaN + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cos-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/cos ~a)) + :added "1.11"} + ^double [^double a] + (Math/cos a)) + +(defn tan + {:doc "Returns the tangent of an angle. + If a is ##NaN, ##-Inf, ##Inf => ##NaN + If a is zero => zero with the same sign as a + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#tan-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/tan ~a)) + :added "1.11"} + ^double [^double a] + (Math/tan a)) + +(defn asin + {:doc "Returns the arc sine of an angle, in the range -pi/2 to pi/2. + If a is ##NaN or |a|>1 => ##NaN + If a is zero => zero with the same sign as a + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#asin-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/asin ~a)) + :added "1.11"} + ^double [^double a] + (Math/asin a)) + +(defn acos + {:doc "Returns the arc cosine of a, in the range 0.0 to pi. + If a is ##NaN or |a|>1 => ##NaN + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#acos-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/acos ~a)) + :added "1.11"} + ^double [^double a] + (Math/acos a)) + +(defn atan + {:doc "Returns the arc tangent of a, in the range of -pi/2 to pi/2. + If a is ##NaN => ##NaN + If a is zero => zero with the same sign as a + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#atan-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/atan ~a)) + :added "1.11"} + ^double [^double a] + (Math/atan a)) + +(defn to-radians + {:doc "Converts an angle in degrees to an approximate equivalent angle in radians. + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#toRadians-double-" + :inline-arities #{1} + :inline (fn [deg] `(Math/toRadians ~deg)) + :added "1.11"} + ^double [^double deg] + (Math/toRadians deg)) + +(defn to-degrees + {:doc "Converts an angle in radians to an approximate equivalent angle in degrees. + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#toDegrees-double-" + :inline-arities #{1} + :inline (fn [r] `(Math/toDegrees ~r)) + :added "1.11"} + ^double [^double r] + (Math/toDegrees r)) + +(defn exp + {:doc "Returns Euler's number e raised to the power of a. + If a is ##NaN => ##NaN + If a is ##Inf => ##Inf + If a is ##-Inf => +0.0 + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#exp-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/exp ~a)) + :added "1.11"} + ^double [^double a] + (Math/exp a)) + +(defn log + {:doc "Returns the natural logarithm (base e) of a. + If a is ##NaN or negative => ##NaN + If a is ##Inf => ##Inf + If a is zero => ##-Inf + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/log ~a)) + :added "1.11"} + ^double [^double a] + (Math/log a)) + +(defn log10 + {:doc "Returns the logarithm (base 10) of a. + If a is ##NaN or negative => ##NaN + If a is ##Inf => ##Inf + If a is zero => ##-Inf + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log10-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/log10 ~a)) + :added "1.11"} + ^double [^double a] + (Math/log10 a)) + +(defn sqrt + {:doc "Returns the positive square root of a. + If a is ##NaN or negative => ##NaN + If a is ##Inf => ##Inf + If a is zero => a + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sqrt-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/sqrt ~a)) + :added "1.11"} + ^double [^double a] + (Math/sqrt a)) + +(defn cbrt + {:doc "Returns the cube root of a. + If a is ##NaN => ##NaN + If a is ##Inf or ##-Inf => a + If a is zero => zero with sign matching a + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cbrt-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/cbrt ~a)) + :added "1.11"} + ^double [^double a] + (Math/cbrt a)) + +(defn IEEE-remainder + {:doc "Returns the remainder per IEEE 754 such that + remainder = dividend - divisor * n + where n is the integer closest to the exact value of dividend / divisor. + If two integers are equally close, then n is the even one. + If the remainder is zero, sign will match dividend. + If dividend or divisor is ##NaN, or dividend is ##Inf or ##-Inf, or divisor is zero => ##NaN + If dividend is finite and divisor is infinite => dividend + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#IEEEremainder-double-double-" + :inline-arities #{2} + :inline (fn [dividend divisor] `(Math/IEEEremainder ~dividend ~divisor)) + :added "1.11"} + ^double [^double dividend ^double divisor] + (Math/IEEEremainder dividend divisor)) + +(defn ceil + {:doc "Returns the smallest double greater than or equal to a, and equal to a + mathematical integer. + If a is ##NaN or ##Inf or ##-Inf or already equal to an integer => a + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#ceil-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/ceil ~a)) + :added "1.11"} + ^double [^double a] + (Math/ceil a)) + +(defn floor + {:doc "Returns the largest double less than or equal to a, and equal to a + mathematical integer. + If a is ##NaN or ##Inf or ##-Inf or already equal to an integer => a + If a is less than zero but greater than -1.0 => -0.0 + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floor-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/floor ~a)) + :added "1.11"} + ^double [^double a] + (Math/floor a)) + +(defn rint + {:doc "Returns the double closest to a and equal to a mathematical integer. + If two values are equally close, return the even one. + If a is ##NaN or ##Inf or ##-Inf or zero => a + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#rint-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/rint ~a)) + :added "1.11"} + ^double [^double a] + (Math/rint a)) + +(defn atan2 + {:doc "Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta). + Computes the phase theta by computing an arc tangent of y/x in the range of -pi to pi. + For more details on special cases, see: + https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#atan2-double-double-" + :inline-arities #{2} + :inline (fn [y x] `(Math/atan2 ~y ~x)) + :added "1.11"} + ^double [^double y ^double x] + (Math/atan2 y x)) + +(defn pow + {:doc "Returns the value of a raised to the power of b. + For more details on special cases, see: + https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#pow-double-double-" + :inline-arities #{2} + :inline (fn [a b] `(Math/pow ~a ~b)) + :added "1.11"} + ^double [^double a ^double b] + (Math/pow a b)) + +(defn round + {:doc "Returns the closest long to a. If equally close to two values, return the one + closer to ##Inf. + If a is ##NaN => 0 + If a is ##-Inf or < Long/MIN_VALUE => Long/MIN_VALUE + If a is ##Inf or > Long/MAX_VALUE => Long/MAX_VALUE + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#round-double-" + :inline-arities #{1} + :inline (fn [a] `(Math/round ~a)) + :added "1.11"} + ^long [^double a] + (Math/round a)) + +(defn random + {:doc "Returns a positive double between 0.0 and 1.0, chosen pseudorandomly with + approximately random distribution. + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#random--" + :inline-arities #{0} + :inline (fn [] `(Math/random)) + :added "1.11"} + ^double [] + (Math/random)) + +(defn add-exact + {:doc "Returns the sum of x and y, throws ArithmeticException on overflow. + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#addExact-long-long-" + :inline-arities #{2} + :inline (fn [x y] `(Math/addExact ~x ~y)) + :added "1.11"} + ^long [^long x ^long y] + (Math/addExact x y)) + +(defn subtract-exact + {:doc "Returns the difference of x and y, throws ArithmeticException on overflow. + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#subtractExact-long-long-" + :inline-arities #{2} + :inline (fn [x y] `(Math/subtractExact ~x ~y)) + :added "1.11"} + ^long [^long x ^long y] + (Math/subtractExact x y)) + +(defn multiply-exact + {:doc "Returns the product of x and y, throws ArithmeticException on overflow. + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#multiplyExact-long-long-" + :inline-arities #{2} + :inline (fn [x y] `(Math/multiplyExact ~x ~y)) + :added "1.11"} + ^long [^long x ^long y] + (Math/multiplyExact x y)) + +(defn increment-exact + {:doc "Returns a incremented by 1, throws ArithmeticException on overflow. + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#incrementExact-long-" + :inline-arities #{1} + :inline (fn [a] `(Math/incrementExact ~a)) + :added "1.11"} + ^long [^long a] + (Math/incrementExact a)) + +(defn decrement-exact + {:doc "Returns a decremented by 1, throws ArithmeticException on overflow. + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#decrementExact-long-" + :inline-arities #{1} + :inline (fn [a] `(Math/decrementExact ~a)) + :added "1.11"} + ^long [^long a] + (Math/decrementExact a)) + +(defn negative-exact + {:doc "Returns the negation of a, throws ArithmeticException on overflow. + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#negateExact-long-" + :inline-arities #{1} + :inline (fn [a] `(Math/negateExact ~a)) + :added "1.11"} + ^long [^long a] + (Math/negateExact a)) + +(defn floor-div + {:doc "Integer division that rounds to negative infinity (as opposed to zero). + The special case (floorDiv Long/MIN_VALUE -1) overflows and returns Long/MIN_VALUE. + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floorDiv-long-long-" + :inline-arities #{2} + :inline (fn [x y] `(Math/floorDiv ~x ~y)) + :added "1.11"} + ^long [^long x ^long y] + (Math/floorDiv x y)) + +(defn floor-mod + {:doc "Integer modulus x - (floorDiv(x, y) * y). Sign matches y and is in the + range -|y| < r < |y|. + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floorMod-long-long-" + :inline-arities #{2} + :inline (fn [x y] `(Math/floorMod ~x ~y)) + :added "1.11"} + ^long [^long x ^long y] + (Math/floorMod x y)) + +(defn abs + {:doc "Returns the absolute value of a (long or double). + If not negative, a is returned, else negation of a is returned. + If a is Long/MIN_VALUE => Long/MIN_VALUE + If a is a double and zero => +0.0 + If a is a double and ##Inf or ##-Inf => ##Inf + If a is a double and ##NaN => ##NaN + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#abs-long-" + :inline-arities #{1} + :inline (fn [a] `(Math/abs ~a)) + :added "1.11"} + [a] + (Math/abs a)) + +(defn max + {:doc "Returns the greater of a or b. + If doubles and a or b is ##NaN => ##NaN + If doubles and one is negative zero, other positive zero => positive zero + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#max-long-long-" + :inline-arities #{2} + :inline (fn [a b] `(Math/max ~a ~b)) + :added "1.11"} + [a b] + (Math/max a b)) + +(defn min + {:doc "Returns the lesser of a or b. + If doubles and a or b is ##NaN => ##NaN + If doubles and one is negative zero, other positive zero => negative zero + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#min-double-double-" + :inline-arities #{2} + :inline (fn [p0 p1] `(Math/min ~p0 ~p1)) + :added "1.11"} + [p0 p1] + (Math/min p0 p1)) + +(defn ulp + {:doc "Returns the size of an ulp (unit in last place) for d. + If d is ##NaN => ##NaN + If d is ##Inf or ##-Inf => ##Inf + If d is zero => Double/MIN_VALUE + If d is +/- Double/MAX_VALUE => 2^971 + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#ulp-double-" + :inline-arities #{1} + :inline (fn [d] `(Math/ulp ~d)) + :added "1.11"} + ^double [^double d] + (Math/ulp d)) + +(defn signum + {:doc "Returns the signum function of d - zero for zero, 1.0 if >0, -1.0 if <0. + If d is ##NaN => ##NaN + If d is ##Inf or ##-Inf => d + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#signum-double-" + :inline-arities #{1} + :inline (fn [d] `(Math/signum ~d)) + :added "1.11"} + ^double [^double d] + (Math/signum d)) + +(defn sinh + {:doc "Returns the hyperbolic sine of x, (e^x - e^-x)/2. + If x is ##NaN => ##NaN + If x is ##Inf or ##-Inf or zero => x + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sinh-double-" + :inline-arities #{1} + :inline (fn [x] `(Math/sinh ~x)) + :added "1.11"} + ^double [^double x] + (Math/sinh x)) + +(defn cosh + {:doc "Returns the hyperbolic cosine of x, (e^x + e^-x)/2. + If x is ##NaN => ##NaN + If x is ##Inf or ##-Inf => ##Inf + If x is zero => 1.0 + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cosh-double-" + :inline-arities #{1} + :inline (fn [x] `(Math/cosh ~x)) + :added "1.11"} + ^double [^double x] + (Math/cosh x)) + +(defn tanh + {:doc "Returns the hyperbolic tangent of x, sinh(x)/cosh(x). + If x is ##NaN => ##NaN + If x is zero => zero, with same sign + If x is ##Inf => +1.0 + If x is ##-Inf => -1.0 + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#tanh-double-" + :inline-arities #{1} + :inline (fn [x] `(Math/tanh ~x)) + :added "1.11"} + ^double [^double x] + (Math/tanh x)) + +(defn hypot + {:doc "Returns sqrt(x^2 + y^2) without intermediate underflow or overflow. + If x or y is ##Inf or ##-Inf => ##Inf + If x or y is ##NaN and neither is ##Inf or ##-Inf => ##NaN + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#hypot-double-double-" + :inline-arities #{2} + :inline (fn [x y] `(Math/hypot ~x ~y)) + :added "1.11"} + ^double [^double x ^double y] + (Math/hypot x y)) + +(defn expm1 + {:doc "Returns e^x - 1. Near 0, expm1(x)+1 is more accurate to e^x than exp(x). + If x is ##NaN => ##NaN + If x is ##Inf => #Inf + If x is ##-Inf => -1.0 + If x is zero => x + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#expm1-double-" + :inline-arities #{1} + :inline (fn [x] `(Math/expm1 ~x)) + :added "1.11"} + ^double [^double x] + (Math/expm1 x)) + +(defn log1p + {:doc "Returns ln(1+x). For small values of x, log1p(x) is more accurate than + log(1.0+x). + If x is ##NaN or < -1 => ##NaN + If x is ##Inf or ##-Inf or x => x + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log1p-double-" + :inline-arities #{1} + :inline (fn [x] `(Math/log1p ~x)) + :added "1.11"} + ^double [^double x] + (Math/log1p x)) + +(defn copy-sign + {:doc "Returns a double with the magnitude of the first argument and the sign of + the second. + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#copySign-double-double-" + :inline-arities #{2} + :inline (fn [magnitude sign] `(Math/copySign ~magnitude ~sign)) + :added "1.11"} + ^double [^double magnitude ^double sign] + (Math/copySign magnitude sign)) + +(defn get-exponent + {:doc "Returns the exponent of d. + If d is ##NaN, ##Inf, ##-Inf => Double/MAX_EXPONENT + 1 + If d is zero or subnormal => Double/MIN_EXPONENT - 1 + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#getExponent-double-" + :inline-arities #{1} + :inline (fn [d] `(Math/getExponent ~d)) + :added "1.11"} + [^double d] + (Math/getExponent d)) + +(defn next-after + {:doc "Returns the adjacent floating point number to start in the direction of + the second argument. If the arguments are equal, the second is returned. + If either arg is #NaN => #NaN + If both arguments are signed zeros => direction + If start is +-Double/MIN_VALUE and direction would cause a smaller magnitude + => zero with sign matching start + If start is ##Inf or ##-Inf and direction would cause a smaller magnitude + => Double/MAX_VALUE with same sign as start + If start is equal to +=Double/MAX_VALUE and direction would cause a larger magnitude + => ##Inf or ##-Inf with sign matching start + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextAfter-double-double-" + :inline-arities #{2} + :inline (fn [start direction] `(Math/nextAfter ~start ~direction)) + :added "1.11"} + ^double [^double start ^double direction] + (Math/nextAfter start direction)) + +(defn next-up + {:doc "Returns the adjacent double of d in the direction of ##Inf. + If d is ##NaN => ##NaN + If d is ##Inf => ##Inf + If d is zero => Double/MIN_VALUE + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextUp-double-" + :inline-arities #{1} + :inline (fn [d] `(Math/nextUp ~d)) + :added "1.11"} + ^double [^double d] + (Math/nextUp d)) + +(defn next-down + {:doc "Returns the adjacent double of d in the direction of ##-Inf. + If d is ##NaN => ##NaN + If d is ##Inf => ##-Inf + If d is zero => Double/MIN_VALUE + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextDown-double-" + :inline-arities #{1} + :inline (fn [d] `(Math/nextDown ~d)) + :added "1.11"} + ^double [^double d] + (Math/nextDown d)) + +(defn scalb + {:doc "Returns d * 2^scaleFactor, scaling by a factor of 2. If the exponent + is between Double/MIN_EXPONENT and Double/MAX_EXPONENT, the answer is exact. + If d is ##NaN => ##NaN + If d is ##Inf or ##-Inf => ##Inf or ##-Inf respectively + If d is zero => zero of same sign as d + See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextDown-double-" + :inline-arities #{1} + :inline (fn [d scaleFactor] `(Math/scalb ~d ~scaleFactor)) + :added "1.11"} + ^double [^double d scaleFactor] + (Math/scalb d scaleFactor)) \ No newline at end of file From 3c9a245e1c6ee3dfe55822b5828427c32d9901d0 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 27 Oct 2021 14:17:09 -0500 Subject: [PATCH 069/285] CLJ-2666 Make javadoc text match example Signed-off-by: Alex Miller --- src/jvm/clojure/java/api/Clojure.java | 2 +- src/jvm/clojure/java/api/package.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jvm/clojure/java/api/Clojure.java b/src/jvm/clojure/java/api/Clojure.java index 3667b22791..8a9ef9b543 100644 --- a/src/jvm/clojure/java/api/Clojure.java +++ b/src/jvm/clojure/java/api/Clojure.java @@ -41,7 +41,7 @@ * require.invoke(Clojure.read("clojure.set")); * *

IFns can be passed to higher order functions, e.g. the - * example below passes plus to read:

+ * example below passes inc to map:

* *
  * IFn map = Clojure.var("clojure.core", "map");
diff --git a/src/jvm/clojure/java/api/package.html b/src/jvm/clojure/java/api/package.html
index 6536c33ab5..a24d3c9b79 100644
--- a/src/jvm/clojure/java/api/package.html
+++ b/src/jvm/clojure/java/api/package.html
@@ -57,7 +57,7 @@
 

IFns can be passed to higher order functions, e.g. the - example below passes plus to read: + example below passes inc to map:

 IFn map = Clojure.var("clojure.core", "map");
 IFn inc = Clojure.var("clojure.core", "inc");

From ade22645ba5dbf4c0d8115b19938af96d6fb4cd5 Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Thu, 18 Nov 2021 09:47:56 -0600
Subject: [PATCH 070/285] CLJ-1360 Update clojure.string/split docstring
 regarding trailing empty parts

Signed-off-by: Alex Miller 
---
 src/clj/clojure/string.clj | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/clj/clojure/string.clj b/src/clj/clojure/string.clj
index 35e0650f65..38f0d6d91d 100644
--- a/src/clj/clojure/string.clj
+++ b/src/clj/clojure/string.clj
@@ -218,7 +218,8 @@ Design notes for clojure.string:
 
 (defn split
   "Splits string on a regular expression.  Optional argument limit is
-  the maximum number of splits. Not lazy. Returns vector of the splits."
+  the maximum number of parts. Not lazy. Returns vector of the parts.
+  Trailing empty strings are not returned - pass limit of -1 to return all."
   {:added "1.2"}
   ([^CharSequence s ^Pattern re]
      (LazilyPersistentVector/createOwning (.split re s)))
@@ -226,7 +227,7 @@ Design notes for clojure.string:
      (LazilyPersistentVector/createOwning (.split re s limit))))
 
 (defn split-lines
-  "Splits s on \\n or \\r\\n."
+  "Splits s on \\n or \\r\\n. Trailing empty lines are not returned."
   {:added "1.2"}
   [^CharSequence s]
   (split s #"\r?\n"))

From 554090e7fd5f33fc3c1c962bb34af53a01332a75 Mon Sep 17 00:00:00 2001
From: Arne Brasseur 
Date: Thu, 18 Nov 2021 09:41:29 -0600
Subject: [PATCH 071/285] CLJ-2249 Clarify clojure.core/get docstring regarding
 sets, strings, arrays, ILookup

Signed-off-by: Alex Miller 
---
 src/clj/clojure/core.clj | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index a3a32522b4..9f3cdf371f 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -1494,7 +1494,8 @@
   [coll key] (. clojure.lang.RT (contains coll key)))
 
 (defn get
-  "Returns the value mapped to key, not-found or nil if key not present."
+  "Returns the value mapped to key, not-found or nil if key not present
+  in associative collection, set, string, array, or ILookup instance."
   {:inline (fn  [m k & nf] `(. clojure.lang.RT (get ~m ~k ~@nf)))
    :inline-arities #{2 3}
    :added "1.0"}

From e1220832d900745727cf5a1b69f4a6cd664f1443 Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Tue, 5 Oct 2021 10:32:45 -0500
Subject: [PATCH 072/285] CLJ-2488 Add definition to reify docstring

Signed-off-by: Alex Miller 
---
 src/clj/clojure/core_deftype.clj | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/clj/clojure/core_deftype.clj b/src/clj/clojure/core_deftype.clj
index 786f0d4b53..7906ccbe35 100644
--- a/src/clj/clojure/core_deftype.clj
+++ b/src/clj/clojure/core_deftype.clj
@@ -67,8 +67,9 @@
       (throw (IllegalArgumentException. (apply print-str "Unsupported option(s) -" bad-opts))))
     [interfaces methods opts]))
 
-(defmacro reify 
-  "reify is a macro with the following structure:
+(defmacro reify
+  "reify creates an object implementing a protocol or interface.
+  reify is a macro with the following structure:
 
  (reify options* specs*)
   

From 631c46ed98ed3bfefdb8a15080e004ab470b0bf4 Mon Sep 17 00:00:00 2001
From: Nikita Prokopov 
Date: Sun, 30 Aug 2015 18:56:04 +0600
Subject: [PATCH 073/285] CLJ-1808 map-invert should use reduce-kv and
 transient

Signed-off-by: Alex Miller 
---
 src/clj/clojure/set.clj | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/clj/clojure/set.clj b/src/clj/clojure/set.clj
index b63a004475..9ffb72900a 100644
--- a/src/clj/clojure/set.clj
+++ b/src/clj/clojure/set.clj
@@ -106,7 +106,11 @@
 (defn map-invert
   "Returns the map with the vals mapped to the keys."
   {:added "1.0"}
-  [m] (reduce (fn [m [k v]] (assoc m v k)) {} m))
+  [m]
+  (persistent!
+    (reduce-kv (fn [m k v] (assoc! m v k))
+               (transient {})
+               m)))
 
 (defn join
   "When passed 2 rels, returns the rel corresponding to the natural

From d004e799364e29815dc1b080dbf9e8bd9858c321 Mon Sep 17 00:00:00 2001
From: Steve Miner 
Date: Tue, 5 Oct 2021 09:48:39 -0500
Subject: [PATCH 074/285] CLJ-2065 Support IKVReduce on SubVector

Signed-off-by: Alex Miller 
---
 src/jvm/clojure/lang/APersistentVector.java | 12 +++++++++++-
 test/clojure/test_clojure/vectors.clj       |  4 ++++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/src/jvm/clojure/lang/APersistentVector.java b/src/jvm/clojure/lang/APersistentVector.java
index c9f15cdd3f..de8a09ea68 100644
--- a/src/jvm/clojure/lang/APersistentVector.java
+++ b/src/jvm/clojure/lang/APersistentVector.java
@@ -544,7 +544,7 @@ public APersistentVector.RSeq withMeta(IPersistentMap meta){
 	}
 }
 
-public static class SubVector extends APersistentVector implements IObj{
+public static class SubVector extends APersistentVector implements IObj, IKVReduce{
 	public final IPersistentVector v;
 	public final int start;
 	public final int end;
@@ -574,6 +574,16 @@ public Iterator iterator(){
 		return super.iterator();
 	}
 
+	public Object kvreduce(IFn f, Object init){
+		int cnt = count();
+		for (int i=0; i= end) || (i < 0))
 			throw new IndexOutOfBoundsException();
diff --git a/test/clojure/test_clojure/vectors.clj b/test/clojure/test_clojure/vectors.clj
index 0bea3ff4b8..0be0bf14e8 100644
--- a/test/clojure/test_clojure/vectors.clj
+++ b/test/clojure/test_clojure/vectors.clj
@@ -416,3 +416,7 @@
   (is (= [0 1 2 3] (vec (reify clojure.lang.IReduceInit
                           (reduce [_ f start]
                             (reduce f start (range 4))))))))
+
+(deftest test-reduce-kv-vectors
+  (is (= 25 (reduce-kv + 10 [2 4 6])))
+  (is (= 25 (reduce-kv + 10 (subvec [0 2 4 6] 1)))))

From e21bbfe1d1b06ae703e939951e6c8f199969d70b Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Tue, 23 Nov 2021 12:47:24 -0600
Subject: [PATCH 075/285] CLJ-2326 Add :direct-linking to *compiler-options*
 docstring and remove Alpha marking

Signed-off-by: Alex Miller 
---
 src/clj/clojure/core.clj | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index 9f3cdf371f..0dba6fcd97 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -6473,7 +6473,10 @@ fails, attempts to require sym's namespace and retries."
   Supported options:
   :elide-meta - a collection of metadata keys to elide during compilation.
   :disable-locals-clearing - set to true to disable clearing, useful for using a debugger
-  Alpha, subject to change."
+  :direct-linking - set to true to use direct static invocation of functions, rather than vars
+    Note that call sites compiled with direct linking will not be affected by var redefinition.
+    Use ^:redef (or ^:dynamic) on a var to prevent direct linking and allow redefinition.
+  See https://clojure.org/reference/compilation for more information."
   {:added "1.4"})
 
 (add-doc-and-meta *ns*

From 8ebad0ab3f912932d94874120cad89493f2aa22e Mon Sep 17 00:00:00 2001
From: "Hudson @ build.clojure.org" 
Date: Tue, 23 Nov 2021 13:25:56 -0600
Subject: [PATCH 076/285] [maven-release-plugin] prepare release
 clojure-1.11.0-alpha3

---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 71c4378068..d9ae7e5f14 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
   clojure
   clojure
   jar
-  1.11.0-master-SNAPSHOT
+  1.11.0-alpha3
 
   http://clojure.org/
   Clojure core environment and runtime library.
@@ -30,7 +30,7 @@
     scm:git:git@github.com:clojure/clojure.git
     scm:git:git@github.com:clojure/clojure.git
     git@github.com:clojure/clojure.git
-    HEAD
+    clojure-1.11.0-alpha3
   
 
   

From 7697d5da77a319077e71343f76fa204327881de4 Mon Sep 17 00:00:00 2001
From: "Hudson @ build.clojure.org" 
Date: Tue, 23 Nov 2021 13:25:56 -0600
Subject: [PATCH 077/285] [maven-release-plugin] prepare for next development
 iteration

---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index d9ae7e5f14..71c4378068 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
   clojure
   clojure
   jar
-  1.11.0-alpha3
+  1.11.0-master-SNAPSHOT
 
   http://clojure.org/
   Clojure core environment and runtime library.
@@ -30,7 +30,7 @@
     scm:git:git@github.com:clojure/clojure.git
     scm:git:git@github.com:clojure/clojure.git
     git@github.com:clojure/clojure.git
-    clojure-1.11.0-alpha3
+    HEAD
   
 
   

From abe19832c0294fec4c9c55430c9262c4b6d2f8b1 Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Tue, 30 Nov 2021 10:45:25 -0600
Subject: [PATCH 078/285] Remove/ignore project files

---
 .gitignore                                    |  1 +
 ...ven__org_clojure_data_generators_0_1_2.xml | 13 -----------
 ...ven__org_clojure_test_generative_0_4_0.xml | 13 -----------
 clojure.iml                                   | 23 -------------------
 4 files changed, 1 insertion(+), 49 deletions(-)
 delete mode 100644 .idea/libraries/Maven__org_clojure_data_generators_0_1_2.xml
 delete mode 100644 .idea/libraries/Maven__org_clojure_test_generative_0_4_0.xml
 delete mode 100644 clojure.iml

diff --git a/.gitignore b/.gitignore
index 5376efaf3f..18cf4cc05c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@ nbproject/private/
 maven-classpath
 maven-classpath.properties
 .idea/
+*.iml
diff --git a/.idea/libraries/Maven__org_clojure_data_generators_0_1_2.xml b/.idea/libraries/Maven__org_clojure_data_generators_0_1_2.xml
deleted file mode 100644
index 78f485eeb9..0000000000
--- a/.idea/libraries/Maven__org_clojure_data_generators_0_1_2.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-  
-    
-      
-    
-    
-      
-    
-    
-      
-    
-  
-
\ No newline at end of file
diff --git a/.idea/libraries/Maven__org_clojure_test_generative_0_4_0.xml b/.idea/libraries/Maven__org_clojure_test_generative_0_4_0.xml
deleted file mode 100644
index 78fac6dfd0..0000000000
--- a/.idea/libraries/Maven__org_clojure_test_generative_0_4_0.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-  
-    
-      
-    
-    
-      
-    
-    
-      
-    
-  
-
\ No newline at end of file
diff --git a/clojure.iml b/clojure.iml
deleted file mode 100644
index c1c8a6a84a..0000000000
--- a/clojure.iml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-  
-    
-    
-    
-      
-      
-      
-      
-      
-      
-      
-    
-    
-    
-    
-    
-    
-    
-    
-  
-
\ No newline at end of file

From f5e5a4a7b8e0785436f0bbb9b91b6de9f754aa33 Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Thu, 13 Jan 2022 11:57:31 -0600
Subject: [PATCH 079/285] CLJ-2684 Update contrib deps

Signed-off-by: Alex Miller 
---
 pom.xml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pom.xml b/pom.xml
index 71c4378068..59159805a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -41,7 +41,7 @@
     
       org.clojure
       spec.alpha
-       0.3.214
+       0.3.218
     
     
       org.clojure
@@ -51,7 +51,7 @@
     
       org.clojure
       test.generative
-      0.5.2
+      1.0.0
       test
       
         
@@ -63,7 +63,7 @@
     
       org.clojure
       test.check
-      0.9.0
+      1.1.1
       test
       
         

From b32e35ae89d291882dbdb662c4193ecfa9a593e8 Mon Sep 17 00:00:00 2001
From: Alexander Yakushev 
Date: Thu, 13 Jan 2022 11:29:09 -0600
Subject: [PATCH 080/285] CLJ-2621: Make InstanceMethodExpr.emit discard unused
 primitive returns without boxing

Signed-off-by: Alex Miller 
---
 src/jvm/clojure/lang/Compiler.java         | 16 ++++++++++++----
 test/clojure/test_clojure/java_interop.clj | 18 +++++++++++++++++-
 2 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index 041786e888..ce16f85a21 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -1612,8 +1612,16 @@ public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
 				gen.invokeInterface(type, m);
 			else
 				gen.invokeVirtual(type, m);
-			//if(context != C.STATEMENT || method.getReturnType() == Void.TYPE)
-			HostExpr.emitBoxReturn(objx, gen, method.getReturnType());
+			Class retClass = method.getReturnType();
+			if(context == C.STATEMENT)
+				{
+				if(retClass == long.class || retClass == double.class)
+					gen.pop2();
+				else if(retClass != void.class)
+					gen.pop();
+				}
+			else
+				HostExpr.emitBoxReturn(objx, gen, retClass);
 			}
 		else
 			{
@@ -1627,9 +1635,9 @@ public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
 				method.emitClearLocals(gen);
 				}
 			gen.invokeStatic(REFLECTOR_TYPE, invokeInstanceMethodMethod);
+			if(context == C.STATEMENT)
+				gen.pop();
 			}
-		if(context == C.STATEMENT)
-			gen.pop();
 	}
 
 	public boolean hasJavaClass(){
diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj
index 30fab56e56..cb21064b25 100644
--- a/test/clojure/test_clojure/java_interop.clj
+++ b/test/clojure/test_clojure/java_interop.clj
@@ -13,7 +13,8 @@
   (:use clojure.test)
   (:require [clojure.inspector]
             [clojure.set :as set])
-  (:import java.util.Base64))
+  (:import java.util.Base64
+           (java.util.concurrent.atomic AtomicLong AtomicInteger)))
 
 ; http://clojure.org/java_interop
 ; http://clojure.org/compilation
@@ -589,3 +590,18 @@
   (is (= (char \a) \a)))
 
 ;; Note: More coercions in numbers.clj
+
+; Test that primitive boxing elision in statement context works
+; correctly (CLJ-2621)
+
+(defn inc-atomic-int [^AtomicInteger l]
+  (.incrementAndGet l)
+  nil)
+
+(defn inc-atomic-long [^AtomicLong l]
+  (.incrementAndGet l)
+  nil)
+
+(deftest test-boxing-prevention-when-compiling-statements
+  (is (= 1 (.get (doto (AtomicInteger. 0) inc-atomic-int))))
+  (is (= 1 (.get (doto (AtomicLong. 0) inc-atomic-long)))))

From b30a99014814f2fe68833622a567c80133b0c417 Mon Sep 17 00:00:00 2001
From: Fogus 
Date: Thu, 13 Jan 2022 11:37:08 -0500
Subject: [PATCH 081/285] CLJ-2663: Added a guard in APVector#doEquiv so that
 List operands that do not respond to #size are not checked. Also, added count
 short-circuit logic to ASeq#equiv in an attempt to leverage fast-count
 benefit, but the guard is more strict such that this and the operand should
 bouth be Counted.

Signed-off-by: Alex Miller 
---
 src/jvm/clojure/lang/APersistentVector.java | 13 ++++++++-----
 src/jvm/clojure/lang/ASeq.java              |  5 +++++
 test/clojure/test_clojure/vectors.clj       |  8 ++++++++
 3 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/src/jvm/clojure/lang/APersistentVector.java b/src/jvm/clojure/lang/APersistentVector.java
index de8a09ea68..3e88d14dbf 100644
--- a/src/jvm/clojure/lang/APersistentVector.java
+++ b/src/jvm/clojure/lang/APersistentVector.java
@@ -98,15 +98,18 @@ static boolean doEquiv(IPersistentVector v, Object obj){
 	else if(obj instanceof List)
 		{
 		Collection ma = (Collection) obj;
-		if(ma.size() != v.count())
+
+		if((!(ma instanceof IPersistentCollection) || (ma instanceof Counted)) && (ma.size() != v.count()))
 			return false;
-		for(Iterator i1 = ((List) v).iterator(), i2 = ma.iterator();
-		    i1.hasNext();)
+
+		Iterator i2 = ma.iterator();
+
+		for(Iterator i1 = ((List) v).iterator(); i1.hasNext();)
 			{
-			if(!Util.equiv(i1.next(), i2.next()))
+			if(!i2.hasNext() || !Util.equiv(i1.next(), i2.next()))
 				return false;
 			}
-		return true;
+		return !i2.hasNext();
 		}
 	else
 		{
diff --git a/src/jvm/clojure/lang/ASeq.java b/src/jvm/clojure/lang/ASeq.java
index 325aa27c24..f0f8e5d447 100644
--- a/src/jvm/clojure/lang/ASeq.java
+++ b/src/jvm/clojure/lang/ASeq.java
@@ -37,6 +37,11 @@ public boolean equiv(Object obj){
 
 	if(!(obj instanceof Sequential || obj instanceof List))
 		return false;
+
+	if(this instanceof Counted && obj instanceof Counted &&
+	   ((Counted)this).count() != ((Counted)obj).count())
+		return false;
+
 	ISeq ms = RT.seq(obj);
 	for(ISeq s = seq(); s != null; s = s.next(), ms = ms.next())
 		{
diff --git a/test/clojure/test_clojure/vectors.clj b/test/clojure/test_clojure/vectors.clj
index 0be0bf14e8..ea2b8e77d5 100644
--- a/test/clojure/test_clojure/vectors.clj
+++ b/test/clojure/test_clojure/vectors.clj
@@ -420,3 +420,11 @@
 (deftest test-reduce-kv-vectors
   (is (= 25 (reduce-kv + 10 [2 4 6])))
   (is (= 25 (reduce-kv + 10 (subvec [0 2 4 6] 1)))))
+
+(deftest test-vector-eqv-to-non-counted-types
+  (is (not= (range) [0 1 2]))
+  (is (not= [0 1 2] (range)))
+  (is (= [0 1 2] (take 3 (range))))
+  (is (= [0 1 2] (new java.util.ArrayList [0 1 2])))
+  (is (not= [1 2] (take 1 (cycle [1 2]))))
+  (is (= [1 2 3 nil 4 5 6 nil] (eduction cat [[1 2 3 nil] [4 5 6 nil]]))))

From 304d7c6a81bd7d8511e9ef3d89dc199b1464afaa Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Wed, 12 Jan 2022 16:03:23 -0600
Subject: [PATCH 082/285] CLJ-2677 In clojure.math inline methods, use coercion
 functions to resolve to single overload

Signed-off-by: Alex Miller 
---
 build.xml                           |   2 +-
 codegen/gen_math.clj                | 263 +++++++++++++++++++++++
 src/clj/clojure/{java => }/math.clj | 141 +++++-------
 test/clojure/test_clojure/math.clj  | 320 ++++++++++++++++++++++++++++
 4 files changed, 638 insertions(+), 88 deletions(-)
 create mode 100644 codegen/gen_math.clj
 rename src/clj/clojure/{java => }/math.clj (83%)
 create mode 100644 test/clojure/test_clojure/math.clj

diff --git a/build.xml b/build.xml
index 444b5d9603..6796b3d986 100644
--- a/build.xml
+++ b/build.xml
@@ -76,7 +76,6 @@
       
       
       
-      
       
       
       
@@ -86,6 +85,7 @@
       
       
       
+      
     
   
 
diff --git a/codegen/gen_math.clj b/codegen/gen_math.clj
new file mode 100644
index 0000000000..484649d3d3
--- /dev/null
+++ b/codegen/gen_math.clj
@@ -0,0 +1,263 @@
+;; This code was used to generate the clojure.math namespace in
+;; Clojure 1.11 to wrap Java 1.8 java.lang.Math methods. There are
+;; many small tweaks in this to get exactly the output that was
+;; desired and it was not intended to be reused in any way, it is
+;; included here for future reference.
+
+(ns gen-math
+  (:require
+    [clojure.reflect :as reflect]
+    [clojure.set :as set]
+    [clojure.string :as str])
+  (:import
+    [java.io StringWriter Writer]))
+
+;; manually created
+(declare HEADER)
+(declare FNS)
+(declare DOCS)
+(declare ARGS)
+(declare ARGTYPES)
+
+(def const-template
+  "(def
+  ^{:doc %s
+    :added %s
+    :const true
+    :tag %s}
+  %s
+  %s)\n\n")
+
+(defn- emit-constant
+  [^Writer writer {:keys [cname name added type]}]
+  (let [sym (symbol (str cname) (str name))
+        doc (str "\"" (get DOCS (symbol name)) "\"")
+        tag (str "'" type)]
+    (.write writer
+      (format const-template doc (pr-str added) tag name sym))))
+
+(def fn-template
+  "(defn %s
+  {:doc %s
+   :inline-arities %s
+   :inline %s
+   :added %s}
+  %s%s
+  %s)\n\n")
+
+(defn- clojurize
+  [sym]
+  (or
+    (get '{IEEEremainder IEEE-remainder} sym)
+    (let [s (name sym)]
+      (symbol
+        (str
+          (reduce
+            (fn [^StringBuilder b ^Character c]
+              (if (Character/isUpperCase c)
+                (.. b (append "-") (append (Character/toLowerCase c)))
+                (.append b c)))
+            (StringBuilder.)
+            s))))))
+
+(defn- inline-body
+  [params param-types]
+  (str/join " "
+    (map (fn [p pt] (format "(%s ~%s)" pt p))
+      params param-types)))
+
+(defn- body
+  [params param-types on-types]
+  (map (fn [p pt] (if (contains? on-types pt) `(~pt ~p) p))
+    params param-types))
+
+(defn- emit-fn
+  [^Writer writer {:keys [cname fname sigs]}]
+  (let [sym (symbol (str cname) (str fname))
+        arities (group-by #(-> % :parameter-types count) sigs)
+        arity (-> arities keys first) ;; NOTE: ignore multiple arities, none in Math
+        arity-sigs (get arities arity)
+        cname (clojurize fname)
+        doc (str "\"" (get DOCS cname) "\"")
+        sig (if (= 1 (count arity-sigs)) (first arity-sigs) (get ARGTYPES cname))
+        {pts :parameter-types, rt :return-type} sig
+        ps (get ARGS cname)
+        ;; coerce all args in inline body
+        inline-body (format "(fn %s `(%s%s))" (pr-str ps) (if (< 0 (count ps)) (str sym " ") sym) (inline-body ps pts))
+        ;; ps are hinted, so coerce only ps that can't be hinted - int type
+        body `(~sym ~@(body ps pts #{'int}))
+        rts (if (#{'long 'double} rt) (str "^" rt " ") "")
+        hints (map #(if (#{'long 'double} %) (symbol (str "^" %)) nil) pts)
+        pst (vec (remove nil? (interleave hints ps)))]
+    (.write writer
+      (format fn-template cname doc #{arity} inline-body (pr-str "1.11") rts pst body))))
+
+(defn gen-static-wrappers
+  [csym]
+  (let [added "1.11"
+        members (:members (reflect/type-reflect (resolve csym)))
+        statics (filter #(set/subset? #{:public :static} (:flags %)) members)
+        {fs false, ms true} (group-by #(contains? % :return-type) statics)
+        methods (->> ms (filter (fn [m]
+                                  (or (= 'scalb (:name m))
+                                    (empty? (set/intersection #{'int 'float} (set (:parameter-types m))))))))
+        by-name (group-by :name methods)
+        writer (StringWriter.)]
+    (.write writer HEADER)
+    (doseq [f fs]
+      (emit-constant writer (merge f {:cname csym, :added added})))
+    (doseq [n FNS]
+      (emit-fn writer {:cname csym, :fname n, :added added, :sigs (get by-name n)}))
+    (spit "src/clj/clojure/math.clj" (str writer))))
+
+(comment
+  (gen-static-wrappers 'Math)
+  )
+
+;;;; Manually provided info used during the generator
+
+(def ^String HEADER
+  ";   Copyright (c) Rich Hickey. All rights reserved.
+;   The use and distribution terms for this software are covered by the
+;   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
+;   which can be found in the file epl-v10.html at the root of this distribution.
+;   By using this software in any fashion, you are agreeing to be bound by
+;   the terms of this license.
+;   You must not remove this notice, or any other, from this software.
+
+(ns
+  ^{:author \"Alex Miller\",
+    :doc \"Clojure wrapper functions for java.lang.Math static methods.
+
+  Function calls are inlined for performance, and type hinted for primitive
+  long or double parameters where appropriate. In general, Math methods are
+  optimized for performance and have bounds for error tolerance. If
+  greater precision is needed, use java.lang.StrictMath directly instead.
+
+  For more complete information, see:
+  https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html\"}
+  clojure.math)
+
+(set! *warn-on-reflection* true)
+
+")
+
+;; fns
+
+;; omitted: toIntExact
+;; omitted but include in core w/polymorphic impl: abs, min, max
+(def FNS
+  '[sin cos tan asin acos atan toRadians toDegrees exp log log10
+    sqrt cbrt IEEEremainder ceil floor rint atan2 pow round random
+    addExact subtractExact multiplyExact incrementExact decrementExact negateExact
+    floorDiv floorMod ulp signum sinh cosh tanh hypot expm1 log1p copySign getExponent
+    nextAfter nextUp nextDown scalb])
+
+;; docstrings to use
+(def DOCS
+  '{
+    E "Constant for e, the base for natural logarithms.\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#E"
+    PI "Constant for pi, the ratio of the circumference of a circle to its diameter.\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#PI"
+    sin "Returns the sine of an angle.\n  If a is ##NaN, ##-Inf, ##Inf => ##NaN\n  If a is zero => zero with the same sign as a\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sin-double-"
+    cos "Returns the cosine of an angle.\n  If a is ##NaN, ##-Inf, ##Inf => ##NaN\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cos-double-"
+    tan "Returns the tangent of an angle.\n  If a is ##NaN, ##-Inf, ##Inf => ##NaN\n  If a is zero => zero with the same sign as a\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#tan-double-"
+    asin "Returns the arc sine of an angle, in the range -pi/2 to pi/2.\n  If a is ##NaN or |a|>1 => ##NaN\n  If a is zero => zero with the same sign as a\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#asin-double-"
+    acos "Returns the arc cosine of a, in the range 0.0 to pi.\n  If a is ##NaN or |a|>1 => ##NaN\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#acos-double-"
+    atan "Returns the arc tangent of a, in the range of -pi/2 to pi/2.\n  If a is ##NaN => ##NaN\n  If a is zero => zero with the same sign as a\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#atan-double-"
+    to-radians "Converts an angle in degrees to an approximate equivalent angle in radians.\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#toRadians-double-"
+    to-degrees "Converts an angle in radians to an approximate equivalent angle in degrees.\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#toDegrees-double-"
+    exp "Returns Euler's number e raised to the power of a.\n  If a is ##NaN => ##NaN\n  If a is ##Inf => ##Inf\n  If a is ##-Inf => +0.0\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#exp-double-"
+    log "Returns the natural logarithm (base e) of a.\n  If a is ##NaN or negative => ##NaN\n  If a is ##Inf => ##Inf\n  If a is zero => ##-Inf\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log-double-"
+    log10 "Returns the logarithm (base 10) of a.\n  If a is ##NaN or negative => ##NaN\n  If a is ##Inf => ##Inf\n  If a is zero => ##-Inf\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log10-double-"
+    sqrt "Returns the positive square root of a.\n  If a is ##NaN or negative => ##NaN\n  If a is ##Inf => ##Inf\n  If a is zero => a\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sqrt-double-"
+    cbrt "Returns the cube root of a.\n  If a is ##NaN => ##NaN\n  If a is ##Inf or ##-Inf => a\n  If a is zero => zero with sign matching a\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cbrt-double-"
+    IEEE-remainder "Returns the remainder per IEEE 754 such that\n    remainder = dividend - divisor * n\n  where n is the integer closest to the exact value of dividend / divisor.\n  If two integers are equally close, then n is the even one.\n  If the remainder is zero, sign will match dividend.\n  If dividend or divisor is ##NaN, or dividend is ##Inf or ##-Inf, or divisor is zero => ##NaN\n  If dividend is finite and divisor is infinite => dividend\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#IEEEremainder-double-double-"
+    ceil "Returns the smallest double greater than or equal to a, and equal to a\n  mathematical integer.\n  If a is ##NaN or ##Inf or ##-Inf or already equal to an integer => a\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#ceil-double-"
+    floor "Returns the largest double less than or equal to a, and equal to a\n  mathematical integer.\n  If a is ##NaN or ##Inf or ##-Inf or already equal to an integer => a\n  If a is less than zero but greater than -1.0 => -0.0\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floor-double-"
+    rint "Returns the double closest to a and equal to a mathematical integer.\n  If two values are equally close, return the even one.\n  If a is ##NaN or ##Inf or ##-Inf or zero => a\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#rint-double-"
+    atan2 "Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta).\n  Computes the phase theta by computing an arc tangent of y/x in the range of -pi to pi.\n  For more details on special cases, see:\n  https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#atan2-double-double-"
+    pow "Returns the value of a raised to the power of b.\n  For more details on special cases, see:\n  https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#pow-double-double-"
+    round "Returns the closest long to a. If equally close to two values, return the one\n  closer to ##Inf.\n  If a is ##NaN => 0\n  If a is ##-Inf or < Long/MIN_VALUE => Long/MIN_VALUE\n  If a is ##Inf or > Long/MAX_VALUE => Long/MAX_VALUE\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#round-double-"
+    random "Returns a positive double between 0.0 and 1.0, chosen pseudorandomly with\n  approximately random distribution.\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#random--"
+    add-exact "Returns the sum of x and y, throws ArithmeticException on overflow.\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#addExact-long-long-"
+    subtract-exact "Returns the difference of x and y, throws ArithmeticException on overflow.\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#subtractExact-long-long-"
+    multiply-exact "Returns the product of x and y, throws ArithmeticException on overflow.\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#multiplyExact-long-long-"
+    increment-exact "Returns a incremented by 1, throws ArithmeticException on overflow.\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#incrementExact-long-"
+    decrement-exact "Returns a decremented by 1, throws ArithmeticException on overflow.\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#decrementExact-long-"
+    negate-exact "Returns the negation of a, throws ArithmeticException on overflow.\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#negateExact-long-"
+    floor-div "Integer division that rounds to negative infinity (as opposed to zero).\n  The special case (floorDiv Long/MIN_VALUE -1) overflows and returns Long/MIN_VALUE.\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floorDiv-long-long-"
+    floor-mod "Integer modulus x - (floorDiv(x, y) * y). Sign matches y and is in the\n  range -|y| < r < |y|.\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floorMod-long-long-"
+    ulp "Returns the size of an ulp (unit in last place) for d.\n  If d is ##NaN => ##NaN\n  If d is ##Inf or ##-Inf => ##Inf\n  If d is zero => Double/MIN_VALUE\n  If d is +/- Double/MAX_VALUE => 2^971\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#ulp-double-"
+    signum "Returns the signum function of d - zero for zero, 1.0 if >0, -1.0 if <0.\n  If d is ##NaN => ##NaN\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#signum-double-"
+    sinh "Returns the hyperbolic sine of x, (e^x - e^-x)/2.\n  If x is ##NaN => ##NaN\n  If x is ##Inf or ##-Inf or zero => x\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sinh-double-"
+    cosh "Returns the hyperbolic cosine of x, (e^x + e^-x)/2.\n  If x is ##NaN => ##NaN\n  If x is ##Inf or ##-Inf => ##Inf\n  If x is zero => 1.0\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cosh-double-"
+    tanh "Returns the hyperbolic tangent of x, sinh(x)/cosh(x).\n  If x is ##NaN => ##NaN\n  If x is zero => zero, with same sign\n  If x is ##Inf => +1.0\n  If x is ##-Inf => -1.0\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#tanh-double-"
+    hypot "Returns sqrt(x^2 + y^2) without intermediate underflow or overflow.\n  If x or y is ##Inf or ##-Inf => ##Inf\n  If x or y is ##NaN and neither is ##Inf or ##-Inf => ##NaN\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#hypot-double-double-"
+    expm1 "Returns e^x - 1. Near 0, expm1(x)+1 is more accurate to e^x than exp(x).\n  If x is ##NaN => ##NaN\n  If x is ##Inf => #Inf\n  If x is ##-Inf => -1.0\n  If x is zero => x\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#expm1-double-"
+    log1p "Returns ln(1+x). For small values of x, log1p(x) is more accurate than\n  log(1.0+x).\n  If x is ##NaN or < -1 => ##NaN\n  If x is ##Inf => ##Inf\n  If x is -1 => ##-Inf\n  If x is 0 => 0 with sign matching x\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log1p-double-"
+    copy-sign "Returns a double with the magnitude of the first argument and the sign of\n  the second.\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#copySign-double-double-"
+    get-exponent "Returns the exponent of d.\n  If d is ##NaN, ##Inf, ##-Inf => Double/MAX_EXPONENT + 1\n  If d is zero or subnormal => Double/MIN_EXPONENT - 1\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#getExponent-double-"
+    next-after "Returns the adjacent floating point number to start in the direction of\n  the second argument. If the arguments are equal, the second is returned.\n  If either arg is #NaN => #NaN\n  If both arguments are signed zeros => direction\n  If start is +-Double/MIN_VALUE and direction would cause a smaller magnitude\n    => zero with sign matching start\n  If start is ##Inf or ##-Inf and direction would cause a smaller magnitude\n    => Double/MAX_VALUE with same sign as start\n  If start is equal to +=Double/MAX_VALUE and direction would cause a larger magnitude\n    => ##Inf or ##-Inf with sign matching start\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextAfter-double-double-"
+    next-up "Returns the adjacent double of d in the direction of ##Inf.\n  If d is ##NaN => ##NaN\n  If d is ##Inf => ##Inf\n  If d is zero => Double/MIN_VALUE\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextUp-double-"
+    next-down "Returns the adjacent double of d in the direction of ##-Inf.\n  If d is ##NaN => ##NaN\n  If d is ##-Inf => ##-Inf\n  If d is zero => -Double/MIN_VALUE\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextDown-double-"
+    scalb "Returns d * 2^scaleFactor, scaling by a factor of 2. If the exponent\n  is between Double/MIN_EXPONENT and Double/MAX_EXPONENT, the answer is exact.\n  If d is ##NaN => ##NaN\n  If d is ##Inf or ##-Inf => ##Inf or ##-Inf respectively\n  If d is zero => zero of same sign as d\n  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextDown-double-"
+    })
+
+(def FNS
+  '[sin cos tan asin acos atan toRadians toDegrees exp log log10
+    sqrt cbrt IEEEremainder ceil floor rint atan2 pow round random
+    addExact subtractExact multiplyExact incrementExact decrementExact negateExact
+    floorDiv floorMod ulp signum sinh cosh tanh hypot expm1 log1p copySign getExponent
+    nextAfter nextUp nextDown scalb])
+
+;; arg names to use (match java.lang.Math signatures)
+(def ARGS
+  '{
+    sin [a]
+    cos [a]
+    tan [a]
+    asin [a]
+    acos [a]
+    atan [a]
+    to-radians [deg]
+    to-degrees [r]
+    exp [a]
+    log [a]
+    log10 [a]
+    sqrt [a]
+    cbrt [a]
+    IEEE-remainder [dividend divisor]
+    ceil [a]
+    floor [a]
+    rint [a]
+    atan2 [y x]
+    pow [a b]
+    round [a]
+    random []
+    add-exact [x y]
+    subtract-exact [x y]
+    multiply-exact [x y]
+    increment-exact [a]
+    decrement-exact [a]
+    negate-exact [a]
+    floor-div [x y]
+    floor-mod [x y]
+    ulp [d]
+    signum [d]
+    sinh [x]
+    cosh [x]
+    tanh [x]
+    hypot [x y]
+    expm1 [x]
+    log1p [x]
+    copy-sign [magnitude sign]
+    get-exponent [d]
+    next-after [start direction]
+    next-up [d]
+    next-down [d]
+    scalb [d scaleFactor]
+    })
+
+;; type signature to use (otherwise automatically determined)
+(def ARGTYPES
+  '{scalb {:parameter-types [double int] :return-type double}})
diff --git a/src/clj/clojure/java/math.clj b/src/clj/clojure/math.clj
similarity index 83%
rename from src/clj/clojure/java/math.clj
rename to src/clj/clojure/math.clj
index 2d54fb52d7..c5b67b1f1c 100644
--- a/src/clj/clojure/java/math.clj
+++ b/src/clj/clojure/math.clj
@@ -17,8 +17,9 @@
 
   For more complete information, see:
   https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html"}
-  clojure.java.math
-  (:refer-clojure :exclude [min max]))
+  clojure.math)
+
+(set! *warn-on-reflection* true)
 
 (def
   ^{:doc "Constant for e, the base for natural logarithms.
@@ -44,7 +45,7 @@
   If a is zero => zero with the same sign as a
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sin-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/sin ~a))
+   :inline (fn [a] `(Math/sin (double ~a)))
    :added "1.11"}
   ^double [^double a]
   (Math/sin a))
@@ -54,7 +55,7 @@
   If a is ##NaN, ##-Inf, ##Inf => ##NaN
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cos-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/cos ~a))
+   :inline (fn [a] `(Math/cos (double ~a)))
    :added "1.11"}
   ^double [^double a]
   (Math/cos a))
@@ -65,7 +66,7 @@
   If a is zero => zero with the same sign as a
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#tan-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/tan ~a))
+   :inline (fn [a] `(Math/tan (double ~a)))
    :added "1.11"}
   ^double [^double a]
   (Math/tan a))
@@ -76,7 +77,7 @@
   If a is zero => zero with the same sign as a
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#asin-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/asin ~a))
+   :inline (fn [a] `(Math/asin (double ~a)))
    :added "1.11"}
   ^double [^double a]
   (Math/asin a))
@@ -86,7 +87,7 @@
   If a is ##NaN or |a|>1 => ##NaN
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#acos-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/acos ~a))
+   :inline (fn [a] `(Math/acos (double ~a)))
    :added "1.11"}
   ^double [^double a]
   (Math/acos a))
@@ -97,7 +98,7 @@
   If a is zero => zero with the same sign as a
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#atan-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/atan ~a))
+   :inline (fn [a] `(Math/atan (double ~a)))
    :added "1.11"}
   ^double [^double a]
   (Math/atan a))
@@ -106,7 +107,7 @@
   {:doc "Converts an angle in degrees to an approximate equivalent angle in radians.
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#toRadians-double-"
    :inline-arities #{1}
-   :inline (fn [deg] `(Math/toRadians ~deg))
+   :inline (fn [deg] `(Math/toRadians (double ~deg)))
    :added "1.11"}
   ^double [^double deg]
   (Math/toRadians deg))
@@ -115,7 +116,7 @@
   {:doc "Converts an angle in radians to an approximate equivalent angle in degrees.
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#toDegrees-double-"
    :inline-arities #{1}
-   :inline (fn [r] `(Math/toDegrees ~r))
+   :inline (fn [r] `(Math/toDegrees (double ~r)))
    :added "1.11"}
   ^double [^double r]
   (Math/toDegrees r))
@@ -127,7 +128,7 @@
   If a is ##-Inf => +0.0
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#exp-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/exp ~a))
+   :inline (fn [a] `(Math/exp (double ~a)))
    :added "1.11"}
   ^double [^double a]
   (Math/exp a))
@@ -139,7 +140,7 @@
   If a is zero => ##-Inf
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/log ~a))
+   :inline (fn [a] `(Math/log (double ~a)))
    :added "1.11"}
   ^double [^double a]
   (Math/log a))
@@ -151,7 +152,7 @@
   If a is zero => ##-Inf
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log10-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/log10 ~a))
+   :inline (fn [a] `(Math/log10 (double ~a)))
    :added "1.11"}
   ^double [^double a]
   (Math/log10 a))
@@ -163,7 +164,7 @@
   If a is zero => a
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sqrt-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/sqrt ~a))
+   :inline (fn [a] `(Math/sqrt (double ~a)))
    :added "1.11"}
   ^double [^double a]
   (Math/sqrt a))
@@ -175,7 +176,7 @@
   If a is zero => zero with sign matching a
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cbrt-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/cbrt ~a))
+   :inline (fn [a] `(Math/cbrt (double ~a)))
    :added "1.11"}
   ^double [^double a]
   (Math/cbrt a))
@@ -190,7 +191,7 @@
   If dividend is finite and divisor is infinite => dividend
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#IEEEremainder-double-double-"
    :inline-arities #{2}
-   :inline (fn [dividend divisor] `(Math/IEEEremainder ~dividend ~divisor))
+   :inline (fn [dividend divisor] `(Math/IEEEremainder (double ~dividend) (double ~divisor)))
    :added "1.11"}
   ^double [^double dividend ^double divisor]
   (Math/IEEEremainder dividend divisor))
@@ -201,7 +202,7 @@
   If a is ##NaN or ##Inf or ##-Inf or already equal to an integer => a
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#ceil-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/ceil ~a))
+   :inline (fn [a] `(Math/ceil (double ~a)))
    :added "1.11"}
   ^double [^double a]
   (Math/ceil a))
@@ -213,7 +214,7 @@
   If a is less than zero but greater than -1.0 => -0.0
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floor-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/floor ~a))
+   :inline (fn [a] `(Math/floor (double ~a)))
    :added "1.11"}
   ^double [^double a]
   (Math/floor a))
@@ -224,7 +225,7 @@
   If a is ##NaN or ##Inf or ##-Inf or zero => a
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#rint-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/rint ~a))
+   :inline (fn [a] `(Math/rint (double ~a)))
    :added "1.11"}
   ^double [^double a]
   (Math/rint a))
@@ -235,7 +236,7 @@
   For more details on special cases, see:
   https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#atan2-double-double-"
    :inline-arities #{2}
-   :inline (fn [y x] `(Math/atan2 ~y ~x))
+   :inline (fn [y x] `(Math/atan2 (double ~y) (double ~x)))
    :added "1.11"}
   ^double [^double y ^double x]
   (Math/atan2 y x))
@@ -245,7 +246,7 @@
   For more details on special cases, see:
   https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#pow-double-double-"
    :inline-arities #{2}
-   :inline (fn [a b] `(Math/pow ~a ~b))
+   :inline (fn [a b] `(Math/pow (double ~a) (double ~b)))
    :added "1.11"}
   ^double [^double a ^double b]
   (Math/pow a b))
@@ -258,7 +259,7 @@
   If a is ##Inf or > Long/MAX_VALUE => Long/MAX_VALUE
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#round-double-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/round ~a))
+   :inline (fn [a] `(Math/round (double ~a)))
    :added "1.11"}
   ^long [^double a]
   (Math/round a))
@@ -277,7 +278,7 @@
   {:doc "Returns the sum of x and y, throws ArithmeticException on overflow.
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#addExact-long-long-"
    :inline-arities #{2}
-   :inline (fn [x y] `(Math/addExact ~x ~y))
+   :inline (fn [x y] `(Math/addExact (long ~x) (long ~y)))
    :added "1.11"}
   ^long [^long x ^long y]
   (Math/addExact x y))
@@ -286,7 +287,7 @@
   {:doc "Returns the difference of x and y, throws ArithmeticException on overflow.
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#subtractExact-long-long-"
    :inline-arities #{2}
-   :inline (fn [x y] `(Math/subtractExact ~x ~y))
+   :inline (fn [x y] `(Math/subtractExact (long ~x) (long ~y)))
    :added "1.11"}
   ^long [^long x ^long y]
   (Math/subtractExact x y))
@@ -295,7 +296,7 @@
   {:doc "Returns the product of x and y, throws ArithmeticException on overflow.
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#multiplyExact-long-long-"
    :inline-arities #{2}
-   :inline (fn [x y] `(Math/multiplyExact ~x ~y))
+   :inline (fn [x y] `(Math/multiplyExact (long ~x) (long ~y)))
    :added "1.11"}
   ^long [^long x ^long y]
   (Math/multiplyExact x y))
@@ -304,7 +305,7 @@
   {:doc "Returns a incremented by 1, throws ArithmeticException on overflow.
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#incrementExact-long-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/incrementExact ~a))
+   :inline (fn [a] `(Math/incrementExact (long ~a)))
    :added "1.11"}
   ^long [^long a]
   (Math/incrementExact a))
@@ -313,16 +314,16 @@
   {:doc "Returns a decremented by 1, throws ArithmeticException on overflow.
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#decrementExact-long-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/decrementExact ~a))
+   :inline (fn [a] `(Math/decrementExact (long ~a)))
    :added "1.11"}
   ^long [^long a]
   (Math/decrementExact a))
 
-(defn negative-exact
+(defn negate-exact
   {:doc "Returns the negation of a, throws ArithmeticException on overflow.
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#negateExact-long-"
    :inline-arities #{1}
-   :inline (fn [a] `(Math/negateExact ~a))
+   :inline (fn [a] `(Math/negateExact (long ~a)))
    :added "1.11"}
   ^long [^long a]
   (Math/negateExact a))
@@ -332,7 +333,7 @@
   The special case (floorDiv Long/MIN_VALUE -1) overflows and returns Long/MIN_VALUE.
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floorDiv-long-long-"
    :inline-arities #{2}
-   :inline (fn [x y] `(Math/floorDiv ~x ~y))
+   :inline (fn [x y] `(Math/floorDiv (long ~x) (long ~y)))
    :added "1.11"}
   ^long [^long x ^long y]
   (Math/floorDiv x y))
@@ -342,47 +343,11 @@
   range -|y| < r < |y|.
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#floorMod-long-long-"
    :inline-arities #{2}
-   :inline (fn [x y] `(Math/floorMod ~x ~y))
+   :inline (fn [x y] `(Math/floorMod (long ~x) (long ~y)))
    :added "1.11"}
   ^long [^long x ^long y]
   (Math/floorMod x y))
 
-(defn abs
-  {:doc "Returns the absolute value of a (long or double).
-  If not negative, a is returned, else negation of a is returned.
-  If a is Long/MIN_VALUE => Long/MIN_VALUE
-  If a is a double and zero => +0.0
-  If a is a double and ##Inf or ##-Inf => ##Inf
-  If a is a double and ##NaN => ##NaN
-  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#abs-long-"
-   :inline-arities #{1}
-   :inline (fn [a] `(Math/abs ~a))
-   :added "1.11"}
-  [a]
-  (Math/abs a))
-
-(defn max
-  {:doc "Returns the greater of a or b.
-  If doubles and a or b is ##NaN => ##NaN
-  If doubles and one is negative zero, other positive zero => positive zero
-  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#max-long-long-"
-   :inline-arities #{2}
-   :inline (fn [a b] `(Math/max ~a ~b))
-   :added "1.11"}
-  [a b]
-  (Math/max a b))
-
-(defn min
-  {:doc "Returns the lesser of a or b.
-  If doubles and a or b is ##NaN => ##NaN
-  If doubles and one is negative zero, other positive zero => negative zero
-  See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#min-double-double-"
-   :inline-arities #{2}
-   :inline (fn [p0 p1] `(Math/min ~p0 ~p1))
-   :added "1.11"}
-  [p0 p1]
-  (Math/min p0 p1))
-
 (defn ulp
   {:doc "Returns the size of an ulp (unit in last place) for d.
   If d is ##NaN => ##NaN
@@ -391,7 +356,7 @@
   If d is +/- Double/MAX_VALUE => 2^971
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#ulp-double-"
    :inline-arities #{1}
-   :inline (fn [d] `(Math/ulp ~d))
+   :inline (fn [d] `(Math/ulp (double ~d)))
    :added "1.11"}
   ^double [^double d]
   (Math/ulp d))
@@ -399,10 +364,9 @@
 (defn signum
   {:doc "Returns the signum function of d - zero for zero, 1.0 if >0, -1.0 if <0.
   If d is ##NaN => ##NaN
-  If d is ##Inf or ##-Inf => d
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#signum-double-"
    :inline-arities #{1}
-   :inline (fn [d] `(Math/signum ~d))
+   :inline (fn [d] `(Math/signum (double ~d)))
    :added "1.11"}
   ^double [^double d]
   (Math/signum d))
@@ -413,7 +377,7 @@
   If x is ##Inf or ##-Inf or zero => x
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#sinh-double-"
    :inline-arities #{1}
-   :inline (fn [x] `(Math/sinh ~x))
+   :inline (fn [x] `(Math/sinh (double ~x)))
    :added "1.11"}
   ^double [^double x]
   (Math/sinh x))
@@ -425,7 +389,7 @@
   If x is zero => 1.0
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#cosh-double-"
    :inline-arities #{1}
-   :inline (fn [x] `(Math/cosh ~x))
+   :inline (fn [x] `(Math/cosh (double ~x)))
    :added "1.11"}
   ^double [^double x]
   (Math/cosh x))
@@ -438,7 +402,7 @@
   If x is ##-Inf => -1.0
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#tanh-double-"
    :inline-arities #{1}
-   :inline (fn [x] `(Math/tanh ~x))
+   :inline (fn [x] `(Math/tanh (double ~x)))
    :added "1.11"}
   ^double [^double x]
   (Math/tanh x))
@@ -449,7 +413,7 @@
   If x or y is ##NaN and neither is ##Inf or ##-Inf => ##NaN
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#hypot-double-double-"
    :inline-arities #{2}
-   :inline (fn [x y] `(Math/hypot ~x ~y))
+   :inline (fn [x y] `(Math/hypot (double ~x) (double ~y)))
    :added "1.11"}
   ^double [^double x ^double y]
   (Math/hypot x y))
@@ -462,7 +426,7 @@
   If x is zero => x
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#expm1-double-"
    :inline-arities #{1}
-   :inline (fn [x] `(Math/expm1 ~x))
+   :inline (fn [x] `(Math/expm1 (double ~x)))
    :added "1.11"}
   ^double [^double x]
   (Math/expm1 x))
@@ -471,10 +435,12 @@
   {:doc "Returns ln(1+x). For small values of x, log1p(x) is more accurate than
   log(1.0+x).
   If x is ##NaN or < -1 => ##NaN
-  If x is ##Inf or ##-Inf or x => x
+  If x is ##Inf => ##Inf
+  If x is -1 => ##-Inf
+  If x is 0 => 0 with sign matching x
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#log1p-double-"
    :inline-arities #{1}
-   :inline (fn [x] `(Math/log1p ~x))
+   :inline (fn [x] `(Math/log1p (double ~x)))
    :added "1.11"}
   ^double [^double x]
   (Math/log1p x))
@@ -484,7 +450,7 @@
   the second.
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#copySign-double-double-"
    :inline-arities #{2}
-   :inline (fn [magnitude sign] `(Math/copySign ~magnitude ~sign))
+   :inline (fn [magnitude sign] `(Math/copySign (double ~magnitude) (double ~sign)))
    :added "1.11"}
   ^double [^double magnitude ^double sign]
   (Math/copySign magnitude sign))
@@ -495,7 +461,7 @@
   If d is zero or subnormal => Double/MIN_EXPONENT - 1
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#getExponent-double-"
    :inline-arities #{1}
-   :inline (fn [d] `(Math/getExponent ~d))
+   :inline (fn [d] `(Math/getExponent (double ~d)))
    :added "1.11"}
   [^double d]
   (Math/getExponent d))
@@ -513,7 +479,7 @@
     => ##Inf or ##-Inf with sign matching start
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextAfter-double-double-"
    :inline-arities #{2}
-   :inline (fn [start direction] `(Math/nextAfter ~start ~direction))
+   :inline (fn [start direction] `(Math/nextAfter (double ~start) (double ~direction)))
    :added "1.11"}
   ^double [^double start ^double direction]
   (Math/nextAfter start direction))
@@ -525,7 +491,7 @@
   If d is zero => Double/MIN_VALUE
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextUp-double-"
    :inline-arities #{1}
-   :inline (fn [d] `(Math/nextUp ~d))
+   :inline (fn [d] `(Math/nextUp (double ~d)))
    :added "1.11"}
   ^double [^double d]
   (Math/nextUp d))
@@ -533,11 +499,11 @@
 (defn next-down
   {:doc "Returns the adjacent double of d in the direction of ##-Inf.
   If d is ##NaN => ##NaN
-  If d is ##Inf => ##-Inf
-  If d is zero => Double/MIN_VALUE
+  If d is ##-Inf => ##-Inf
+  If d is zero => -Double/MIN_VALUE
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextDown-double-"
    :inline-arities #{1}
-   :inline (fn [d] `(Math/nextDown ~d))
+   :inline (fn [d] `(Math/nextDown (double ~d)))
    :added "1.11"}
   ^double [^double d]
   (Math/nextDown d))
@@ -549,8 +515,9 @@
   If d is ##Inf or ##-Inf => ##Inf or ##-Inf respectively
   If d is zero => zero of same sign as d
   See: https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#nextDown-double-"
-   :inline-arities #{1}
-   :inline (fn [d scaleFactor] `(Math/scalb ~d ~scaleFactor))
+   :inline-arities #{2}
+   :inline (fn [d scaleFactor] `(Math/scalb (double ~d) (int ~scaleFactor)))
    :added "1.11"}
   ^double [^double d scaleFactor]
-  (Math/scalb d scaleFactor))
\ No newline at end of file
+  (Math/scalb d (int scaleFactor)))
+
diff --git a/test/clojure/test_clojure/math.clj b/test/clojure/test_clojure/math.clj
new file mode 100644
index 0000000000..63975e7505
--- /dev/null
+++ b/test/clojure/test_clojure/math.clj
@@ -0,0 +1,320 @@
+;   Copyright (c) Rich Hickey. All rights reserved.
+;   The use and distribution terms for this software are covered by the
+;   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
+;   which can be found in the file epl-v10.html at the root of this distribution.
+;   By using this software in any fashion, you are agreeing to be bound by
+;   the terms of this license.
+;   You must not remove this notice, or any other, from this software.
+
+(ns clojure.test-clojure.math
+  (:require
+    [clojure.test :refer :all]
+    [clojure.math :as m]))
+
+(set! *warn-on-reflection* true)
+
+(defn neg-zero?
+  [^double d]
+  (and (zero? d) (< (Double/compare d 0.0) 0)))
+
+(defn pos-zero?
+  [^double d]
+  (and (zero? d) (not (< (Double/compare d 0.0) 0))))
+
+(deftest test-sin
+  (is (NaN? (m/sin ##NaN)))
+  (is (NaN? (m/sin ##-Inf)))
+  (is (NaN? (m/sin ##Inf)))
+  (is (pos-zero? (m/sin 0.0)))
+  (is (neg-zero? (m/sin -0.0)))
+  (is (= (m/sin m/PI) (- (m/sin (- m/PI))))))
+
+(deftest test-cos
+  (is (NaN? (m/cos ##NaN)))
+  (is (NaN? (m/cos ##-Inf)))
+  (is (NaN? (m/cos ##Inf)))
+  (is (= 1.0 (m/cos 0.0) (m/cos -0.0)))
+  (is (= (m/cos m/PI) (m/cos (- m/PI)))))
+
+(deftest test-tan
+  (is (NaN? (m/tan ##NaN)))
+  (is (NaN? (m/tan ##-Inf)))
+  (is (NaN? (m/tan ##Inf)))
+  (is (pos-zero? (m/tan 0.0)))
+  (is (neg-zero? (m/tan -0.0)))
+  (is (= (- (m/tan m/PI)) (m/tan (- m/PI)))))
+
+(deftest test-asin
+  (is (NaN? (m/asin ##NaN)))
+  (is (NaN? (m/asin 2.0)))
+  (is (NaN? (m/asin -2.0)))
+  (is (zero? (m/asin -0.0))))
+
+(deftest test-acos
+  (is (NaN? (m/acos ##NaN)))
+  (is (NaN? (m/acos -2.0)))
+  (is (NaN? (m/acos 2.0)))
+  (is (= m/PI (* 2 (m/acos 0.0)))))
+
+(deftest test-atan
+  (is (NaN? (m/atan ##NaN)))
+  (is (pos-zero? (m/atan 0.0)))
+  (is (neg-zero? (m/atan -0.0)))
+  (is (= 0.7853981633974483 (m/atan 1))))
+
+(deftest test-radians-degrees-roundtrip
+  (doseq [d (range 0.0 360.0 5.0)]
+    (is (= (m/round d) (m/round (-> d m/to-radians m/to-degrees))))))
+
+(deftest test-exp
+  (is (NaN? (m/exp ##NaN)))
+  (is (= ##Inf (m/exp ##Inf)))
+  (is (pos-zero? (m/exp ##-Inf)))
+  (is (= 1.0 (m/exp 0.0)))
+  (is (= m/E (m/exp 1))))
+
+(deftest test-log
+  (is (NaN? (m/log ##NaN)))
+  (is (NaN? (m/log -1.0)))
+  (is (= ##Inf (m/log ##Inf)))
+  (is (= ##-Inf (m/log 0.0)))
+  (is (= 1.0 (m/log m/E))))
+
+(deftest test-log10
+  (is (NaN? (m/log10 ##NaN)))
+  (is (NaN? (m/log10 -1.0)))
+  (is (= ##Inf (m/log10 ##Inf)))
+  (is (= ##-Inf (m/log10 0.0)))
+  (is (= 1.0 (m/log10 10))))
+
+(deftest test-sqrt
+  (is (NaN? (m/sqrt ##NaN)))
+  (is (NaN? (m/sqrt -1.0)))
+  (is (= ##Inf (m/sqrt ##Inf)))
+  (is (pos-zero? (m/sqrt 0)))
+  (is (= 2.0 (m/sqrt 4.0))))
+
+(deftest test-cbrt
+  (is (NaN? (m/cbrt ##NaN)))
+  (is (= ##-Inf (m/cbrt ##-Inf)))
+  (is (= ##Inf (m/cbrt ##Inf)))
+  (is (pos-zero? (m/cbrt 0)))
+  (is (= 2.0 (m/cbrt 8.0))))
+
+(deftest test-IEEE-remainder
+  (is (NaN? (m/IEEE-remainder ##NaN 1.0)))
+  (is (NaN? (m/IEEE-remainder 1.0 ##NaN)))
+  (is (NaN? (m/IEEE-remainder ##Inf 2.0)))
+  (is (NaN? (m/IEEE-remainder ##-Inf 2.0)))
+  (is (NaN? (m/IEEE-remainder 2 0.0)))
+  (is (= 1.0 (m/IEEE-remainder 5.0 4.0))))
+
+(deftest test-ceil
+  (is (NaN? (m/ceil ##NaN)))
+  (is (= ##Inf (m/ceil ##Inf)))
+  (is (= ##-Inf (m/ceil ##-Inf)))
+  (is (= 4.0 (m/ceil m/PI))))
+
+(deftest test-floor
+  (is (NaN? (m/floor ##NaN)))
+  (is (= ##Inf (m/floor ##Inf)))
+  (is (= ##-Inf (m/floor ##-Inf)))
+  (is (= 3.0 (m/floor m/PI))))
+
+(deftest test-rint
+  (is (NaN? (m/rint ##NaN)))
+  (is (= ##Inf (m/rint ##Inf)))
+  (is (= ##-Inf (m/rint ##-Inf)))
+  (is (= 1.0 (m/rint 1.2)))
+  (is (neg-zero? (m/rint -0.01))))
+
+(deftest test-atan2
+  (is (NaN? (m/atan2 ##NaN 1.0)))
+  (is (NaN? (m/atan2 1.0 ##NaN)))
+  (is (pos-zero? (m/atan2 0.0 1.0)))
+  (is (neg-zero? (m/atan2 -0.0 1.0)))
+  (is (= m/PI (m/atan2 0.0 -1.0)))
+  (is (= (- m/PI) (m/atan2 -0.0 -1.0)))
+  (is (= m/PI (* 2.0 (m/atan2 1.0 0.0))))
+  (is (= m/PI (* -2.0 (m/atan2 -1.0 0.0))))
+  (is (= m/PI (* 4.0 (m/atan2 ##Inf ##Inf))))
+  (is (= m/PI (/ (* 4.0 (m/atan2 ##Inf ##-Inf)) 3.0)))
+  (is (= m/PI (* -4.0 (m/atan2 ##-Inf ##Inf))))
+  (is (= m/PI (/ (* -4.0 (m/atan2 ##-Inf ##-Inf)) 3.0))))
+
+(deftest test-pow
+  (is (= 1.0 (m/pow 4.0 0.0)))
+  (is (= 1.0 (m/pow 4.0 -0.0)))
+  (is (= 4.2 (m/pow 4.2 1.0)))
+  (is (NaN? (m/pow 4.2 ##NaN)))
+  (is (NaN? (m/pow ##NaN 2.0)))
+  (is (= ##Inf (m/pow 2.0 ##Inf)))
+  (is (= ##Inf (m/pow 0.5 ##-Inf)))
+  (is (= 0.0 (m/pow 2.0 ##-Inf)))
+  (is (= 0.0 (m/pow 0.5 ##Inf)))
+  (is (NaN? (m/pow 1.0 ##Inf)))
+  (is (pos-zero? (m/pow 0.0 1.5)))
+  (is (pos-zero? (m/pow ##Inf -2.0)))
+  (is (= ##Inf (m/pow 0.0 -2.0)))
+  (is (= ##Inf (m/pow ##Inf 2.0)))
+  (is (pos-zero? (m/pow -0.0 1.5)))
+  (is (pos-zero? (m/pow ##-Inf -1.5)))
+  (is (neg-zero? (m/pow -0.0 3.0)))
+  (is (neg-zero? (m/pow ##-Inf -3.0)))
+  (is (= ##Inf (m/pow -0.0 -1.5)))
+  (is (= ##Inf (m/pow ##-Inf 2.5)))
+  (is (= ##-Inf (m/pow -0.0 -3.0)))
+  (is (= ##-Inf (m/pow ##-Inf 3.0)))
+  (is (= 4.0 (m/pow -2.0 2.0)))
+  (is (= -8.0 (m/pow -2.0 3.0)))
+  (is (= 8.0 (m/pow 2.0 3.0))))
+
+(deftest test-round
+  (is (= 0 (m/round ##NaN)))
+  (is (= Long/MIN_VALUE (m/round ##-Inf)))
+  (is (= Long/MIN_VALUE (m/round (- Long/MIN_VALUE 2.0))))
+  (is (= Long/MAX_VALUE (m/round ##Inf)))
+  (is (= Long/MAX_VALUE (m/round (+ Long/MAX_VALUE 2.0))))
+  (is (= 4 (m/round 3.5))))
+
+(deftest test-add-exact
+  (try
+    (m/add-exact Long/MAX_VALUE 1)
+    (is false)
+    (catch ArithmeticException _
+      (is true))))
+
+(deftest test-subtract-exact
+  (try
+    (m/subtract-exact Long/MIN_VALUE 1)
+    (is false)
+    (catch ArithmeticException _
+      (is true))))
+
+(deftest test-multiply-exact
+  (try
+    (m/multiply-exact Long/MAX_VALUE 2)
+    (is false)
+    (catch ArithmeticException _
+      (is true))))
+
+(deftest test-increment-exact
+  (try
+    (m/increment-exact Long/MAX_VALUE)
+    (is false)
+    (catch ArithmeticException _
+      (is true))))
+
+(deftest test-decrement-exact
+  (try
+    (m/decrement-exact Long/MIN_VALUE)
+    (is false)
+    (catch ArithmeticException _
+      (is true))))
+
+(deftest test-negate-exact
+  (is (= (inc Long/MIN_VALUE) (m/negate-exact Long/MAX_VALUE)))
+  (try
+    (m/negate-exact Long/MIN_VALUE)
+    (is false)
+    (catch ArithmeticException _
+      (is true))))
+
+(deftest test-floor-div
+  (is (= Long/MIN_VALUE (m/floor-div Long/MIN_VALUE -1)))
+  (is (= -1 (m/floor-div -2 5))))
+
+(deftest test-floor-mod
+  (is (= 3 (m/floor-mod -2 5))))
+
+(deftest test-ulp
+  (is (NaN? (m/ulp ##NaN)))
+  (is (= ##Inf (m/ulp ##Inf)))
+  (is (= ##Inf (m/ulp ##-Inf)))
+  (is (= Double/MIN_VALUE (m/ulp 0.0)))
+  (is (= (m/pow 2 971) (m/ulp Double/MAX_VALUE)))
+  (is (= (m/pow 2 971) (m/ulp (- Double/MAX_VALUE)))))
+
+(deftest test-signum
+  (is (NaN? (m/signum ##NaN)))
+  (is (zero? (m/signum 0.0)))
+  (is (zero? (m/signum -0.0)))
+  (is (= 1.0 (m/signum 42.0)))
+  (is (= -1.0 (m/signum -42.0))))
+
+(deftest test-sinh
+  (is (NaN? (m/sinh ##NaN)))
+  (is (= ##Inf (m/sinh ##Inf)))
+  (is (= ##-Inf (m/sinh ##-Inf)))
+  (is (= 0.0 (m/sinh 0.0))))
+
+(deftest test-cosh
+  (is (NaN? (m/cosh ##NaN)))
+  (is (= ##Inf (m/cosh ##Inf)))
+  (is (= ##Inf (m/cosh ##-Inf)))
+  (is (= 1.0 (m/cosh 0.0))))
+
+(deftest test-tanh
+  (is (NaN? (m/tanh ##NaN)))
+  (is (= 1.0 (m/tanh ##Inf)))
+  (is (= -1.0 (m/tanh ##-Inf)))
+  (is (= 0.0 (m/tanh 0.0))))
+
+(deftest test-hypot
+  (is (= ##Inf (m/hypot 1.0 ##Inf)))
+  (is (= ##Inf (m/hypot ##Inf 1.0)))
+  (is (NaN? (m/hypot ##NaN 1.0)))
+  (is (NaN? (m/hypot 1.0 ##NaN)))
+  (is (= 13.0 (m/hypot 5.0 12.0))))
+
+(deftest test-expm1
+  (is (NaN? (m/expm1 ##NaN)))
+  (is (= ##Inf (m/expm1 ##Inf)))
+  (is (= -1.0 (m/expm1 ##-Inf)))
+  (is (= 0.0 (m/expm1 0.0))))
+
+(deftest test-log1p
+  (is (NaN? (m/log1p ##NaN)))
+  (is (= ##Inf (m/log1p ##Inf)))
+  (is (= ##-Inf (m/log1p -1.0)))
+  (is (pos-zero? (m/log1p 0.0)))
+  (is (neg-zero? (m/log1p -0.0))))
+
+(deftest test-copy-sign
+  (is (= 1.0 (m/copy-sign 1.0 42.0)))
+  (is (= -1.0 (m/copy-sign 1.0 -42.0)))
+  (is (= -1.0 (m/copy-sign 1.0 ##-Inf))))
+
+(deftest test-get-exponent
+  (is (= (inc Double/MAX_EXPONENT) (m/get-exponent ##NaN)))
+  (is (= (inc Double/MAX_EXPONENT) (m/get-exponent ##Inf)))
+  (is (= (inc Double/MAX_EXPONENT) (m/get-exponent ##-Inf)))
+  (is (= (dec Double/MIN_EXPONENT) (m/get-exponent 0.0)))
+  (is (= 0 (m/get-exponent 1.0)))
+  (is (= 13 (m/get-exponent 12345.678))))
+
+(deftest test-next-after
+  (is (NaN? (m/next-after ##NaN 1)))
+  (is (NaN? (m/next-after 1 ##NaN)))
+  (is (pos-zero? (m/next-after 0.0 0.0)))
+  (is (neg-zero? (m/next-after -0.0 -0.0)))
+  (is (= Double/MAX_VALUE (m/next-after ##Inf 1.0)))
+  (is (pos-zero? (m/next-after Double/MIN_VALUE -1.0))))
+
+(deftest test-next-up
+  (is (NaN? (m/next-up ##NaN)))
+  (is (= ##Inf (m/next-up ##Inf)))
+  (is (= Double/MIN_VALUE (m/next-up 0.0))))
+
+(deftest test-next-down
+  (is (NaN? (m/next-down ##NaN)))
+  (is (= ##-Inf (m/next-down ##-Inf)))
+  (is (= (- Double/MIN_VALUE) (m/next-down 0.0))))
+
+(deftest test-scalb
+  (is (NaN? (m/scalb ##NaN 1)))
+  (is (= ##Inf (m/scalb ##Inf 1)))
+  (is (= ##-Inf (m/scalb ##-Inf 1)))
+  (is (pos-zero? (m/scalb 0.0 2)))
+  (is (neg-zero? (m/scalb -0.0 2)))
+  (is (= 32.0 (m/scalb 2.0 4))))

From ff61321179a0b0f7d2c17a394ade80465ac15c28 Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Mon, 10 Jan 2022 13:52:31 -0600
Subject: [PATCH 083/285] CLJ-2673 Implement abs/min/max in clojure.core with
 polymorphic numeric support

Signed-off-by: Alex Miller 
---
 src/clj/clojure/core.clj              | 12 +++++++
 src/jvm/clojure/lang/Numbers.java     | 51 +++++++++++++++++++++------
 test/clojure/test_clojure/numbers.clj | 14 ++++++++
 3 files changed, 67 insertions(+), 10 deletions(-)

diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index 0dba6fcd97..7c8cb1804a 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -1134,6 +1134,18 @@
   ([x y & more]
    (reduce1 min (min x y) more)))
 
+(defn abs
+  {:doc "Returns the absolute value of a.
+  If a is Long/MIN_VALUE => Long/MIN_VALUE
+  If a is a double and zero => +0.0
+  If a is a double and ##Inf or ##-Inf => ##Inf
+  If a is a double and ##NaN => ##NaN"
+   :inline-arities #{1}
+   :inline (fn [a] `(clojure.lang.Numbers/abs ~a))
+   :added "1.11"}
+  [a]
+  (clojure.lang.Numbers/abs a))
+
 (defn dec'
   "Returns a number one less than num. Supports arbitrary precision.
   See also: dec"
diff --git a/src/jvm/clojure/lang/Numbers.java b/src/jvm/clojure/lang/Numbers.java
index fa13cba62c..6405bc2193 100644
--- a/src/jvm/clojure/lang/Numbers.java
+++ b/src/jvm/clojure/lang/Numbers.java
@@ -68,6 +68,8 @@ static interface Ops{
 	public Number dec(Number x);
 	public Number decP(Number x);
 	public Number unchecked_dec(Number x);
+
+	public Number abs(Number x);
 }
 
 static abstract class OpsP implements Ops{
@@ -619,6 +621,10 @@ public Number unchecked_dec(Number x){
 		long val = x.longValue();
 		return num(Numbers.unchecked_dec(val));
 	}
+
+	public Number abs(Number x){
+		return num(Math.abs(x.longValue()));
+	}
 }
 
 final static class DoubleOps extends OpsP{
@@ -706,6 +712,10 @@ public Number inc(Number x){
 	public Number dec(Number x){
 		return Double.valueOf(x.doubleValue() - 1);
 	}
+
+	public Number abs(Number x) {
+		return num(Math.abs(x.doubleValue()));
+	}
 }
 
 final static class RatioOps extends OpsP{
@@ -837,6 +847,11 @@ public Number dec(Number x){
 		return Numbers.add(x, -1);
 	}
 
+	public Number abs(Number x) {
+		Ratio r = (Ratio) x;
+		return new Ratio(r.numerator.abs(), r.denominator);
+	}
+
 }
 
 final static class BigIntOps extends OpsP{
@@ -935,6 +950,10 @@ public Number dec(Number x){
 		BigInteger bx = toBigInteger(x);
 		return BigInt.fromBigInteger(bx.subtract(BigInteger.ONE));
 	}
+
+	public Number abs(Number x) {
+		return BigInt.fromBigInteger(toBigInteger(x).abs());
+	}
 }
 
 
@@ -1054,6 +1073,14 @@ public Number dec(Number x){
 		       ? bx.subtract(BigDecimal.ONE)
 		       : bx.subtract(BigDecimal.ONE, mc);
 	}
+
+	public Number abs(Number x) {
+		MathContext mc = (MathContext) MATH_CONTEXT.deref();
+		BigDecimal bx = (BigDecimal) x;
+		return mc == null
+				? ((BigDecimal) x).abs()
+				: ((BigDecimal) x).abs(mc);
+	}
 }
 
 static final LongOps LONG_OPS = new LongOps();
@@ -4068,11 +4095,7 @@ static public Object max(long x, double y){
 
 
 static public long max(long x, long y){
-	if(x > y) {
-		return x;
-	} else {
-		return y;
-	}
+	return Math.max(x, y);
 }
 
 
@@ -4166,11 +4189,7 @@ static public Object min(long x, double y){
 
 
 static public long min(long x, long y){
-	if(x < y) {
-		return x;
-	} else {
-		return y;
-	}
+	return Math.min(x, y);
 }
 
 static public Object min(long x, Object y){
@@ -4221,4 +4240,16 @@ static public Object min(Object x, Object y){
 	}
 }
 
+static public long abs(long x){
+	return Math.abs(x);
+}
+
+static public double abs(double x){
+	return Math.abs(x);
+}
+
+static public Number abs(Object x) {
+	return ops(x).abs((Number)x);
+}
+
 }
diff --git a/test/clojure/test_clojure/numbers.clj b/test/clojure/test_clojure/numbers.clj
index 26140a7c29..cc62a63c89 100644
--- a/test/clojure/test_clojure/numbers.clj
+++ b/test/clojure/test_clojure/numbers.clj
@@ -644,6 +644,20 @@ Math/pow overflows to Infinity."
     (is (= java.lang.Long (class (min 1.0 2.0 -10))))
     (is (= java.lang.Double (class (min 1 2 -10.0 3 4 5))))))
 
+(deftest test-abs
+  (are [in ex] (= ex (abs in))
+    -1 1
+    1 1
+    Long/MIN_VALUE Long/MIN_VALUE ;; special case!
+    -1.0 1.0
+    -0.0 0.0
+    ##-Inf ##Inf
+    ##Inf ##Inf
+    -123.456M 123.456M
+    -123N 123N
+    -1/5 1/5)
+  (is (NaN? (abs ##NaN))))
+
 (deftest clj-868
   (testing "min/max: NaN is contagious"
     (letfn [(fnan? [^Float x] (Float/isNaN x))

From bf0c0e23a0e05509c785598be19b01c2b8e80bb5 Mon Sep 17 00:00:00 2001
From: Paula Gearon 
Date: Tue, 14 Dec 2021 10:44:30 -0500
Subject: [PATCH 084/285] CLJ-2679 quoting condition values that are generated
 for case-hash collisions

Signed-off-by: Alex Miller 
---
 src/clj/clojure/core.clj              | 2 +-
 test/clojure/test_clojure/control.clj | 9 ++++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index 7c8cb1804a..72a4548eb3 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -6702,7 +6702,7 @@ fails, attempts to require sym's namespace and retries."
                       (next ks) (next vs))
                     m))
         assoc-multi (fn [m h bucket]
-                      (let [testexprs (apply concat bucket)
+                      (let [testexprs (mapcat (fn [kv] [(list 'quote (first kv)) (second kv)]) bucket)
                             expr `(condp = ~expr-sym ~@testexprs ~default)]
                         (assoc m h expr)))
         hmap (reduce1
diff --git a/test/clojure/test_clojure/control.clj b/test/clojure/test_clojure/control.clj
index 92846ad38d..f3fe436b45 100644
--- a/test/clojure/test_clojure/control.clj
+++ b/test/clojure/test_clojure/control.clj
@@ -421,7 +421,14 @@
          :b 1
          :c -2
          :d 4294967296
-         :d 3))
+         :d 3)
+    (are [result input] (= result (case input
+                                    #{a} :set
+                                    :foo :keyword
+                                    a :symbol))
+         :symbol 'a
+         :keyword :foo
+         :set '#{a}))
   (testing "test warn for hash collision"
     (should-print-err-message
      #"Performance warning, .*:\d+ - hash collision of some case test constants; if selected, those entries will be tested sequentially..*\r?\n"

From 0cbf655d181c2de8cd30bf234e40488fc94dbdfa Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Tue, 30 Nov 2021 08:19:41 -0600
Subject: [PATCH 085/285] CLJ-2670 - Use Math exact methods where possible for
 perf

Signed-off-by: Alex Miller 
---
 src/jvm/clojure/lang/Numbers.java     | 29 ++++++---------------------
 src/jvm/clojure/lang/RT.java          |  5 +----
 test/clojure/test_clojure/numbers.clj |  2 +-
 3 files changed, 8 insertions(+), 28 deletions(-)

diff --git a/src/jvm/clojure/lang/Numbers.java b/src/jvm/clojure/lang/Numbers.java
index 6405bc2193..82d8e6914c 100644
--- a/src/jvm/clojure/lang/Numbers.java
+++ b/src/jvm/clojure/lang/Numbers.java
@@ -1915,10 +1915,7 @@ static public Number unchecked_dec(Object x){
 static public double remainder(long x, double y){return remainder((double)x,y);}
 
 static public long add(long x, long y){
-	long ret = x + y;
-	if ((ret ^ x) < 0 && (ret ^ y) < 0)
-		return throwIntOverflow();
-	return ret;
+	return Math.addExact(x, y);
 }
 
 static public Number addP(long x, long y){
@@ -1929,10 +1926,7 @@ static public Number addP(long x, long y){
 }
 
 static public long minus(long x, long y){
-	long ret = x - y;
-	if (((ret ^ x) < 0 && (ret ^ ~y) < 0))
-		return throwIntOverflow();
-	return ret;
+	return Math.subtractExact(x, y);
 }
 
 static public Number minusP(long x, long y){
@@ -1943,9 +1937,7 @@ static public Number minusP(long x, long y){
 }
 
 static public long minus(long x){
-	if(x == Long.MIN_VALUE)
-		return throwIntOverflow();
-	return -x;
+	return Math.negateExact(x);
 }
 
 static public Number minusP(long x){
@@ -1955,9 +1947,7 @@ static public Number minusP(long x){
 }
 
 static public long inc(long x){
-	if(x == Long.MAX_VALUE)
-		return throwIntOverflow();
-	return x + 1;
+	return Math.incrementExact(x);
 }
 
 static public Number incP(long x){
@@ -1967,9 +1957,7 @@ static public Number incP(long x){
 }
 
 static public long dec(long x){
-	if(x == Long.MIN_VALUE)
-		return throwIntOverflow();
-	return x - 1;
+	return Math.decrementExact(x);
 }
 
 static public Number decP(long x){
@@ -1980,12 +1968,7 @@ static public Number decP(long x){
 
 
 static public long multiply(long x, long y){
-  if (x == Long.MIN_VALUE && y < 0)
-		return throwIntOverflow();
-	long ret = x * y;
-	if (y != 0 && ret/y != x)
-		return throwIntOverflow();
-	return ret;
+	return Math.multiplyExact(x, y);
 }
 
 static public Number multiplyP(long x, long y){
diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java
index 74399cf15f..5d20ef4964 100644
--- a/src/jvm/clojure/lang/RT.java
+++ b/src/jvm/clojure/lang/RT.java
@@ -1244,10 +1244,7 @@ static public int intCast(float x){
 }
 
 static public int intCast(long x){
-	int i = (int) x;
-	if(i != x)
-		throw new IllegalArgumentException("Value out of range for int: " + x);
-	return i;
+	return Math.toIntExact(x);
 }
 
 static public int intCast(double x){
diff --git a/test/clojure/test_clojure/numbers.clj b/test/clojure/test_clojure/numbers.clj
index cc62a63c89..a6b61605ea 100644
--- a/test/clojure/test_clojure/numbers.clj
+++ b/test/clojure/test_clojure/numbers.clj
@@ -181,7 +181,7 @@
       (let [wrapped (fn [x]
                       (try
                        (f x)
-                       (catch IllegalArgumentException e :error)))]
+                       (catch RuntimeException e :error)))]
         (is (= vals (map wrapped inputs)))))))
 
 ;; *** Functions ***

From 4b9eadccce2aaf97e64bcc8e35c05c529df8fdd2 Mon Sep 17 00:00:00 2001
From: Hugo Duncan 
Date: Wed, 12 Mar 2014 14:38:38 -0400
Subject: [PATCH 086/285] Fix quoting in assert-predicate

Signed-off-by: Alex Miller 
---
 src/clj/clojure/test.clj | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/clj/clojure/test.clj b/src/clj/clojure/test.clj
index 0ab20a75a3..fc3536d7f3 100644
--- a/src/clj/clojure/test.clj
+++ b/src/clj/clojure/test.clj
@@ -447,7 +447,7 @@
            result# (apply ~pred values#)]
        (if result#
          (do-report {:type :pass, :message ~msg,
-                  :expected '~form, :actual (cons ~pred values#)})
+                  :expected '~form, :actual (cons '~pred values#)})
          (do-report {:type :fail, :message ~msg,
                   :expected '~form, :actual (list '~'not (cons '~pred values#))}))
        result#)))

From f08a81ba946cb7afaea859822bba1f52004326ec Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Mon, 20 Sep 2021 15:06:45 -0500
Subject: [PATCH 087/285] CLJ-2234 - Use explicit multimethod hierarchy in
 preference checks

Signed-off-by: Alex Miller 
---
 src/jvm/clojure/lang/MultiFn.java          | 26 +++++++--------
 test/clojure/test_clojure/multimethods.clj | 37 ++++++++++++++++++++++
 2 files changed, 50 insertions(+), 13 deletions(-)

diff --git a/src/jvm/clojure/lang/MultiFn.java b/src/jvm/clojure/lang/MultiFn.java
index fd37e2a085..44ac1ce1c0 100644
--- a/src/jvm/clojure/lang/MultiFn.java
+++ b/src/jvm/clojure/lang/MultiFn.java
@@ -85,7 +85,7 @@ public MultiFn preferMethod(Object dispatchValX, Object dispatchValY) {
 	rw.writeLock().lock();
 	try
 		{
-		if(prefers(dispatchValY, dispatchValX))
+		if(prefers(hierarchy.deref(), dispatchValY, dispatchValX))
 			throw new IllegalStateException(
 					String.format("Preference conflict in multimethod '%s': %s is already preferred to %s",
 					              name, dispatchValY, dispatchValX));
@@ -102,29 +102,29 @@ public MultiFn preferMethod(Object dispatchValX, Object dispatchValY) {
 		}
 }
 
-private boolean prefers(Object x, Object y) {
+private boolean prefers(Object hierarchy, Object x, Object y) {
 	IPersistentSet xprefs = (IPersistentSet) getPreferTable().valAt(x);
 	if(xprefs != null && xprefs.contains(y))
 		return true;
-	for(ISeq ps = RT.seq(parents.invoke(y)); ps != null; ps = ps.next())
+	for(ISeq ps = RT.seq(parents.invoke(hierarchy, y)); ps != null; ps = ps.next())
 		{
-		if(prefers(x, ps.first()))
+		if(prefers(hierarchy, x, ps.first()))
 			return true;
 		}
-	for(ISeq ps = RT.seq(parents.invoke(x)); ps != null; ps = ps.next())
+	for(ISeq ps = RT.seq(parents.invoke(hierarchy, x)); ps != null; ps = ps.next())
 		{
-		if(prefers(ps.first(), y))
+		if(prefers(hierarchy, ps.first(), y))
 			return true;
 		}
 	return false;
 }
 
-private boolean isA(Object x, Object y) {
-    return RT.booleanCast(isa.invoke(hierarchy.deref(), x, y));
+private boolean isA(Object hierarchy, Object x, Object y) {
+    return RT.booleanCast(isa.invoke(hierarchy, x, y));
 }
 
-private boolean dominates(Object x, Object y) {
-	return prefers(x, y) || isA(x, y);
+private boolean dominates(Object hierarchy, Object x, Object y) {
+	return prefers(hierarchy, x, y) || isA(hierarchy, x, y);
 }
 
 private IPersistentMap resetCache() {
@@ -170,11 +170,11 @@ private IFn findAndCacheBestMethod(Object dispatchVal) {
 		for(Object o : getMethodTable())
 			{
 			Map.Entry e = (Map.Entry) o;
-			if(isA(dispatchVal, e.getKey()))
+			if(isA(ch, dispatchVal, e.getKey()))
 				{
-				if(bestEntry == null || dominates(e.getKey(), bestEntry.getKey()))
+				if(bestEntry == null || dominates(ch, e.getKey(), bestEntry.getKey()))
 					bestEntry = e;
-				if(!dominates(bestEntry.getKey(), e.getKey()))
+				if(!dominates(ch, bestEntry.getKey(), e.getKey()))
 					throw new IllegalArgumentException(
 							String.format(
 									"Multiple methods in multimethod '%s' match dispatch value: %s -> %s and %s, and neither is preferred",
diff --git a/test/clojure/test_clojure/multimethods.clj b/test/clojure/test_clojure/multimethods.clj
index 924b0bcbeb..435f0f64a5 100644
--- a/test/clojure/test_clojure/multimethods.clj
+++ b/test/clojure/test_clojure/multimethods.clj
@@ -203,6 +203,43 @@
  (testing "The prefers method now returns the correct table"
    (is (= {[::rect ::shape] #{[::shape ::rect]}} (prefers bar)))))
 
+(deftest indirect-preferences-mulitmethod-test
+  (testing "Using global hierarchy"
+    (derive ::parent-1 ::grandparent-1)
+    (derive ::parent-2 ::grandparent-2)
+    (derive ::child ::parent-1)
+    (derive ::child ::parent-2)
+    (testing "x should be preferred over y if x is preferred over an ancestor of y"
+      (defmulti indirect-1 keyword)
+      (prefer-method indirect-1 ::parent-1 ::grandparent-2)
+      (defmethod indirect-1 ::parent-1 [_] ::parent-1)
+      (defmethod indirect-1 ::parent-2 [_] ::parent-2)
+      (is (= ::parent-1 (indirect-1 ::child))))
+    (testing "x should be preferred over y if an ancestor of x is preferred over y"
+      (defmulti indirect-2 keyword)
+      (prefer-method indirect-2 ::grandparent-1 ::parent-2)
+      (defmethod indirect-2 ::parent-1 [_] ::parent-1)
+      (defmethod indirect-2 ::parent-2 [_] ::parent-2)
+      (is (= ::parent-1 (indirect-2 ::child)))))
+  (testing "Using custom hierarchy"
+    (def local-h (-> (make-hierarchy)
+                     (derive :parent-1 :grandparent-1)
+                     (derive :parent-2 :grandparent-2)
+                     (derive :child :parent-1)
+                     (derive :child :parent-2)))
+    (testing "x should be preferred over y if x is preferred over an ancestor of y"
+      (defmulti indirect-3 keyword :hierarchy #'local-h)
+      (prefer-method indirect-3 :parent-1 :grandparent-2)
+      (defmethod indirect-3 :parent-1 [_] :parent-1)
+      (defmethod indirect-3 :parent-2 [_] :parent-2)
+      (is (= :parent-1 (indirect-3 :child))))
+    (testing "x should be preferred over y if an ancestor of x is preferred over y"
+      (defmulti indirect-4 keyword :hierarchy #'local-h)
+      (prefer-method indirect-4 :grandparent-1 :parent-2)
+      (defmethod indirect-4 :parent-1 [_] :parent-1)
+      (defmethod indirect-4 :parent-2 [_] :parent-2)
+      (is (= :parent-1 (indirect-4 :child))))))
+
 (deftest remove-all-methods-test
   (testing "Core function remove-all-methods works"
     (defmulti simple1 identity)

From c33a5abca7828843b7018a8aa28e63dd40310f86 Mon Sep 17 00:00:00 2001
From: Jonathan D Johnston 
Date: Thu, 21 Mar 2019 20:59:30 -0400
Subject: [PATCH 088/285] CLJ-2493: Prevent browse-url from hanging when using
 xdg-open (updated)

Signed-off-by: Alex Miller 
---
 src/clj/clojure/java/browse.clj |  2 +-
 src/clj/clojure/java/shell.clj  | 20 ++++++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/clj/clojure/java/browse.clj b/src/clj/clojure/java/browse.clj
index 6fcc650756..c416e53832 100644
--- a/src/clj/clojure/java/browse.clj
+++ b/src/clj/clojure/java/browse.clj
@@ -71,6 +71,6 @@
         script (if (= :uninitialized script)
                  (reset! *open-url-script* (open-url-script-val))
                  script)]
-    (or (when script (sh/sh script (str url)) true)
+    (or (when script (sh/launch script (str url)) true)
         (open-url-in-browser url)
         (open-url-in-swing url))))
diff --git a/src/clj/clojure/java/shell.clj b/src/clj/clojure/java/shell.clj
index cb3f90a276..8f167086df 100644
--- a/src/clj/clojure/java/shell.clj
+++ b/src/clj/clojure/java/shell.clj
@@ -127,6 +127,21 @@ collecting its stdout"}
             exit-code (.waitFor proc)]
         {:exit exit-code :out @out :err @err}))))
 
+(defn launch
+  "Same as sh except the I/O channels of the sub-process are ignored.
+
+  Use when you want the sub-process to take an action, but do not want to wait
+  for the I/O channels to close. Example: Launching a browser with xdg-open.
+  "
+  {:added "1.11"}
+  [& args]
+  (let [[cmd opts] (parse-args args)
+        proc (.exec (Runtime/getRuntime)
+               ^"[Ljava.lang.String;" (into-array cmd)
+               (as-env-strings (:env opts))
+               (as-file (:dir opts)))]
+    {:exit (.waitFor proc)}))
+
 (comment
 
 (println (sh "ls" "-l"))
@@ -139,4 +154,9 @@ collecting its stdout"}
 (println (sh "cat" "myimage.png" :out-enc :bytes)) ; reads binary file into bytes[]
 (println (sh "cmd" "/c dir 1>&2"))
 
+(println (launch "touch" "my-test-file"))
+(println (sh "ls" "-l" "my-test-file"))
+(println (launch "rm" "my-test-file"))
+(println (sh "ls" "-l" "my-test-file"))
+
 )

From b962791cbb201e91c29003f2ae1f7cd7a908971f Mon Sep 17 00:00:00 2001
From: Ghadi Shayban 
Date: Fri, 16 Oct 2020 16:13:10 -0400
Subject: [PATCH 089/285] CLJ-2556 complete into's process consistently

Signed-off-by: Alex Miller 
---
 src/clj/clojure/core.clj                  |  6 +++++-
 test/clojure/test_clojure/transducers.clj | 10 ++++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index 72a4548eb3..30500de3e9 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -6961,7 +6961,11 @@ fails, attempts to require sym's namespace and retries."
        (reduce conj to from)))
   ([to xform from]
      (if (instance? clojure.lang.IEditableCollection to)
-       (with-meta (persistent! (transduce xform conj! (transient to) from)) (meta to))
+       (let [tm (meta to)
+             rf (fn
+                  ([coll] (-> (persistent! coll) (with-meta tm)))
+                  ([coll v] (conj! coll v)))]
+         (transduce xform rf (transient to) from))
        (transduce xform conj to from))))
 
 (defn mapv
diff --git a/test/clojure/test_clojure/transducers.clj b/test/clojure/test_clojure/transducers.clj
index 76a0e978a3..b7a9c665e2 100644
--- a/test/clojure/test_clojure/transducers.clj
+++ b/test/clojure/test_clojure/transducers.clj
@@ -398,3 +398,13 @@
          (sequence (map-indexed vector) [])))
   (is (= [[0 1] [1 2] [2 3] [3 4]]
          (sequence (map-indexed vector) (range 1 5)))))
+
+(deftest test-into+halt-when
+  (is (= :anomaly (into [] (comp (filter some?) (halt-when #{:anomaly}))
+                        [1 2 3 :anomaly 4])))
+  (is (= {:anomaly :oh-no!,
+          :partial-results [1 2]}
+         (into []
+               (halt-when :anomaly #(assoc %2 :partial-results %1))
+               [1 2 {:anomaly :oh-no!} 3 4]))))
+

From c01f10bd8c68bd16c657fe352b206573f9306168 Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Thu, 21 Oct 2021 22:40:07 -0500
Subject: [PATCH 090/285] CLJ-2665 Modify change for :as-alias to load if :as
 or :use also included

Signed-off-by: Alex Miller 
---
 src/clj/clojure/core.clj              | 31 +++++++++++++--------------
 test/clojure/test_clojure/ns_libs.clj | 12 ++++++-----
 2 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index 30500de3e9..055050b530 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -5960,26 +5960,25 @@
         opts (apply hash-map options)
         {:keys [as reload reload-all require use verbose as-alias]} opts
         loaded (contains? @*loaded-libs* lib)
-        load (cond reload-all
-                   load-all
-                   (or reload (not require) (not loaded))
-                   load-one)
         need-ns (or as use)
+        load (cond reload-all load-all
+                   reload load-one
+                   (not loaded) (cond need-ns load-one
+                                      as-alias (fn [lib _need _require] (create-ns lib))
+                                      :else load-one))
+
         filter-opts (select-keys opts '(:exclude :only :rename :refer))
         undefined-on-entry (not (find-ns lib))]
     (binding [*loading-verbosely* (or *loading-verbosely* verbose)]
-      (if as-alias
-        (when (not (find-ns lib))
-          (create-ns lib))
-        (if load
-          (try
-            (load lib need-ns require)
-            (catch Exception e
-              (when undefined-on-entry
-                (remove-ns lib))
-              (throw e)))
-          (throw-if (and need-ns (not (find-ns lib)))
-            "namespace '%s' not found" lib)))
+      (if load
+        (try
+          (load lib need-ns require)
+          (catch Exception e
+            (when undefined-on-entry
+              (remove-ns lib))
+            (throw e)))
+        (throw-if (and need-ns (not (find-ns lib)))
+          "namespace '%s' not found" lib))
       (when (and need-ns *loading-verbosely*)
         (printf "(clojure.core/in-ns '%s)\n" (ns-name *ns*)))
       (when as
diff --git a/test/clojure/test_clojure/ns_libs.clj b/test/clojure/test_clojure/ns_libs.clj
index a9f4f97f71..256f99ae87 100644
--- a/test/clojure/test_clojure/ns_libs.clj
+++ b/test/clojure/test_clojure/ns_libs.clj
@@ -116,16 +116,18 @@
 
   (is (= :not.a.real.ns.foo/baz (read-string "::foo/baz")))
 
-  ;; can use :as-alias in use
-  (use '[dummy.example1 :as-alias e1])
-  (let [aliases (ns-aliases *ns*)]
-    (is (= 'dummy.example1 (ns-name (get aliases 'e1)))))
+  ;; can use :as-alias in use, but load will occur
+  (use '[clojure.walk :as-alias e1])
+  (is (= 'clojure.walk (ns-name (get (ns-aliases *ns*) 'e1))))
+  (is (= :clojure.walk/walk (read-string "::e1/walk")))
 
   ;; can use both :as and :as-alias
   (require '[clojure.set :as n1 :as-alias n2])
   (let [aliases (ns-aliases *ns*)]
     (is (= 'clojure.set (ns-name (get aliases 'n1))))
-    (is (= 'clojure.set (ns-name (get aliases 'n2))))))
+    (is (= 'clojure.set (ns-name (get aliases 'n2))))
+    (is (= (resolve 'n1/union) #'clojure.set/union))
+    (is (= (resolve 'n2/union) #'clojure.set/union))))
 
 (deftest require-as-alias-then-load-later
   ;; alias but don't load

From 4a4a6e7717d411679820c4a3ce735a77aef45cc3 Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Thu, 2 Dec 2021 13:37:05 -0600
Subject: [PATCH 091/285] CLJ-2611 Disallow XXE by default in clojure.xml/parse

Signed-off-by: Alex Miller 
---
 src/clj/clojure/xml.clj                   | 40 ++++++++++++++++++++---
 test/clojure/test_clojure/clojure_xml.clj | 13 ++++++--
 2 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/src/clj/clojure/xml.clj b/src/clj/clojure/xml.clj
index 4e4220f265..d892e19279 100644
--- a/src/clj/clojure/xml.clj
+++ b/src/clj/clojure/xml.clj
@@ -72,8 +72,36 @@
            (skippedEntity [name])
            ))))
 
-(defn startparse-sax [s ch]
-  (.. SAXParserFactory (newInstance) (newSAXParser) (parse s ch)))
+(defn sax-parser
+  "Create a new SAXParser"
+  {:added "1.11"}
+  ^SAXParser []
+  (.newSAXParser (SAXParserFactory/newInstance)))
+
+(defn disable-external-entities
+  "Modifies a SAXParser to disable external entity resolution to prevent XXE attacks"
+  {:added "1.11"}
+  ^SAXParser [^SAXParser parser]
+  (let [reader (.getXMLReader parser)]
+    ;; as per https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
+    (.setFeature reader "http://apache.org/xml/features/nonvalidating/load-external-dtd" false)
+    (.setFeature reader "http://xml.org/sax/features/external-general-entities", false)
+    (.setFeature reader "http://xml.org/sax/features/external-parameter-entities" false)
+    parser))
+
+(defn startparse-sax
+  "A startparse function suitable for use with clojure.xml/parse.
+  Note that this function is open to XXE entity attacks, see startparse-sax-safe."
+  {:added "1.0"}
+  [s ch]
+  (.parse (sax-parser) s ch))
+
+(defn startparse-sax-safe
+  "A startparse function suitable for use with clojure.xml/parse.
+  External entity resolution is disabled to prevent XXE entity attacks."
+  {:added "1.11"}
+  [s ch]
+  (.parse (disable-external-entities (sax-parser)) s ch))
 
 (defn parse
   "Parses and loads the source s, which can be a File, InputStream or
@@ -81,9 +109,13 @@
   which has the keys :tag, :attrs, and :content. and accessor fns tag,
   attrs, and content. Other parsers can be supplied by passing
   startparse, a fn taking a source and a ContentHandler and returning
-  a parser"
+  a parser.
+
+  Prior to 1.11, used startparse-sax by default. As of 1.11, uses
+  startparse-sax-safe, which disables XXE (XML External Entity)
+  processing. Pass startparse-sax to revert to prior behavior."
   {:added "1.0"}
-  ([s] (parse s startparse-sax))
+  ([s] (parse s startparse-sax-safe))
   ([s startparse]
     (binding [*stack* nil
               *current* (struct element)
diff --git a/test/clojure/test_clojure/clojure_xml.clj b/test/clojure/test_clojure/clojure_xml.clj
index cf7eb9508d..d37962f361 100644
--- a/test/clojure/test_clojure/clojure_xml.clj
+++ b/test/clojure/test_clojure/clojure_xml.clj
@@ -11,9 +11,18 @@
 
 (ns clojure.test-clojure.clojure-xml
   (:use clojure.test)
-  (:require [clojure.xml :as xml]))
-
+  (:require [clojure.xml :as xml])
+  (:import [java.io ByteArrayInputStream]))
 
+(deftest CLJ-2611-avoid-XXE
+  (let [xml-str "
+
+  ]>
+&xxe;"]
+    (is (= {:tag :foo, :attrs nil, :content nil}
+           (with-open [input (ByteArrayInputStream. (.getBytes xml-str))]
+             (xml/parse input))))))
 ; parse
 
 ; emit-element

From e45e47882597359aa2adce9f244ecdba730e6c76 Mon Sep 17 00:00:00 2001
From: Ghadi Shayban 
Date: Thu, 13 Jan 2022 14:27:57 -0600
Subject: [PATCH 092/285] CLJ-2555: clojure.core/iteration

Subsumes CLJ-1906

Signed-off-by: Alex Miller 
---
 src/clj/clojure/core.clj                | 43 +++++++++++++
 test/clojure/test_clojure/sequences.clj | 85 +++++++++++++++++++++++++
 2 files changed, 128 insertions(+)

diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index 055050b530..4db32604a6 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -7783,6 +7783,49 @@ fails, attempts to require sym's namespace and retries."
   (reduce #(proc %2) nil coll)
   nil)
 
+(defn iteration
+  "creates a seqable/reducible given step!,
+   a function of some (opaque continuation data) k
+
+   step! - fn of k/nil to (opaque) 'ret'
+
+   :some? - fn of ret -> truthy, indicating there is a value
+           will not call vf/kf nor continue when false
+   :vf - fn of ret -> v, the values produced by the iteration
+   :kf - fn of ret -> next-k or nil (will not continue)
+   :initk - the first value passed to step!
+
+   vf, kf default to identity, some? defaults to some?, initk defaults to nil
+
+   it is presumed that step! with non-initk is unreproducible/non-idempotent
+   if step! with initk is unreproducible, it is on the consumer to not consume twice"
+  {:added "1.11"}
+  [step! & {:keys [vf kf some? initk]
+            :or {vf identity
+                 kf identity
+                 some? some?
+                 initk nil}}]
+  (reify
+   clojure.lang.Seqable
+   (seq [_]
+        ((fn next [ret]
+           (when (some? ret)
+             (cons (vf ret)
+                   (when-some [k (kf ret)]
+                     (lazy-seq (next (step! k)))))))
+         (step! initk)))
+   clojure.lang.IReduceInit
+   (reduce [_ rf init]
+           (loop [acc init
+                  ret (step! initk)]
+             (if (some? ret)
+               (let [acc (rf acc (vf ret))]
+                 (if (reduced? acc)
+                   @acc
+                   (if-some [k (kf ret)]
+                     (recur acc (step! k))
+                     acc)))
+               acc)))))
 
 (defn tagged-literal?
   "Return true if the value is the data representation of a tagged literal"
diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj
index 54d640f72d..96e6775bdd 100644
--- a/test/clojure/test_clojure/sequences.clj
+++ b/test/clojure/test_clojure/sequences.clj
@@ -1384,3 +1384,88 @@
     (when (reversible? coll)
       (is (= true (instance? clojure.lang.IMeta (rseq coll))))
       (is (= {:a true} (meta (with-meta (rseq coll) {:a true})))))))
+
+(deftest test-iteration-opts
+  (let [genstep (fn [steps]
+                  (fn [k] (swap! steps inc) (inc k)))
+        test (fn [expect & iteropts]
+               (is (= expect
+                      (let [nsteps (atom 0)
+                            iter (apply iteration (genstep nsteps) iteropts)
+                            ret (doall (seq iter))]
+                        {:ret ret :steps @nsteps})
+                      (let [nsteps (atom 0)
+                            iter (apply iteration (genstep nsteps) iteropts)
+                            ret (into [] iter)]
+                        {:ret ret :steps @nsteps}))))]
+    (test {:ret [1 2 3 4]
+           :steps 5}
+          :initk 0 :some? #(< % 5))
+    (test {:ret [1 2 3 4 5]
+           :steps 5}
+          :initk 0 :kf (fn [ret] (when (< ret 5) ret)))
+    (test {:ret ["1"]
+           :steps 2}
+          :initk 0 :some? #(< % 2) :vf str))
+
+  ;; kf does not stop on false
+  (let [iter #(iteration (fn [k]
+                           (if (boolean? k)
+                             [10 :boolean]
+                             [k k]))
+                         :vf second
+                         :kf (fn [[k v]]
+                               (cond
+                                 (= k 3) false
+                                 (< k 14) (inc k)))
+                         :initk 0)]
+    (is (= [0 1 2 3 :boolean 11 12 13 14]
+           (into [] (iter))
+           (seq (iter))))))
+
+(deftest test-iteration
+  ;; equivalence to line-seq
+  (let [readme #(java.nio.file.Files/newBufferedReader (.toPath (java.io.File. "readme.txt")))]
+    (is (= (with-open [r (readme)]
+             (vec (iteration (fn [_] (.readLine r)))))
+           (with-open [r (readme)]
+             (doall (line-seq r))))))
+
+  ;; paginated API
+  (let [items 12 pgsize 5
+        src (vec (repeatedly items #(java.util.UUID/randomUUID)))
+        api (fn [tok]
+              (let [tok (or tok 0)]
+                (when (< tok items)
+                  {:tok (+ tok pgsize)
+                   :ret (subvec src tok (min (+ tok pgsize) items))})))]
+    (is (= src
+           (mapcat identity (iteration api :kf :tok :vf :ret))
+           (into [] cat (iteration api :kf :tok :vf :ret)))))
+
+  (let [src [:a :b :c :d :e]
+        api (fn [k]
+              (let [k (or k 0)]
+                (if (< k (count src))
+                  {:item (nth src k)
+                   :k (inc k)})))]
+    (is (= [:a :b :c]
+           (vec (iteration api
+                           :some? (comp #{:a :b :c} :item)
+                           :kf :k
+                           :vf :item))
+           (vec (iteration api
+                           :kf #(some-> % :k #{0 1 2})
+                           :vf :item))))))
+
+(defspec iteration-seq-equals-reduce 100
+  (prop/for-all [initk gen/int
+                 seed gen/int]
+    (let [src (fn []
+                (let [rng (java.util.Random. seed)]
+                  (iteration #(unchecked-add % (.nextLong rng))
+                             :some? (complement #(zero? (mod % 1000)))
+                             :vf str
+                             :initk initk)))]
+      (= (into [] (src))
+         (seq (src))))))
\ No newline at end of file

From 5451cee06b9e31513a19e596e4e155d1f08d2a8d Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Thu, 13 Jan 2022 14:38:37 -0600
Subject: [PATCH 093/285] CLJ-2680 Primitive local bindings can have matching
 type hint

Signed-off-by: Alex Miller 
---
 src/jvm/clojure/lang/Compiler.java    | 9 +++++++--
 test/clojure/test_clojure/numbers.clj | 3 +++
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index ce16f85a21..cacaeb0f0e 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -6024,9 +6024,14 @@ public static class LocalBindingExpr implements Expr, MaybePrimitiveExpr, Assign
 	public LocalBindingExpr(LocalBinding b, Symbol tag)
             {
 		if(b.getPrimitiveType() != null && tag != null)
-			throw new UnsupportedOperationException("Can't type hint a primitive local");
+			if(! b.getPrimitiveType().equals(tagClass(tag)))
+				throw new UnsupportedOperationException("Can't type hint a primitive local with a different type");
+			else
+				this.tag = null;
+		else
+			this.tag = tag;
+
 		this.b = b;
-		this.tag = tag;
 
         this.clearPath = (PathNode)CLEAR_PATH.get();
         this.clearRoot = (PathNode)CLEAR_ROOT.get();
diff --git a/test/clojure/test_clojure/numbers.clj b/test/clojure/test_clojure/numbers.clj
index a6b61605ea..bf822cc947 100644
--- a/test/clojure/test_clojure/numbers.clj
+++ b/test/clojure/test_clojure/numbers.clj
@@ -184,6 +184,9 @@
                        (catch RuntimeException e :error)))]
         (is (= vals (map wrapped inputs)))))))
 
+(deftest test-prim-with-matching-hint
+  (is (= 1 (let [x 1.2] (Math/round ^double x)))))
+
 ;; *** Functions ***
 
 (defonce DELTA 1e-12)

From 2b3ba822815981e7f76907a3b75e9ecc428f7656 Mon Sep 17 00:00:00 2001
From: Ghadi Shayban 
Date: Thu, 20 Jan 2022 10:54:35 -0600
Subject: [PATCH 094/285] CLJ-2690 Clarify iteration docstring, rename args

Signed-off-by: Alex Miller 
---
 src/clj/clojure/core.clj                | 41 +++++++++++++------------
 test/clojure/test_clojure/sequences.clj |  8 ++---
 2 files changed, 26 insertions(+), 23 deletions(-)

diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index 4db32604a6..42abb7f00a 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -7784,46 +7784,49 @@ fails, attempts to require sym's namespace and retries."
   nil)
 
 (defn iteration
-  "creates a seqable/reducible given step!,
-   a function of some (opaque continuation data) k
+  "Creates a seqable/reducible via repeated calls to step,
+  a function of some (continuation token) 'k'. The first call to step
+  will be passed initk, returning 'ret'. Iff (somef ret) is true,
+  (vf ret) will be included in the iteration, else iteration will
+  terminate and vf/kf will not be called. If (kf ret) is non-nil it
+  will be passed to the next step call, else iteration will terminate.
 
-   step! - fn of k/nil to (opaque) 'ret'
+  This can be used e.g. to consume APIs that return paginated or batched data.
 
-   :some? - fn of ret -> truthy, indicating there is a value
-           will not call vf/kf nor continue when false
-   :vf - fn of ret -> v, the values produced by the iteration
-   :kf - fn of ret -> next-k or nil (will not continue)
-   :initk - the first value passed to step!
+   step - (possibly impure) fn of 'k' -> 'ret'
 
-   vf, kf default to identity, some? defaults to some?, initk defaults to nil
+   :somef - fn of 'ret' -> logical true/false, default 'some?'
+   :vf - fn of 'ret' -> 'v', a value produced by the iteration, default 'identity'
+   :kf - fn of 'ret' -> 'next-k' or nil (signaling 'do not continue'), default 'identity'
+   :initk - the first value passed to step, default 'nil'
 
-   it is presumed that step! with non-initk is unreproducible/non-idempotent
-   if step! with initk is unreproducible, it is on the consumer to not consume twice"
+  It is presumed that step with non-initk is unreproducible/non-idempotent.
+  If step with initk is unreproducible it is on the consumer to not consume twice."
   {:added "1.11"}
-  [step! & {:keys [vf kf some? initk]
+  [step & {:keys [somef vf kf initk]
             :or {vf identity
                  kf identity
-                 some? some?
+                 somef some?
                  initk nil}}]
   (reify
    clojure.lang.Seqable
    (seq [_]
         ((fn next [ret]
-           (when (some? ret)
+           (when (somef ret)
              (cons (vf ret)
                    (when-some [k (kf ret)]
-                     (lazy-seq (next (step! k)))))))
-         (step! initk)))
+                     (lazy-seq (next (step k)))))))
+         (step initk)))
    clojure.lang.IReduceInit
    (reduce [_ rf init]
            (loop [acc init
-                  ret (step! initk)]
-             (if (some? ret)
+                  ret (step initk)]
+             (if (somef ret)
                (let [acc (rf acc (vf ret))]
                  (if (reduced? acc)
                    @acc
                    (if-some [k (kf ret)]
-                     (recur acc (step! k))
+                     (recur acc (step k))
                      acc)))
                acc)))))
 
diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj
index 96e6775bdd..1fc93cd8ce 100644
--- a/test/clojure/test_clojure/sequences.clj
+++ b/test/clojure/test_clojure/sequences.clj
@@ -1400,13 +1400,13 @@
                         {:ret ret :steps @nsteps}))))]
     (test {:ret [1 2 3 4]
            :steps 5}
-          :initk 0 :some? #(< % 5))
+          :initk 0 :somef #(< % 5))
     (test {:ret [1 2 3 4 5]
            :steps 5}
           :initk 0 :kf (fn [ret] (when (< ret 5) ret)))
     (test {:ret ["1"]
            :steps 2}
-          :initk 0 :some? #(< % 2) :vf str))
+          :initk 0 :somef #(< % 2) :vf str))
 
   ;; kf does not stop on false
   (let [iter #(iteration (fn [k]
@@ -1451,7 +1451,7 @@
                    :k (inc k)})))]
     (is (= [:a :b :c]
            (vec (iteration api
-                           :some? (comp #{:a :b :c} :item)
+                           :somef (comp #{:a :b :c} :item)
                            :kf :k
                            :vf :item))
            (vec (iteration api
@@ -1464,7 +1464,7 @@
     (let [src (fn []
                 (let [rng (java.util.Random. seed)]
                   (iteration #(unchecked-add % (.nextLong rng))
-                             :some? (complement #(zero? (mod % 1000)))
+                             :somef (complement #(zero? (mod % 1000)))
                              :vf str
                              :initk initk)))]
       (= (into [] (src))

From 326366d11923620f6815cfd149300bb48da01593 Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Wed, 19 Jan 2022 12:55:12 -0600
Subject: [PATCH 095/285] CLJ-2689 Provide more tolerance for inexact floating
 point math tests

Signed-off-by: Alex Miller 
---
 test/clojure/test_clojure/math.clj | 44 +++++++++++++++++-------------
 1 file changed, 25 insertions(+), 19 deletions(-)

diff --git a/test/clojure/test_clojure/math.clj b/test/clojure/test_clojure/math.clj
index 63975e7505..4520b41b2b 100644
--- a/test/clojure/test_clojure/math.clj
+++ b/test/clojure/test_clojure/math.clj
@@ -21,20 +21,26 @@
   [^double d]
   (and (zero? d) (not (< (Double/compare d 0.0) 0))))
 
+(defn ulp=
+  "Tests that y = x +/- m*ulp(x)"
+  [x y ^double m]
+  (let [mu (* (m/ulp x) m)]
+    (<= (- x mu) y (+ x mu))))
+
 (deftest test-sin
   (is (NaN? (m/sin ##NaN)))
   (is (NaN? (m/sin ##-Inf)))
   (is (NaN? (m/sin ##Inf)))
   (is (pos-zero? (m/sin 0.0)))
   (is (neg-zero? (m/sin -0.0)))
-  (is (= (m/sin m/PI) (- (m/sin (- m/PI))))))
+  (is (ulp= (m/sin m/PI) (- (m/sin (- m/PI))) 1)))
 
 (deftest test-cos
   (is (NaN? (m/cos ##NaN)))
   (is (NaN? (m/cos ##-Inf)))
   (is (NaN? (m/cos ##Inf)))
   (is (= 1.0 (m/cos 0.0) (m/cos -0.0)))
-  (is (= (m/cos m/PI) (m/cos (- m/PI)))))
+  (is (ulp= (m/cos m/PI) (m/cos (- m/PI)) 1)))
 
 (deftest test-tan
   (is (NaN? (m/tan ##NaN)))
@@ -42,7 +48,7 @@
   (is (NaN? (m/tan ##Inf)))
   (is (pos-zero? (m/tan 0.0)))
   (is (neg-zero? (m/tan -0.0)))
-  (is (= (- (m/tan m/PI)) (m/tan (- m/PI)))))
+  (is (ulp= (- (m/tan m/PI)) (m/tan (- m/PI)) 1)))
 
 (deftest test-asin
   (is (NaN? (m/asin ##NaN)))
@@ -54,45 +60,45 @@
   (is (NaN? (m/acos ##NaN)))
   (is (NaN? (m/acos -2.0)))
   (is (NaN? (m/acos 2.0)))
-  (is (= m/PI (* 2 (m/acos 0.0)))))
+  (is (ulp= (* 2 (m/acos 0.0)) m/PI 1)))
 
 (deftest test-atan
   (is (NaN? (m/atan ##NaN)))
   (is (pos-zero? (m/atan 0.0)))
   (is (neg-zero? (m/atan -0.0)))
-  (is (= 0.7853981633974483 (m/atan 1))))
+  (is (ulp= (m/atan 1) 0.7853981633974483 1)))
 
 (deftest test-radians-degrees-roundtrip
   (doseq [d (range 0.0 360.0 5.0)]
-    (is (= (m/round d) (m/round (-> d m/to-radians m/to-degrees))))))
+    (is (ulp= (m/round d) (m/round (-> d m/to-radians m/to-degrees)) 1))))
 
 (deftest test-exp
   (is (NaN? (m/exp ##NaN)))
   (is (= ##Inf (m/exp ##Inf)))
   (is (pos-zero? (m/exp ##-Inf)))
-  (is (= 1.0 (m/exp 0.0)))
-  (is (= m/E (m/exp 1))))
+  (is (ulp= (m/exp 0.0) 1.0 1))
+  (is (ulp= (m/exp 1) m/E 1)))
 
 (deftest test-log
   (is (NaN? (m/log ##NaN)))
   (is (NaN? (m/log -1.0)))
   (is (= ##Inf (m/log ##Inf)))
   (is (= ##-Inf (m/log 0.0)))
-  (is (= 1.0 (m/log m/E))))
+  (is (ulp= (m/log m/E) 1.0 1)))
 
 (deftest test-log10
   (is (NaN? (m/log10 ##NaN)))
   (is (NaN? (m/log10 -1.0)))
   (is (= ##Inf (m/log10 ##Inf)))
   (is (= ##-Inf (m/log10 0.0)))
-  (is (= 1.0 (m/log10 10))))
+  (is (ulp= (m/log10 10) 1.0 1)))
 
 (deftest test-sqrt
   (is (NaN? (m/sqrt ##NaN)))
   (is (NaN? (m/sqrt -1.0)))
   (is (= ##Inf (m/sqrt ##Inf)))
   (is (pos-zero? (m/sqrt 0)))
-  (is (= 2.0 (m/sqrt 4.0))))
+  (is (= (m/sqrt 4.0) 2.0)))
 
 (deftest test-cbrt
   (is (NaN? (m/cbrt ##NaN)))
@@ -133,14 +139,14 @@
   (is (NaN? (m/atan2 1.0 ##NaN)))
   (is (pos-zero? (m/atan2 0.0 1.0)))
   (is (neg-zero? (m/atan2 -0.0 1.0)))
-  (is (= m/PI (m/atan2 0.0 -1.0)))
-  (is (= (- m/PI) (m/atan2 -0.0 -1.0)))
-  (is (= m/PI (* 2.0 (m/atan2 1.0 0.0))))
-  (is (= m/PI (* -2.0 (m/atan2 -1.0 0.0))))
-  (is (= m/PI (* 4.0 (m/atan2 ##Inf ##Inf))))
-  (is (= m/PI (/ (* 4.0 (m/atan2 ##Inf ##-Inf)) 3.0)))
-  (is (= m/PI (* -4.0 (m/atan2 ##-Inf ##Inf))))
-  (is (= m/PI (/ (* -4.0 (m/atan2 ##-Inf ##-Inf)) 3.0))))
+  (is (ulp= (m/atan2 0.0 -1.0) m/PI 2))
+  (is (ulp= (m/atan2 -0.0 -1.0) (- m/PI) 2))
+  (is (ulp= (* 2.0 (m/atan2 1.0 0.0)) m/PI 2))
+  (is (ulp= (* -2.0 (m/atan2 -1.0 0.0)) m/PI 2))
+  (is (ulp= (* 4.0 (m/atan2 ##Inf ##Inf)) m/PI 2))
+  (is (ulp= (/ (* 4.0 (m/atan2 ##Inf ##-Inf)) 3.0) m/PI 2))
+  (is (ulp= (* -4.0 (m/atan2 ##-Inf ##Inf)) m/PI 2))
+  (is (ulp= (/ (* -4.0 (m/atan2 ##-Inf ##-Inf)) 3.0) m/PI 2)))
 
 (deftest test-pow
   (is (= 1.0 (m/pow 4.0 0.0)))

From da0b9574017918deede6d2a15f386a7cc1b70a2c Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Thu, 20 Jan 2022 16:13:26 -0600
Subject: [PATCH 096/285] CLJ-2685 Fix iteration generative test comparison

Signed-off-by: Alex Miller 
---
 test/clojure/test_clojure/sequences.clj | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj
index 1fc93cd8ce..4eb99e7860 100644
--- a/test/clojure/test_clojure/sequences.clj
+++ b/test/clojure/test_clojure/sequences.clj
@@ -988,7 +988,7 @@
       {} {:a 1 :b 2}
       #{} #{1 2} ))
 
-(defspec longrange-equals-range 100
+(defspec longrange-equals-range 1000
   (prop/for-all [start gen/int
                  end gen/int
                  step gen/s-pos-int]
@@ -1458,7 +1458,7 @@
                            :kf #(some-> % :k #{0 1 2})
                            :vf :item))))))
 
-(defspec iteration-seq-equals-reduce 100
+(defspec iteration-seq-equals-reduce 1000
   (prop/for-all [initk gen/int
                  seed gen/int]
     (let [src (fn []
@@ -1468,4 +1468,4 @@
                              :vf str
                              :initk initk)))]
       (= (into [] (src))
-         (seq (src))))))
\ No newline at end of file
+         (into [] (seq (src)))))))

From 027d8ff2859442b222bf9cfa4c1be45567b788eb Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Wed, 2 Feb 2022 14:43:41 -0600
Subject: [PATCH 097/285] Revert "CLJ-2493: Prevent browse-url from hanging
 when using xdg-open (updated)"

This reverts commit c33a5abca7828843b7018a8aa28e63dd40310f86.
---
 src/clj/clojure/java/browse.clj |  2 +-
 src/clj/clojure/java/shell.clj  | 20 --------------------
 2 files changed, 1 insertion(+), 21 deletions(-)

diff --git a/src/clj/clojure/java/browse.clj b/src/clj/clojure/java/browse.clj
index c416e53832..6fcc650756 100644
--- a/src/clj/clojure/java/browse.clj
+++ b/src/clj/clojure/java/browse.clj
@@ -71,6 +71,6 @@
         script (if (= :uninitialized script)
                  (reset! *open-url-script* (open-url-script-val))
                  script)]
-    (or (when script (sh/launch script (str url)) true)
+    (or (when script (sh/sh script (str url)) true)
         (open-url-in-browser url)
         (open-url-in-swing url))))
diff --git a/src/clj/clojure/java/shell.clj b/src/clj/clojure/java/shell.clj
index 8f167086df..cb3f90a276 100644
--- a/src/clj/clojure/java/shell.clj
+++ b/src/clj/clojure/java/shell.clj
@@ -127,21 +127,6 @@ collecting its stdout"}
             exit-code (.waitFor proc)]
         {:exit exit-code :out @out :err @err}))))
 
-(defn launch
-  "Same as sh except the I/O channels of the sub-process are ignored.
-
-  Use when you want the sub-process to take an action, but do not want to wait
-  for the I/O channels to close. Example: Launching a browser with xdg-open.
-  "
-  {:added "1.11"}
-  [& args]
-  (let [[cmd opts] (parse-args args)
-        proc (.exec (Runtime/getRuntime)
-               ^"[Ljava.lang.String;" (into-array cmd)
-               (as-env-strings (:env opts))
-               (as-file (:dir opts)))]
-    {:exit (.waitFor proc)}))
-
 (comment
 
 (println (sh "ls" "-l"))
@@ -154,9 +139,4 @@ collecting its stdout"}
 (println (sh "cat" "myimage.png" :out-enc :bytes)) ; reads binary file into bytes[]
 (println (sh "cmd" "/c dir 1>&2"))
 
-(println (launch "touch" "my-test-file"))
-(println (sh "ls" "-l" "my-test-file"))
-(println (launch "rm" "my-test-file"))
-(println (sh "ls" "-l" "my-test-file"))
-
 )

From 19e3a2708def5ffb7f2be030d8e8e895464ce2d2 Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Tue, 25 Jan 2022 12:02:09 -0600
Subject: [PATCH 098/285] CLJ-2493 - Prevent browse-url from hanging when using
 xdg-open

Signed-off-by: Alex Miller 
---
 src/clj/clojure/java/browse.clj | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/clj/clojure/java/browse.clj b/src/clj/clojure/java/browse.clj
index 6fcc650756..6a16ce37db 100644
--- a/src/clj/clojure/java/browse.clj
+++ b/src/clj/clojure/java/browse.clj
@@ -12,7 +12,9 @@
   clojure.java.browse
   (:require [clojure.java.shell :as sh]
             [clojure.string :as str])
-  (:import (java.net URI)))
+  (:import (java.io File)
+           (java.net URI)
+           (java.lang ProcessBuilder ProcessBuilder$Redirect)))
 
 (defn- macosx? []
   (-> "os.name" System/getProperty .toLowerCase
@@ -71,6 +73,16 @@
         script (if (= :uninitialized script)
                  (reset! *open-url-script* (open-url-script-val))
                  script)]
-    (or (when script (sh/sh script (str url)) true)
+    (or (when script
+          (try
+            (let [command [script (str url)]
+                  null-file (File. (if (.startsWith (System/getProperty "os.name") "Windows") "NUL" "/dev/null"))
+                  pb (doto (ProcessBuilder. ^java.util.List command)
+                       ;; emulate ProcessBuilder.Redirect.DISCARD added in Java 9
+                       (.redirectOutput null-file)
+                       (.redirectError null-file))]
+              (.start pb) ;; do not wait for the process
+              true)
+            (catch Throwable _ false)))
         (open-url-in-browser url)
         (open-url-in-swing url))))

From 4a9ce390519c41eae100954378937eb220a81dc0 Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Tue, 25 Jan 2022 21:03:58 -0600
Subject: [PATCH 099/285] CLJ-2529 Set exception phase for runtime exceptions
 caught in Compiler.load()

Signed-off-by: Alex Miller 
---
 src/jvm/clojure/lang/Compiler.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index cacaeb0f0e..12cf1e5623 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -7662,7 +7662,7 @@ public static Object load(Reader rdr, String sourcePath, String sourceName) {
 	catch(Throwable e)
 		{
 		if(!(e instanceof CompilerException))
-			throw new CompilerException(sourcePath, (Integer) LINE_BEFORE.deref(), (Integer) COLUMN_BEFORE.deref(), e);
+			throw new CompilerException(sourcePath, (Integer) LINE_BEFORE.deref(), (Integer) COLUMN_BEFORE.deref(), null, CompilerException.PHASE_EXECUTION, e);
 		else
 			throw (CompilerException) e;
 		}

From fc98f92c76254c5a6306debaf0f9df28c3bb3646 Mon Sep 17 00:00:00 2001
From: Fogus 
Date: Tue, 1 Feb 2022 11:34:18 -0500
Subject: [PATCH 100/285] CLJ-2620: io-prepl now calls valf on exeception data
 in the case where an exception occurs in the :print-eval-result phase

Signed-off-by: Alex Miller 
---
 src/clj/clojure/core/server.clj | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/clj/clojure/core/server.clj b/src/clj/clojure/core/server.clj
index 48377d4127..3cda4d1f74 100644
--- a/src/clj/clojure/core/server.clj
+++ b/src/clj/clojure/core/server.clj
@@ -288,7 +288,7 @@
                         (try
                           (assoc m :val (valf (:val m)))
                           (catch Throwable ex
-                            (assoc m :val (ex->data ex :print-eval-result)
+                            (assoc m :val (valf (ex->data ex :print-eval-result))
                                      :exception true)))
                         m))))))))
 

From 8957a93099fc506c3b24ed5739bf9e2fc1811bef Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Thu, 20 Jan 2022 21:18:39 -0600
Subject: [PATCH 101/285] CLJ-1180 Resolve classname for tag metadata on
 defprotocol

Signed-off-by: Alex Miller 
---
 src/clj/clojure/core_deftype.clj              | 10 +++++-
 test/clojure/test_clojure/protocols.clj       | 35 +++++++++++++++----
 .../test_clojure/protocols/examples.clj       |  2 ++
 3 files changed, 40 insertions(+), 7 deletions(-)

diff --git a/src/clj/clojure/core_deftype.clj b/src/clj/clojure/core_deftype.clj
index 7906ccbe35..c2babab291 100644
--- a/src/clj/clojure/core_deftype.clj
+++ b/src/clj/clojure/core_deftype.clj
@@ -652,7 +652,15 @@
             [opts sigs]))
         sigs (when sigs
                (reduce1 (fn [m s]
-                          (let [name-meta (meta (first s))
+                          (let [tag-to-class (fn [tag]
+                                               (if-let [c (and (instance? clojure.lang.Symbol tag)
+                                                            (= (.indexOf (.getName ^clojure.lang.Symbol tag) ".") -1)
+                                                            (not (contains? '#{int long float double char short byte boolean void
+                                                                               ints longs floats doubles chars shorts bytes booleans objects} tag))
+                                                            (resolve tag))]
+                                                 (symbol (.getName c))
+                                                 tag))
+                                name-meta (update-in (meta (first s)) [:tag] tag-to-class)
                                 mname (with-meta (first s) nil)
                                 [arglists doc]
                                 (loop [as [] rs (rest s)]
diff --git a/test/clojure/test_clojure/protocols.clj b/test/clojure/test_clojure/protocols.clj
index ff556dcaed..4e951449bb 100644
--- a/test/clojure/test_clojure/protocols.clj
+++ b/test/clojure/test_clojure/protocols.clj
@@ -47,13 +47,13 @@
 (deftest protocols-test
   (testing "protocol fns have useful metadata"
     (let [common-meta {:ns (find-ns 'clojure.test-clojure.protocols.examples)
-                       :protocol #'ExampleProtocol}]
-      (are [m f] (= (merge (quote m) common-meta)
+                       :protocol #'ExampleProtocol :tag nil}]
+      (are [m f] (= (merge common-meta m)
                     (meta (var f)))
-           {:name foo :arglists ([a]) :doc "method with one arg"} foo
-           {:name bar :arglists ([a b]) :doc "method with two args"} bar
-           {:name baz :arglists ([a] [a b]) :doc "method with multiple arities" :tag String} baz
-           {:name with-quux :arglists ([a]) :doc "method name with a hyphen"} with-quux)))
+           {:name 'foo :arglists '([a]) :doc "method with one arg"} foo
+           {:name 'bar :arglists '([a b]) :doc "method with two args"} bar
+           {:name 'baz :arglists '([a] [a b]) :doc "method with multiple arities" :tag 'java.lang.String} baz
+           {:name 'with-quux :arglists '([a]) :doc "method name with a hyphen"} with-quux)))
   (testing "protocol fns throw IllegalArgumentException if no impl matches"
     (is (thrown-with-msg?
           IllegalArgumentException
@@ -682,3 +682,26 @@
          (reduce-kv #(assoc %1 %3 %2)
                     {}
                     (seq {:a 1 :b 2})))))
+
+(defn aget-long-hinted ^long [x] (aget (longs-hinted x) 0))
+
+(deftest test-longs-hinted-proto
+  (is (= 1
+        (aget-long-hinted
+          (reify LongsHintedProto
+            (longs-hinted [_] (long-array [1])))))))
+
+;; CLJ-1180 - resolve type hints in protocol methods
+
+(import 'clojure.lang.ISeq)
+(defprotocol P
+  (^ISeq f [_]))
+(ns clojure.test-clojure.protocols.other
+  (:use clojure.test))
+(defn cf [val]
+  (let [aseq (clojure.test-clojure.protocols/f val)]
+    (count aseq)))
+(extend-protocol clojure.test-clojure.protocols/P String
+  (f [s] (seq s)))
+(deftest test-resolve-type-hints-in-protocol-methods
+  (is (= 4 (clojure.test-clojure.protocols/f "test"))))
diff --git a/test/clojure/test_clojure/protocols/examples.clj b/test/clojure/test_clojure/protocols/examples.clj
index 9d962d5651..0c247eab04 100644
--- a/test/clojure/test_clojure/protocols/examples.clj
+++ b/test/clojure/test_clojure/protocols/examples.clj
@@ -17,3 +17,5 @@
   (hinted [^int i])
   (hinted [^String s]))
 
+(defprotocol LongsHintedProto
+  (^longs longs-hinted [_]))

From 658693f6cf97e6ab0ff789e096c9eb6654e4d3ab Mon Sep 17 00:00:00 2001
From: Ambrose Bonnaire-Sergeant 
Date: Tue, 25 Jan 2022 12:34:24 -0600
Subject: [PATCH 102/285] CLJ-1973: sort proxy methods for reproducibility

Comparator sorts methods by arity then name/param-types/return-types on clashes.

Signed-off-by: Alex Miller 
---
 build.xml                                    |  1 +
 src/clj/clojure/core_proxy.clj               | 15 +++++---
 test/clojure/test_clojure/java_interop.clj   | 38 ++++++++++++++++++--
 test/clojure/test_clojure/proxy/examples.clj | 30 ++++++++++++++++
 4 files changed, 77 insertions(+), 7 deletions(-)
 create mode 100644 test/clojure/test_clojure/proxy/examples.clj

diff --git a/build.xml b/build.xml
index 6796b3d986..34fd65b2c6 100644
--- a/build.xml
+++ b/build.xml
@@ -105,6 +105,7 @@
         
       
       
+      
       
       
       
diff --git a/src/clj/clojure/core_proxy.clj b/src/clj/clojure/core_proxy.clj
index c7f35774e6..46f7b4b868 100644
--- a/src/clj/clojure/core_proxy.clj
+++ b/src/clj/clojure/core_proxy.clj
@@ -241,12 +241,17 @@
           mb (map #(vector (%1 %2) (vals (dissoc %1 %2))) mgroups rtypes)
           bridge? (reduce1 into1 #{} (map second mb))
           ifaces-meths (remove bridge? (vals ifaces-meths))
-          mm (remove bridge? (vals mm))]
+          mm (remove bridge? (vals mm))
+          reflect-Method-keyfn (fn [meth]
+                                 (let [[name param-types ^Class return-type] (method-sig meth)]
+                                   (-> [name]
+                                       (into1 (map #(.getName ^Class %) param-types))
+                                       (conj (.getName return-type)))))]
                                         ;add methods matching supers', if no mapping -> call super
-      (doseq [[^java.lang.reflect.Method dest bridges] mb
-              ^java.lang.reflect.Method meth bridges]
+      (doseq [[^java.lang.reflect.Method dest bridges] (sort-by (comp reflect-Method-keyfn first) mb)
+              ^java.lang.reflect.Method meth (sort-by reflect-Method-keyfn bridges)]
           (gen-bridge meth dest))
-      (doseq [^java.lang.reflect.Method meth mm]
+      (doseq [^java.lang.reflect.Method meth (sort-by reflect-Method-keyfn mm)]
           (gen-method meth 
                       (fn [^GeneratorAdapter gen ^Method m]
                           (. gen (loadThis))
@@ -259,7 +264,7 @@
                                                 (. m (getDescriptor)))))))
       
                                         ;add methods matching interfaces', if no mapping -> throw
-      (doseq [^java.lang.reflect.Method meth ifaces-meths]
+      (doseq [^java.lang.reflect.Method meth (sort-by reflect-Method-keyfn ifaces-meths)]
                 (gen-method meth 
                             (fn [^GeneratorAdapter gen ^Method m]
                                 (. gen (throwException ex-type (. m (getName))))))))
diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj
index cb21064b25..4925284cc2 100644
--- a/test/clojure/test_clojure/java_interop.clj
+++ b/test/clojure/test_clojure/java_interop.clj
@@ -11,8 +11,11 @@
 
 (ns clojure.test-clojure.java-interop
   (:use clojure.test)
-  (:require [clojure.inspector]
-            [clojure.set :as set])
+  (:require [clojure.data :as data]
+            [clojure.inspector]
+            [clojure.pprint :as pp]
+            [clojure.set :as set]
+            [clojure.test-clojure.proxy.examples :as proxy-examples])
   (:import java.util.Base64
            (java.util.concurrent.atomic AtomicLong AtomicInteger)))
 
@@ -176,6 +179,37 @@
             str)
         "chain chain chain")))
 
+;https://clojure.atlassian.net/browse/CLJ-1973
+(deftest test-proxy-method-order
+  (let [class-reader (clojure.asm.ClassReader. proxy-examples/proxy1-class-name)
+        method-order (atom [])
+        method-visitor (proxy [clojure.asm.ClassVisitor] [clojure.asm.Opcodes/ASM4 nil]
+                         (visitMethod [access name descriptor signature exceptions]
+                           (swap! method-order conj {:name name :descriptor descriptor})
+                           nil))
+        _ (.accept class-reader method-visitor 0)
+        expected [{:name "", :descriptor "()V"}
+                  {:name "__initClojureFnMappings", :descriptor "(Lclojure/lang/IPersistentMap;)V"}
+                  {:name "__updateClojureFnMappings", :descriptor "(Lclojure/lang/IPersistentMap;)V"}
+                  {:name "__getClojureFnMappings", :descriptor "()Lclojure/lang/IPersistentMap;"}
+                  {:name "clone", :descriptor "()Ljava/lang/Object;"}
+                  {:name "hashCode", :descriptor "()I"}
+                  {:name "toString", :descriptor "()Ljava/lang/String;"}
+                  {:name "equals", :descriptor "(Ljava/lang/Object;)Z"}
+                  {:name "a", :descriptor "(Ljava/io/File;)Z"}
+                  {:name "a", :descriptor "(Ljava/lang/Boolean;)Ljava/lang/Object;"}
+                  {:name "a", :descriptor "(Ljava/lang/Runnable;)Z"}
+                  {:name "a", :descriptor "(Ljava/lang/String;)I"}
+                  {:name "b", :descriptor "(Ljava/lang/String;)Ljava/lang/Object;"}
+                  {:name "c", :descriptor "(Ljava/lang/String;)Ljava/lang/Object;"}
+                  {:name "d", :descriptor "(Ljava/lang/String;)Ljava/lang/Object;"}
+                  {:name "a", :descriptor "(Ljava/lang/Boolean;Ljava/lang/String;)I"}
+                  {:name "a", :descriptor "(Ljava/lang/String;Ljava/io/File;)Z"}
+                  {:name "a", :descriptor "(Ljava/lang/String;Ljava/lang/Runnable;)Z"}
+                  {:name "a", :descriptor "(Ljava/lang/String;Ljava/lang/String;)I"}]
+        actual @method-order]
+    (is (= expected actual)
+        (with-out-str (pp/pprint (data/diff expected actual))))))
 
 ;; serialized-proxy can be regenerated using a modified version of
 ;; Clojure with the proxy serialization prohibition disabled and the
diff --git a/test/clojure/test_clojure/proxy/examples.clj b/test/clojure/test_clojure/proxy/examples.clj
new file mode 100644
index 0000000000..b98042320f
--- /dev/null
+++ b/test/clojure/test_clojure/proxy/examples.clj
@@ -0,0 +1,30 @@
+;   Copyright (c) Rich Hickey. All rights reserved.
+;   The use and distribution terms for this software are covered by the
+;   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
+;   which can be found in the file epl-v10.html at the root of this distribution.
+;   By using this software in any fashion, you are agreeing to be bound by
+;   the terms of this license.
+;   You must not remove this notice, or any other, from this software.
+
+(ns ^{:doc "Test proxy classes that are AOT-compiled for the tests in
+           clojure.test-clojure.java-interop."
+      :author "Ambrose Bonnaire-Sergeant"}
+  clojure.test-clojure.proxy.examples)
+
+(definterface A
+  (^int a [^String x])
+  (^boolean a [^java.io.File x])
+  (^boolean a [^Runnable x])
+  (a [^Boolean x])
+  (^int a [^Boolean x ^String y])
+  (^int a [^String x ^String y])
+  (^boolean a [^String x ^java.io.File y])
+  (^boolean a [^String x ^Runnable y])
+  (b [^String x])
+  (c [^String x])
+  (d [^String x]))
+
+(def ^String proxy1-class-name
+  (-> (proxy [A] [])
+      class
+      .getName))

From 16c91f256fd843687be99b4e3fe2e9af12f5428a Mon Sep 17 00:00:00 2001
From: Clojure Build 
Date: Wed, 2 Feb 2022 15:07:32 -0600
Subject: [PATCH 103/285] [maven-release-plugin] prepare release
 clojure-1.11.0-beta1

---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 59159805a1..4be09160a6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
   clojure
   clojure
   jar
-  1.11.0-master-SNAPSHOT
+  1.11.0-beta1
 
   http://clojure.org/
   Clojure core environment and runtime library.
@@ -30,7 +30,7 @@
     scm:git:git@github.com:clojure/clojure.git
     scm:git:git@github.com:clojure/clojure.git
     git@github.com:clojure/clojure.git
-    HEAD
+    clojure-1.11.0-beta1
   
 
   

From 84811650bb33846c7212f391468f9661819b906b Mon Sep 17 00:00:00 2001
From: Clojure Build 
Date: Wed, 2 Feb 2022 15:07:32 -0600
Subject: [PATCH 104/285] [maven-release-plugin] prepare for next development
 iteration

---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 4be09160a6..59159805a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
   clojure
   clojure
   jar
-  1.11.0-beta1
+  1.11.0-master-SNAPSHOT
 
   http://clojure.org/
   Clojure core environment and runtime library.
@@ -30,7 +30,7 @@
     scm:git:git@github.com:clojure/clojure.git
     scm:git:git@github.com:clojure/clojure.git
     git@github.com:clojure/clojure.git
-    clojure-1.11.0-beta1
+    HEAD
   
 
   

From 3fbdffadabbc36436525a0183f2b3c8aca8648a3 Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Tue, 15 Feb 2022 10:52:35 -0600
Subject: [PATCH 105/285] Changelog updates for 1.11

Signed-off-by: Alex Miller 
---
 changes.md | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 159 insertions(+)

diff --git a/changes.md b/changes.md
index 4df7e28540..46b45cbda1 100644
--- a/changes.md
+++ b/changes.md
@@ -1,5 +1,164 @@
 
 
+# Changes to Clojure in Version 1.11.0
+
+## 1 Compatibility
+
+### 1.1 Security
+
+Because XML external entity (XXE) attacks can be used to disclose local files using file schemes or relative paths in the system identifier, `clojure.xml/parse` now disables external entity processing by default.
+
+See: https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing
+
+This change disables the following SAX parser features:
+
+* `http://apache.org/xml/features/nonvalidating/load-external-dtd`
+* `http://xml.org/sax/features/external-general-entities`
+* `http://xml.org/sax/features/external-parameter-entities`
+
+If you rely on these features, modify your calls to `clojure.xml/parse` to explicitly
+supply `startparse-sax` function as the final argument: 
+`(clojure.xml/parse the-string clojure.xml/startparse-sax)`
+This modification also works on prior Clojure versions.
+
+* [CLJ-2611](http://dev.clojure.org/jira/browse/CLJ-2611) clojure.xml now disables XXE processing by default
+
+### 1.2 Dependencies
+
+Updated dependencies:
+
+* spec.alpha dependency to 0.3.218 - [changes](https://github.com/clojure/spec.alpha/blob/master/CHANGES.md)
+* core.specs.alpha dependency to 0.2.62 - [changes](https://github.com/clojure/core.specs.alpha/blob/master/CHANGES.md)
+
+## 2 Features
+
+### 2.1 Keyword argument functions take a trailing map
+
+Keyword arguments are optional trailing variadic arguments of the form *akey aval bkey bval...​*.
+In Clojure 1.11, functions taking keyword arguments can now be passed a map instead of or in addition
+to and following the key/value pairs. When a lone map is passed, it is used for destructuring, else
+a trailing map is added to the key/value pair map by `conj`.
+
+Also see: https://clojure.org/news/2021/03/18/apis-serving-people-and-programs
+
+* [CLJ-2603](https://clojure.atlassian.net/browse/CLJ-2603) Clojure keyword argument functions now also accept a map
+
+### 2.2 `:as-alias` in `require`
+
+Spec (and other libs) rely on qualified keywords as spec names.
+Namespace aliasing in `ns` makes long names shorter but required namespaces to be loadable.
+This change adds `:as-alias` to `require`, which is like `:as` but does not require the namespace to load.
+
+* [CLJ-2123](https://clojure.atlassian.net/browse/CLJ-2123) Add :as-alias option to require like :as but not load
+* [CLJ-2665](https://clojure.atlassian.net/browse/CLJ-2665) Fix require with :as and :as-alias to load
+
+## 3 New functions and namespaces
+
+### 3.1 clojure.math and numeric helper functions
+
+Added a new clojure.math namespace which provides wrappers for the functions available in java.lang.Math.
+These functions are narrowed to only `long` and `double` overloads and provide primitive support without reflection.
+
+In addition, the following functions were added to clojure.core:
+
+* `abs` - absolute value in optimized form for all Clojure numeric types (long, double, ratio, bigint, bigdecimal)
+* `NaN?` - predicate for doubles to check whether "not a number"
+* `infinite?` - predicate for doubles to check whether positive or negative infinity
+
+* [CLJ-2668](https://clojure.atlassian.net/browse/CLJ-2668) Add NaN? and infinite? predicates
+* [CLJ-2664](https://clojure.atlassian.net/browse/CLJ-2664) Add clojure.java.math namespace, wrappers for java.lang.Math
+* [CLJ-2673](https://clojure.atlassian.net/browse/CLJ-2673) Add `abs`, and update `min` and `max` to use Math impls when possible
+* [CLJ-2677](https://clojure.atlassian.net/browse/CLJ-2677) clojure.math - fix method reflection in bodies and inlines, fix docstrings, renamed
+* [CLJ-2689](https://clojure.atlassian.net/browse/CLJ-2689) Fix clojure.math tests to be more tolerant of floating point comparisons
+
+### 3.2 Parser functions
+
+Added the following parsing functions to clojure.core:
+
+* `parse-double` - parses floating point number, including scientific notation
+* `parse-long` - parses integer in long range
+* `parse-boolean` - parses `"true"` or `"false"` to the canonical boolean values
+* `parse-uuid` - parses a UUID string to java.util.UUID
+
+All of these functions expect a string argument and return either the parsed value or `nil` if the value
+is in invalid format.
+
+* [CLJ-2667](https://clojure.atlassian.net/browse/CLJ-2667) Add functions to parse a single long/double/uuid/boolean from a string
+
+### 3.2 `random-uuid`
+
+Added `random-uuid`, a function to construct a random java.util.UUID.
+
+* [CLJ-1925](https://clojure.atlassian.net/browse/CLJ-1925) Add random-uuid
+
+### 3.3 `update-keys` and `update-vals`
+
+Added:
+
+* `update-keys` - applies a function to every key in a map, `m f => {(f k) v ...}`
+* `update-vals` - applies a function to every value in a map, `m f => {k (f v) ...}`
+
+* [CLJ-1959](https://clojure.atlassian.net/browse/CLJ-1959) Add implementation of update-keys
+* [CLJ-2651](https://clojure.atlassian.net/browse/CLJ-2651) Add implementation of update-vals
+
+### 3.4 `iteration`
+
+Added `iteration`, to repeatedly apply a (possibly impure) step function with continuation state.
+This can be used e.g. to consume APIs that return paginated or batched data.
+
+* [CLJ-2555](https://clojure.atlassian.net/browse/CLJ-2555) Add `iteration` generator function
+* [CLJ-2690](https://clojure.atlassian.net/browse/CLJ-2690) Improve `iteration` docstring and arg names
+* [CLJ-2685](https://clojure.atlassian.net/browse/CLJ-2685) Fix `iteration` generative test failure
+
+## 4 Fixes
+
+### 4.1 Compiler
+
+* [CLJ-2680](https://clojure.atlassian.net/browse/CLJ-2680) Fix type hinting a primitive local with matching type hint to not error
+* [CLJ-1180](https://clojure.atlassian.net/browse/CLJ-1180) Fix resolution of class type hints in `defprotocol`
+* [CLJ-1973](https://clojure.atlassian.net/browse/CLJ-1973) Make order of emitted protocol methods in generated classes reproducible
+
+### 4.2 Core
+
+* [CLJ-1879](https://clojure.atlassian.net/browse/CLJ-1879) IKVReduce - make IPersistentMap case faster and extend to Object, detaching it from any fully enumerable set of types
+* [CLJ-2065](https://clojure.atlassian.net/browse/CLJ-2065) IKVReduce - add direct support for SubVector
+* [CLJ-2663](https://clojure.atlassian.net/browse/CLJ-2663) Fix vector `=` not terminating when called with infinite sequence
+* [CLJ-2679](https://clojure.atlassian.net/browse/CLJ-2679) Fix hash collisions in `case` expressions on symbols
+* [CLJ-2600](https://clojure.atlassian.net/browse/CLJ-2600) Don't block `realized?` of `delay` on pending result
+* [CLJ-2649](https://clojure.atlassian.net/browse/CLJ-2649) Fix order of checks in `some-fn` and `every-pred` for 3 predicate case to match other unrollings
+* [CLJ-2234](https://clojure.atlassian.net/browse/CLJ-2234) Fix multimethod preferences to correctly use local hierarchy when it exists
+* [CLJ-2556](https://clojure.atlassian.net/browse/CLJ-2556) Fix `into` completion so `halt-when` works
+
+### 4.3 Performance
+
+* [CLJ-1808](https://clojure.atlassian.net/browse/CLJ-1808) `map-invert` should use `reduce-kv` and transient
+* [CLJ-2621](https://clojure.atlassian.net/browse/CLJ-2621) Fix unnecessary boxing of unused return in statement context for instance method expr
+* [CLJ-2670](https://clojure.atlassian.net/browse/CLJ-2670) Use Math.exact... methods for checked long math ops for performance
+* [CLJ-2636](https://clojure.atlassian.net/browse/CLJ-2636) Get rid of reflection on java.util.Properties when defining `*clojure-version*`
+* [CLJ-1509](https://clojure.atlassian.net/browse/CLJ-1509) AOT compile clojure.instant, clojure.uuid, clojure.core.reducers in build
+
+### 4.4 Error messages
+
+* [CLJ-2529](https://clojure.atlassian.net/browse/CLJ-2529) Fix incorrect reporting of runtime errors as compiler errors in calls through `Compiler.load()`
+* [CLJ-2350](https://clojure.atlassian.net/browse/CLJ-2350) Improve keyword arity exception message
+
+### 4.5 Docstrings
+
+* [CLJ-2249](https://clojure.atlassian.net/browse/CLJ-2249) Clarify `get` docstring regarding sets, strings, arrays, ILookup
+* [CLJ-2488](https://clojure.atlassian.net/browse/CLJ-2488) Add definition to `reify` docstring
+* [CLJ-1360](https://clojure.atlassian.net/browse/CLJ-1360) Update `clojure.string/split` docstring regarding trailing empty parts
+* [CLJ-2444](https://clojure.atlassian.net/browse/CLJ-2444) Fix typo in `test-vars` docstring
+* [CLJ-2666](https://clojure.atlassian.net/browse/CLJ-2666) Make Clojure Java API javadoc text match the example
+
+### 4.6 Other enhancements
+
+* [CLJ-2493](https://clojure.atlassian.net/browse/CLJ-2493) clojure.java.browse - Fix `browse-url` hanging on call to xdg-open
+* [CLJ-1908](https://clojure.atlassian.net/browse/CLJ-1908) clojure.test - Add `run-test` and `run-test-var` to run single test with fixtures and report
+* [CLJ-1379](https://clojure.atlassian.net/browse/CLJ-1379) clojure.test - Fix quoting of `:actual` form in `:pass` maps
+* [CLJ-2620](https://clojure.atlassian.net/browse/CLJ-2620) clojure.server - Fix asymmetric handling of `:exception` `:val`s in `prepl`
+* [CLJ-2387](https://clojure.atlassian.net/browse/CLJ-2387) clojure.server - Fix off-by-one in socket server port validation
+
+
 # Changes to Clojure in Version 1.10.3
 
 ## 1 Changes reverted

From 7b102d84c60ed88d62989d6fd4a6994bd33b3bec Mon Sep 17 00:00:00 2001
From: Paula Gearon 
Date: Sat, 5 Feb 2022 15:14:01 -0500
Subject: [PATCH 106/285] CLJ-2695: parse-double test does not test out-of
 range values

Signed-off-by: Alex Miller 
---
 test/clojure/test_clojure/parse.clj | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/test/clojure/test_clojure/parse.clj b/test/clojure/test_clojure/parse.clj
index 953beefb4d..8078c527f6 100644
--- a/test/clojure/test_clojure/parse.clj
+++ b/test/clojure/test_clojure/parse.clj
@@ -52,12 +52,15 @@
     "Infinity" Double/POSITIVE_INFINITY
     "-Infinity" Double/NEGATIVE_INFINITY
     "1.7976931348623157E308" Double/MAX_VALUE
-    "4.9E-324" Double/MIN_VALUE)
+    "4.9E-324" Double/MIN_VALUE
+    "1.7976931348623157E309" Double/POSITIVE_INFINITY  ;; past max double
+    "2.5e-324" Double/MIN_VALUE  ;; past min double, above half minimum
+    "2.4e-324" 0.0)  ;; below minimum double
   (is (Double/isNaN (parse-double "NaN")))
   (are [s] ;; nil on invalid string
-    (nil? (parse-long s))
-    "1.7976931348623157E309" ;; past max double
-    "9.9E-324")) ;; past min double
+    (nil? (parse-double s))
+    "double" ;; invalid string
+    "1.7976931348623157G309")) ;; invalid, but similar to valid
 
 ;; generative test - gen double -> str -> parse, compare
 (deftest test-gen-parse-double
@@ -96,4 +99,4 @@
     nil
     false
     true
-    100))
\ No newline at end of file
+    100))

From 0971ce23f4cb3a1042483c56a36e4954da26ca70 Mon Sep 17 00:00:00 2001
From: Clojure Build 
Date: Wed, 16 Feb 2022 10:22:29 -0600
Subject: [PATCH 107/285] [maven-release-plugin] prepare release
 clojure-1.11.0-rc1

---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 59159805a1..dc91d0a4aa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
   clojure
   clojure
   jar
-  1.11.0-master-SNAPSHOT
+  1.11.0-rc1
 
   http://clojure.org/
   Clojure core environment and runtime library.
@@ -30,7 +30,7 @@
     scm:git:git@github.com:clojure/clojure.git
     scm:git:git@github.com:clojure/clojure.git
     git@github.com:clojure/clojure.git
-    HEAD
+    clojure-1.11.0-rc1
   
 
   

From 9af0d1d9a0dc34c406c3588dfe9b60dbe4530981 Mon Sep 17 00:00:00 2001
From: Clojure Build 
Date: Wed, 16 Feb 2022 10:22:29 -0600
Subject: [PATCH 108/285] [maven-release-plugin] prepare for next development
 iteration

---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index dc91d0a4aa..59159805a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
   clojure
   clojure
   jar
-  1.11.0-rc1
+  1.11.0-master-SNAPSHOT
 
   http://clojure.org/
   Clojure core environment and runtime library.
@@ -30,7 +30,7 @@
     scm:git:git@github.com:clojure/clojure.git
     scm:git:git@github.com:clojure/clojure.git
     git@github.com:clojure/clojure.git
-    clojure-1.11.0-rc1
+    HEAD
   
 
   

From f376cf62bb0c30f72b0df4ee94c38fa503fa4be7 Mon Sep 17 00:00:00 2001
From: Clojure Build 
Date: Tue, 22 Mar 2022 10:16:08 -0500
Subject: [PATCH 109/285] [maven-release-plugin] prepare release clojure-1.11.0

---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 59159805a1..e237f52448 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
   clojure
   clojure
   jar
-  1.11.0-master-SNAPSHOT
+  1.11.0
 
   http://clojure.org/
   Clojure core environment and runtime library.
@@ -30,7 +30,7 @@
     scm:git:git@github.com:clojure/clojure.git
     scm:git:git@github.com:clojure/clojure.git
     git@github.com:clojure/clojure.git
-    HEAD
+    clojure-1.11.0
   
 
   

From 48818bd96afc2c8ee8ee76075f7a186289c6517a Mon Sep 17 00:00:00 2001
From: Clojure Build 
Date: Tue, 22 Mar 2022 10:16:08 -0500
Subject: [PATCH 110/285] [maven-release-plugin] prepare for next development
 iteration

---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index e237f52448..2dd37faaad 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
   clojure
   clojure
   jar
-  1.11.0
+  1.12.0-master-SNAPSHOT
 
   http://clojure.org/
   Clojure core environment and runtime library.
@@ -30,7 +30,7 @@
     scm:git:git@github.com:clojure/clojure.git
     scm:git:git@github.com:clojure/clojure.git
     git@github.com:clojure/clojure.git
-    clojure-1.11.0
+    HEAD
   
 
   

From 1da6b07722790e898faa261a816a7a070fd93ac5 Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Wed, 30 Mar 2022 15:41:32 -0500
Subject: [PATCH 111/285] CLJ-2701 Set serialVersionUIDs for Keyword and
 ArraySeq to retain 1.10.3 values

Signed-off-by: Alex Miller 
---
 src/jvm/clojure/lang/ArraySeq.java | 3 +++
 src/jvm/clojure/lang/Keyword.java  | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/src/jvm/clojure/lang/ArraySeq.java b/src/jvm/clojure/lang/ArraySeq.java
index 49a74b660d..5f54d87aaf 100644
--- a/src/jvm/clojure/lang/ArraySeq.java
+++ b/src/jvm/clojure/lang/ArraySeq.java
@@ -15,6 +15,9 @@
 import java.lang.reflect.Array;
 
 public class ArraySeq extends ASeq implements IndexedSeq, IReduce{
+
+private static final long serialVersionUID = -9069152683729302290L;
+
 public final Object[] array;
 final int i;
 //ISeq _rest;
diff --git a/src/jvm/clojure/lang/Keyword.java b/src/jvm/clojure/lang/Keyword.java
index 145df4f73b..253f455e4a 100644
--- a/src/jvm/clojure/lang/Keyword.java
+++ b/src/jvm/clojure/lang/Keyword.java
@@ -23,6 +23,8 @@
 
 public class Keyword implements IFn, Comparable, Named, Serializable, IHashEq {
 
+private static final long serialVersionUID = -2105088845257724163L;
+
 private static ConcurrentHashMap> table = new ConcurrentHashMap();
 static final ReferenceQueue rq = new ReferenceQueue();
 public final Symbol sym;

From e917dcc003bdd56660d5057407ea7739d2736af2 Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Fri, 1 Apr 2022 12:46:31 -0500
Subject: [PATCH 112/285] Update changelog for 1.11.1

---
 changes.md | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/changes.md b/changes.md
index 46b45cbda1..f18b330f4a 100644
--- a/changes.md
+++ b/changes.md
@@ -1,5 +1,10 @@
 
 
+# Changes to Clojure in Version 1.11.1
+
+* [CLJ-2701](https://clojure.atlassian.net/browse/CLJ-2701)
+  Pin serialVersionUID for Keyword and ArraySeq back to 1.10.3 values to retain binary serialization
+
 # Changes to Clojure in Version 1.11.0
 
 ## 1 Compatibility

From 3f1c36d779a43b1951ddaa9cdf6250b1d739621b Mon Sep 17 00:00:00 2001
From: Clojure Build 
Date: Fri, 1 Apr 2022 12:52:28 -0500
Subject: [PATCH 113/285] [maven-release-plugin] prepare release
 clojure-1.11.1-rc1

---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 2dd37faaad..4496e1353f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
   clojure
   clojure
   jar
-  1.12.0-master-SNAPSHOT
+  1.11.1-rc1
 
   http://clojure.org/
   Clojure core environment and runtime library.
@@ -30,7 +30,7 @@
     scm:git:git@github.com:clojure/clojure.git
     scm:git:git@github.com:clojure/clojure.git
     git@github.com:clojure/clojure.git
-    HEAD
+    clojure-1.11.1-rc1
   
 
   

From cef38abac0d7139f4d38324290eaf2c40b8924a7 Mon Sep 17 00:00:00 2001
From: Clojure Build 
Date: Fri, 1 Apr 2022 12:52:28 -0500
Subject: [PATCH 114/285] [maven-release-plugin] prepare for next development
 iteration

---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 4496e1353f..2dd37faaad 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
   clojure
   clojure
   jar
-  1.11.1-rc1
+  1.12.0-master-SNAPSHOT
 
   http://clojure.org/
   Clojure core environment and runtime library.
@@ -30,7 +30,7 @@
     scm:git:git@github.com:clojure/clojure.git
     scm:git:git@github.com:clojure/clojure.git
     git@github.com:clojure/clojure.git
-    clojure-1.11.1-rc1
+    HEAD
   
 
   

From ce55092f2b2f5481d25cff6205470c1335760ef6 Mon Sep 17 00:00:00 2001
From: Clojure Build 
Date: Tue, 5 Apr 2022 09:33:41 -0500
Subject: [PATCH 115/285] [maven-release-plugin] prepare release clojure-1.11.1

---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 2dd37faaad..b15f640224 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
   clojure
   clojure
   jar
-  1.12.0-master-SNAPSHOT
+  1.11.1
 
   http://clojure.org/
   Clojure core environment and runtime library.
@@ -30,7 +30,7 @@
     scm:git:git@github.com:clojure/clojure.git
     scm:git:git@github.com:clojure/clojure.git
     git@github.com:clojure/clojure.git
-    HEAD
+    clojure-1.11.1
   
 
   

From 35bd89f05f8dc4aec47001ca10fe9163abc02ea6 Mon Sep 17 00:00:00 2001
From: Clojure Build 
Date: Tue, 5 Apr 2022 09:33:41 -0500
Subject: [PATCH 116/285] [maven-release-plugin] prepare for next development
 iteration

---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index b15f640224..2dd37faaad 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
   clojure
   clojure
   jar
-  1.11.1
+  1.12.0-master-SNAPSHOT
 
   http://clojure.org/
   Clojure core environment and runtime library.
@@ -30,7 +30,7 @@
     scm:git:git@github.com:clojure/clojure.git
     scm:git:git@github.com:clojure/clojure.git
     git@github.com:clojure/clojure.git
-    clojure-1.11.1
+    HEAD
   
 
   

From b2366fa5c748f9d600879c3e0b549e631a5b386f Mon Sep 17 00:00:00 2001
From: Alex Miller 
Date: Tue, 21 Jun 2022 11:03:57 -0500
Subject: [PATCH 117/285] CLJ-2713 Efficient drop, partition for
 persistent/algo colls

Added new IDrop interface and implemented in PV, PAM, LongRange, Repeat,
StringSeq. Added new core functions that make vector partitions and make
better use of fast drop support - partitionv, partitionv-all, splitv-at.
---
 src/clj/clojure/core.clj                     |  68 +++++-
 src/jvm/clojure/lang/IDrop.java              |  30 +++
 src/jvm/clojure/lang/LongRange.java          | 217 ++++++-------------
 src/jvm/clojure/lang/PersistentArrayMap.java |  52 ++++-
 src/jvm/clojure/lang/PersistentVector.java   |  82 ++++++-
 src/jvm/clojure/lang/Repeat.java             |  12 +-
 src/jvm/clojure/lang/StringSeq.java          |  25 ++-
 test/clojure/test_clojure/sequences.clj      |  59 +++++
 8 files changed, 383 insertions(+), 162 deletions(-)
 create mode 100644 src/jvm/clojure/lang/IDrop.java

diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index 42abb7f00a..db5641339d 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -2924,7 +2924,7 @@
           (cons (first s) (take-while pred (rest s))))))))
 
 (defn drop
-  "Returns a lazy sequence of all but the first n items in coll.
+  "Returns a laziness-preserving sequence of all but the first n items in coll.
   Returns a stateful transducer when no collection is provided."
   {:added "1.0"
    :static true}
@@ -2941,12 +2941,14 @@
                   result
                   (rf result input))))))))
   ([n coll]
-     (let [step (fn [n coll]
-                  (let [s (seq coll)]
-                    (if (and (pos? n) s)
-                      (recur (dec n) (rest s))
-                      s)))]
-       (lazy-seq (step n coll)))))
+     (if (instance? clojure.lang.IDrop coll)
+       (or (.drop ^clojure.lang.IDrop coll n) ())
+       (let [step (fn [n coll]
+                    (let [s (seq coll)]
+                      (if (and (pos? n) s)
+                        (recur (dec n) (rest s))
+                        s)))]
+         (lazy-seq (step n coll))))))
 
 (defn drop-last
   "Return a lazy sequence of all but the last n (default 1) items in coll"
@@ -3167,20 +3169,24 @@
   {:added "1.0"
    :static true}
   [coll n]
+  (if (instance? clojure.lang.IDrop coll)
+    (.drop ^clojure.lang.IDrop coll n)
     (loop [n n xs (seq coll)]
       (if (and xs (pos? n))
         (recur (dec n) (next xs))
-        xs)))
+        xs))))
 
 (defn nthrest
   "Returns the nth rest of coll, coll when n is 0."
   {:added "1.3"
    :static true}
   [coll n]
+  (if (instance? clojure.lang.IDrop coll)
+    (or (.drop ^clojure.lang.IDrop coll n) ())
     (loop [n n xs coll]
       (if-let [xs (and (pos? n) (seq xs))]
         (recur (dec n) (rest xs))
-        xs)))
+        xs))))
 
 (defn partition
   "Returns a lazy sequence of lists of n items each, at offsets step
@@ -7339,6 +7345,50 @@ fails, attempts to require sym's namespace and retries."
         (let [seg (doall (take n s))]
           (cons seg (partition-all n step (nthrest s step))))))))
 
+(defn splitv-at
+  "Returns a vector of [(into [] (take n) coll) (drop n coll)]"
+  {:added "1.12"}
+  [n coll]
+  [(into [] (take n) coll) (drop n coll)])
+
+(defn partitionv
+  "Returns a lazy sequence of vectors of n items each, at offsets step
+  apart. If step is not supplied, defaults to n, i.e. the partitions
+  do not overlap. If a pad collection is supplied, use its elements as
+  necessary to complete last partition upto n items. In case there are
+  not enough padding elements, return a partition with less than n items."
+  {:added "1.12"}
+  ([n coll]
+   (partitionv n n coll))
+  ([n step coll]
+   (lazy-seq
+     (when-let [s (seq coll)]
+       (let [p (into [] (take n) s)]
+         (when (= n (count p))
+           (cons p (partitionv n step (nthrest s step))))))))
+  ([n step pad coll]
+   (lazy-seq
+     (when-let [s (seq coll)]
+       (let [p (into [] (take n) s)]
+         (if (= n (count p))
+           (cons p (partitionv n step pad (nthrest s step)))
+           (into [] (take n) (concat p pad))))))))
+
+(defn partitionv-all
+  "Returns a lazy sequence of vector partitions, but may include
+  partitions with fewer than n items at the end.
+  Returns a stateful transducer when no collection is provided."
+  {:added "1.12"}
+  ([n]
+   (partition-all n))
+  ([n coll]
+   (partitionv-all n n coll))
+  ([n step coll]
+   (lazy-seq
+     (when-let [s (seq coll)]
+       (let [seg (into [] (take n) coll)]
+         (cons seg (partitionv-all n step (drop step s))))))))
+
 (defn shuffle
   "Return a random permutation of coll"
   {:added "1.2"
diff --git a/src/jvm/clojure/lang/IDrop.java b/src/jvm/clojure/lang/IDrop.java
new file mode 100644
index 0000000000..ce4341ce02
--- /dev/null
+++ b/src/jvm/clojure/lang/IDrop.java
@@ -0,0 +1,30 @@
+/**
+ *   Copyright (c) Rich Hickey. All rights reserved.
+ *   The use and distribution terms for this software are covered by the
+ *   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
+ *   which can be found in the file epl-v10.html at the root of this distribution.
+ *   By using this software in any fashion, you are agreeing to be bound by
+ * 	 the terms of this license.
+ *   You must not remove this notice, or any other, from this software.
+ **/
+
+package clojure.lang;
+
+/**
+ * Persistent or algorithmically defined collections can implement IDrop to provide
+ * a means of dropping N items that is more efficient than sequential walking.
+ */
+public interface IDrop{
+    /**
+     * Returns a collection that is Sequential, ISeq, and IReduceInit. It is also
+     * useful if the returned coll implements IDrop for subsequent use in a
+     * partition-like scenario.
+     *
+     * If n is <= 0, return this.
+     * If n drops to or past the end of the collection, return null.
+     *
+     * @param n Items to drop
+     * @return Collection that is Sequential, ISeq, and IReduceInit
+     */
+    Sequential drop(int n);
+}
diff --git a/src/jvm/clojure/lang/LongRange.java b/src/jvm/clojure/lang/LongRange.java
index 348e362081..d1bfba2fe0 100644
--- a/src/jvm/clojure/lang/LongRange.java
+++ b/src/jvm/clojure/lang/LongRange.java
@@ -16,87 +16,82 @@
 import java.util.NoSuchElementException;
 
 /**
- * Implements the special common case of a finite range based on long start, end, and step.
+ * Implements the special common case of a finite range based on long start, end, and step,
+ * with no more than Integer.MAX_VALUE items.
  */
-public class LongRange extends ASeq implements Counted, IChunkedSeq, IReduce {
+public class LongRange extends ASeq implements Counted, IChunkedSeq, IReduce, IDrop {
 
-private static final int CHUNK_SIZE = 32;
+private static final long serialVersionUID = -1467242400566893909L;
 
 // Invariants guarantee this is never an empty or infinite seq
 //   assert(start != end && step != 0)
 final long start;
 final long end;
 final long step;
-final BoundsCheck boundsCheck;
-private volatile LongChunk _chunk;  // lazy
-private volatile ISeq _chunkNext;        // lazy
-private volatile ISeq _next;             // cached
+final int count;
 
-private static interface BoundsCheck extends Serializable {
-    boolean exceededBounds(long val);
-}
-
-private static BoundsCheck positiveStep(final long end) {
-    return new BoundsCheck() {
-        public boolean exceededBounds(long val){
-            return (val >= end);
-        }
-    };
-}
-
-private static BoundsCheck negativeStep(final long end) {
-    return new BoundsCheck() {
-        public boolean exceededBounds(long val){
-            return (val <= end);
-        }
-    };
-}
-
-private LongRange(long start, long end, long step, BoundsCheck boundsCheck){
+private LongRange(long start, long end, long step, int count){
     this.start = start;
     this.end = end;
     this.step = step;
-    this.boundsCheck = boundsCheck;
+    this.count = count;
 }
 
-private LongRange(long start, long end, long step, BoundsCheck boundsCheck, LongChunk chunk, ISeq chunkNext){
+private LongRange(IPersistentMap meta, long start, long end, long step, int count){
+    super(meta);
     this.start = start;
     this.end = end;
     this.step = step;
-    this.boundsCheck = boundsCheck;
-    this._chunk = chunk;
-    this._chunkNext = chunkNext;
+    this.count = count;
 }
 
-private LongRange(IPersistentMap meta, long start, long end, long step, BoundsCheck boundsCheck, LongChunk chunk, ISeq chunkNext){
-    super(meta);
-    this.start = start;
-    this.end = end;
-    this.step = step;
-    this.boundsCheck = boundsCheck;
-    this._chunk = chunk;
-    this._chunkNext = chunkNext;
+// returns exact size of remaining items OR throws ArithmeticException for overflow case
+static long rangeCount(long start, long end, long step) {
+    // (1) count = ceiling ( (end - start) / step )
+    // (2) ceiling(a/b) = (a+b+o)/b where o=-1 for positive stepping and +1 for negative stepping
+    // thus: count = end - start + step + o / step
+    return Numbers.add(Numbers.add(Numbers.minus(end, start), step), step > 0 ? -1 : 1) / step;
 }
 
 public static ISeq create(long end) {
-    if(end > 0)
-        return new LongRange(0L, end, 1L, positiveStep(end));
-    return PersistentList.EMPTY;
+    if(end > 0) {
+        try {
+            return new LongRange(0L, end, 1L, Math.toIntExact(rangeCount(0L, end, 1L)));
+        } catch(ArithmeticException e) {
+            return Range.create(end);  // count > Integer.MAX_VALUE
+        }
+    } else {
+        return PersistentList.EMPTY;
+    }
 }
 
 public static ISeq create(long start, long end) {
-    if(start >= end)
+    if(start >= end) {
         return PersistentList.EMPTY;
-    return new LongRange(start, end, 1L, positiveStep(end));
+    } else {
+        try {
+            return new LongRange(start, end, 1L, Math.toIntExact(rangeCount(start, end, 1L)));
+        } catch(ArithmeticException e) {
+            return Range.create(start, end);
+        }
+    }
 }
 
 public static ISeq create(final long start, long end, long step) {
     if(step > 0) {
         if(end <= start) return PersistentList.EMPTY;
-        return new LongRange(start, end, step, positiveStep(end));
+        try {
+            return new LongRange(start, end, step, Math.toIntExact(rangeCount(start, end, step)));
+        } catch(ArithmeticException e) {
+            return Range.create(start, end, step);
+        }
     } else if(step < 0) {
         if(end >= start) return PersistentList.EMPTY;
-        return new LongRange(start, end, step, negativeStep(end));
+        try {
+            return new LongRange(start, end, step, Math.toIntExact(rangeCount(start, end, step)));
+        } catch(ArithmeticException e) {
+            return Range.create(start, end, step);
+        }
     } else {
         if(end == start) return PersistentList.EMPTY;
         return Repeat.create(start);
@@ -106,134 +101,70 @@ public static ISeq create(final long start, long end, long step) {
 public Obj withMeta(IPersistentMap meta){
     if(meta == _meta)
         return this;
-    return new LongRange(meta, start, end, step, boundsCheck, _chunk, _chunkNext);
+    return new LongRange(meta, start, end, step, count);
 }
 
 public Object first() {
     return start;
 }
 
-public void forceChunk() {
-    if(_chunk != null) return;
-
-    long count;
-    try {
-        count = rangeCount(start, end, step);
-    } catch(ArithmeticException e) {
-        // size of total range is > Long.MAX_VALUE so must step to count
-        // this only happens in pathological range cases like:
-        // (range -9223372036854775808 9223372036854775807 9223372036854775807)
-        count = steppingCount(start, end, step);
-    }
-
-    if (count > CHUNK_SIZE) { // not last chunk
-        long nextStart = start + (step * CHUNK_SIZE);   // cannot overflow, must be < end
-        _chunkNext = new LongRange(nextStart, end, step, boundsCheck);
-        _chunk = new LongChunk(start, step, CHUNK_SIZE);
-    } else {  // last chunk
-        _chunk = new LongChunk(start, step, (int) count);   // count must be <= CHUNK_SIZE
-    }
-}
-
 public ISeq next() {
-    if(_next != null)
-        return _next;
-
-    forceChunk();
-    if(_chunk.count() > 1) {
-        LongChunk smallerChunk = _chunk.dropFirst();
-        _next = new LongRange(smallerChunk.first(), end, step, boundsCheck, smallerChunk, _chunkNext);
-        return _next;
+    if(count > 1) {
+        return new LongRange(start + step, end, step, count-1);
+    } else {
+        return null;
     }
-    return chunkedNext();
 }
 
 public IChunk chunkedFirst() {
-    forceChunk();
-    return _chunk;
+    return new LongChunk(start, step, count);
 }
 
 public ISeq chunkedNext() {
-    return chunkedMore().seq();
+    return null;
 }
 
 public ISeq chunkedMore() {
-    forceChunk();
-    if(_chunkNext == null)
-        return PersistentList.EMPTY;
-    return _chunkNext;
+    return PersistentList.EMPTY;
 }
 
-// fallback count mechanism for pathological cases
-// returns either exact count or CHUNK_SIZE+1
-long steppingCount(long start, long end, long step) {
-    long count = 1;
-    long s = start;
-    while(count <= CHUNK_SIZE) {
-        try {
-            s = Numbers.add(s, step);
-            if(boundsCheck.exceededBounds(s))
-                break;
-            else
-                count++;
-        } catch(ArithmeticException e) {
-            break;
-        }
+public Sequential drop(int n) {
+    if(n <= 0) {
+        return this;
+    } else if(n < count) {
+        return new LongRange(start+(step*n), end, step, count - n);
+    } else {
+        return null;
     }
-    return count;
-}
-
-// returns exact size of remaining items OR throws ArithmeticException for overflow case
-long rangeCount(long start, long end, long step) {
-    // (1) count = ceiling ( (end - start) / step )
-    // (2) ceiling(a/b) = (a+b+o)/b where o=-1 for positive stepping and +1 for negative stepping
-    // thus: count = end - start + step + o / step
-    return Numbers.add(Numbers.add(Numbers.minus(end, start), step), this.step > 0 ? -1 : 1) / step;
 }
 
 public int count() {
-    try {
-        long c = rangeCount(start, end, step);
-        if(c > Integer.MAX_VALUE) {
-            return Numbers.throwIntOverflow();
-        } else {
-            return (int) c;
-        }
-    } catch(ArithmeticException e) {
-        // rare case from large range or step, fall back to iterating and counting
-        Iterator iter = this.iterator();
-        long count = 0;
-        while(iter.hasNext()) {
-            iter.next();
-            count++;
-        }
-
-        if(count > Integer.MAX_VALUE)
-            return Numbers.throwIntOverflow();
-        else
-            return (int)count;
-    }
+    return count;
 }
 
 public Object reduce(IFn f) {
     Object acc = start;
     long i = start + step;
-    while(! boundsCheck.exceededBounds(i)) {
+    int n = count;
+    while(n > 1) {
         acc = f.invoke(acc, i);
         if (acc instanceof Reduced) return ((Reduced)acc).deref();
         i += step;
+        n--;
     }
     return acc;
 }
 
 public Object reduce(IFn f, Object val) {
     Object acc = val;
+    int n = count;
     long i = start;
     do {
         acc = f.invoke(acc, i);
         if (RT.isReduced(acc)) return ((Reduced)acc).deref();
         i += step;
-    } while(! boundsCheck.exceededBounds(i));
+        n--;
+    } while(n > 0);
     return acc;
 }
 
@@ -243,26 +174,22 @@ public Iterator iterator() {
 
 class LongRangeIterator implements Iterator {
     private long next;
-    private boolean hasNext;
+    private int remaining;
 
     public LongRangeIterator() {
         this.next = start;
-        this.hasNext = true;
+        this.remaining = count;
     }
 
     public boolean hasNext() {
-        return hasNext;
+        return remaining > 0;
     }
 
     public Object next() {
-        if (hasNext) {
+        if (remaining > 0) {
             long ret = next;
-            try {
-                next = Numbers.add(next, step);
-                hasNext = ! boundsCheck.exceededBounds(next);
-            } catch(ArithmeticException e) {
-                hasNext = false;
-            }
+            next = next + step;
+            remaining = remaining - 1;
             return ret;
         } else {
             throw new NoSuchElementException();
@@ -322,4 +249,4 @@ public Object reduce(IFn f, Object init) {
     }
 
 }
-}
\ No newline at end of file
+}
diff --git a/src/jvm/clojure/lang/PersistentArrayMap.java b/src/jvm/clojure/lang/PersistentArrayMap.java
index 1f86fd80aa..73e8c023cb 100644
--- a/src/jvm/clojure/lang/PersistentArrayMap.java
+++ b/src/jvm/clojure/lang/PersistentArrayMap.java
@@ -27,7 +27,7 @@
  * 

null keys and values are ok, but you won't be able to distinguish a null value via valAt - use contains/entryAt

*/ -public class PersistentArrayMap extends APersistentMap implements IObj, IEditableCollection, IMapIterable, IKVReduce{ +public class PersistentArrayMap extends APersistentMap implements IObj, IEditableCollection, IMapIterable, IKVReduce, IDrop{ final Object[] array; static final int HASHTABLE_THRESHOLD = 16; @@ -348,11 +348,19 @@ public ISeq seq(){ return null; } +public Sequential drop(int n) { + if(array.length > 0) { + return ((Seq) seq()).drop(n); + } else { + return null; + } +} + public IPersistentMap meta(){ return _meta; } -static class Seq extends ASeq implements Counted{ +static class Seq extends ASeq implements Counted, IReduce, IDrop { final Object[] array; final int i; @@ -381,16 +389,52 @@ public int count(){ return (array.length - i) / 2; } + public Sequential drop(int n) { + if(n < count()) { + return new Seq(array, i + (2 * n)); + } else { + return null; + } + } + public Obj withMeta(IPersistentMap meta){ if(meta() == meta) return this; return new Seq(meta, array, i); } + + public Iterator iterator() { + return new Iter(array, i-2, APersistentMap.MAKE_ENTRY); + } + + public Object reduce(IFn f) { + if(i < array.length) { + Object acc = MapEntry.create(array[i], array[i+1]); + for(int j=i+2;j < array.length;j+=2){ + acc = f.invoke(acc, MapEntry.create(array[j], array[j+1])); + if(RT.isReduced(acc)) + return ((IDeref)acc).deref(); + } + return acc; + } else { + return f.invoke(); + } + } + + public Object reduce(IFn f, Object init) { + Object acc = init; + for(int j=i;j < array.length;j+=2){ + acc = f.invoke(acc, MapEntry.create(array[j], array[j+1])); + if(RT.isReduced(acc)) + return ((IDeref)acc).deref(); + } + return acc; + } } static class Iter implements Iterator{ - IFn f; - Object[] array; + final IFn f; + final Object[] array; int i; //for iterator diff --git a/src/jvm/clojure/lang/PersistentVector.java b/src/jvm/clojure/lang/PersistentVector.java index fcd9e46c26..9f02353965 100644 --- a/src/jvm/clojure/lang/PersistentVector.java +++ b/src/jvm/clojure/lang/PersistentVector.java @@ -19,7 +19,7 @@ import java.util.NoSuchElementException; import java.util.concurrent.atomic.AtomicReference; -public class PersistentVector extends APersistentVector implements IObj, IEditableCollection, IReduce, IKVReduce{ +public class PersistentVector extends APersistentVector implements IObj, IEditableCollection, IReduce, IKVReduce, IDrop{ public static class Node implements Serializable { transient public final AtomicReference edit; @@ -363,7 +363,18 @@ public Object kvreduce(IFn f, Object init){ return init; } -static public final class ChunkedSeq extends ASeq implements IChunkedSeq,Counted{ +public Sequential drop(int n) { + if(n < 0) { + return this; + } else if(n < cnt) { + int offset = n%32; + return new ChunkedSeq(this, this.arrayFor(n), n-offset, offset); + } else { + return null; + } +} + +static public final class ChunkedSeq extends ASeq implements IChunkedSeq,Counted,IReduce,IDrop{ public final PersistentVector vec; final Object[] node; @@ -428,6 +439,73 @@ public ISeq next(){ public int count(){ return vec.cnt - (i + offset); } + + public Iterator iterator() { + return vec.rangedIterator(i +offset, vec.cnt); + } + + public Object reduce(IFn f) { + Object acc; + if (i +offset < vec.cnt) + acc = node[offset]; + else + return f.invoke(); + + for(int j=offset+1;j 1) { + return new Repeat(count-n, val); + } else if(count == INFINITE) { + return this; + } else { + return null; + } +} + } diff --git a/src/jvm/clojure/lang/StringSeq.java b/src/jvm/clojure/lang/StringSeq.java index bcb269d5dc..cc93dea55b 100644 --- a/src/jvm/clojure/lang/StringSeq.java +++ b/src/jvm/clojure/lang/StringSeq.java @@ -12,7 +12,10 @@ package clojure.lang; -public class StringSeq extends ASeq implements IndexedSeq{ +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class StringSeq extends ASeq implements IndexedSeq,IDrop,IReduceInit{ public final CharSequence s; public final int i; @@ -51,4 +54,24 @@ public int index(){ public int count(){ return s.length() - i; } + +public Sequential drop(int n) { + int ii = i + n; + if (ii < s.length()) { + return new StringSeq(_meta, s, ii); + } else { + return null; + } +} + +public Object reduce(IFn f, Object start) { + Object acc = start; + for(int ii=i; ii < s.length(); ii++) { + acc = f.invoke(acc, s.charAt(ii)); + if(RT.isReduced(acc)) + return ((IDeref)acc).deref(); + } + return acc; +} + } diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj index 4eb99e7860..c684a6b298 100644 --- a/test/clojure/test_clojure/sequences.clj +++ b/test/clojure/test_clojure/sequences.clj @@ -796,6 +796,23 @@ (is (= (assoc (array-map (repeat 1 :x) :y) '(:x) :z) {'(:x) :z})) (is (= (assoc (hash-map (repeat 1 :x) :y) '(:x) :z) {'(:x) :z}))) +(deftest test-partitionv + (are [x y] (= x y) + (partitionv 2 [1 2 3]) '((1 2)) + (partitionv 2 [1 2 3 4]) '((1 2) (3 4)) + (partitionv 2 []) () + + (partitionv 2 3 [1 2 3 4 5 6 7]) '((1 2) (4 5)) + (partitionv 2 3 [1 2 3 4 5 6 7 8]) '((1 2) (4 5) (7 8)) + (partitionv 2 3 []) () + + (partitionv 1 []) () + (partitionv 1 [1 2 3]) '((1) (2) (3)) + + (partitionv 5 [1 2 3]) () + + (partitionv -1 [1 2 3]) () + (partitionv -2 [1 2 3]) () )) (deftest test-iterate (are [x y] (= x y) @@ -1331,6 +1348,12 @@ (is (= (partition-all 4 2 [1 2 3 4 5 6 7 8 9]) [[1 2 3 4] [3 4 5 6] [5 6 7 8] [7 8 9] [9]]))) +(deftest test-partitionv-all + (is (= (partitionv-all 4 [1 2 3 4 5 6 7 8 9]) + [[1 2 3 4] [5 6 7 8] [9]])) + (is (= (partitionv-all 4 2 [1 2 3 4 5 6 7 8 9]) + [[1 2 3 4] [3 4 5 6] [5 6 7 8] [7 8 9] [9]]))) + (deftest test-shuffle-invariants (is (= (count (shuffle [1 2 3 4])) 4)) (let [shuffled-seq (shuffle [1 2 3 4])] @@ -1458,6 +1481,42 @@ :kf #(some-> % :k #{0 1 2}) :vf :item)))))) +(deftest test-reduce-on-coll-seqs + ;; reduce on seq of coll, both with and without an init + (are [coll expected expected-init] + (and + (= expected-init (reduce conj [:init] (seq coll))) + (= expected (reduce conj (seq coll)))) + ;; (seq [ ... ]) + [] [] [:init] + [1] 1 [:init 1] + [[1] 2] [1 2] [:init [1] 2] + + ;; (seq { ... }) + {} [] [:init] + {1 1} [1 1] [:init [1 1]] + {1 1 2 2} [1 1 [2 2]] [:init [1 1] [2 2]] + + ;; (seq (hash-map ... )) + (hash-map) [] [:init] + (hash-map 1 1) [1 1] [:init [1 1]] + (hash-map 1 1 2 2) [1 1 [2 2]] [:init [1 1] [2 2]] + + ;; (seq (sorted-map ... )) + (sorted-map) [] [:init] + (sorted-map 1 1) [1 1] [:init [1 1]] + (sorted-map 1 1 2 2) [1 1 [2 2]] [:init [1 1] [2 2]]) + + (are [coll expected expected-init] + (and + (= expected-init (reduce + 100 (seq coll))) + (= expected (reduce + (seq coll)))) + + ;; (seq (range ...)) + (range 0) 0 100 + (range 1 2) 1 101 + (range 1 3) 3 103)) + (defspec iteration-seq-equals-reduce 1000 (prop/for-all [initk gen/int seed gen/int] From 56d37996b18df811c20f391c840e7fd26ed2f58d Mon Sep 17 00:00:00 2001 From: Fogus Date: Thu, 9 Jun 2022 09:27:33 -0500 Subject: [PATCH 118/285] CLJ-1327: Pinned the serialVersionUID for Clojure types to v1.10.3 values --- src/jvm/clojure/lang/AFunction.java | 2 ++ src/jvm/clojure/lang/AMapEntry.java | 2 ++ src/jvm/clojure/lang/APersistentMap.java | 3 +++ src/jvm/clojure/lang/APersistentSet.java | 3 +++ src/jvm/clojure/lang/APersistentVector.java | 3 +++ src/jvm/clojure/lang/ASeq.java | 3 +++ src/jvm/clojure/lang/ArityException.java | 2 ++ src/jvm/clojure/lang/ArrayChunk.java | 2 ++ src/jvm/clojure/lang/BigInt.java | 2 ++ src/jvm/clojure/lang/ChunkedCons.java | 2 ++ src/jvm/clojure/lang/Cons.java | 2 ++ src/jvm/clojure/lang/Cycle.java | 2 ++ src/jvm/clojure/lang/EnumerationSeq.java | 3 +++ src/jvm/clojure/lang/ExceptionInfo.java | 3 +++ src/jvm/clojure/lang/FnLoaderThunk.java | 2 ++ src/jvm/clojure/lang/Iterate.java | 2 ++ src/jvm/clojure/lang/IteratorSeq.java | 3 +++ src/jvm/clojure/lang/LazySeq.java | 2 ++ src/jvm/clojure/lang/MapEntry.java | 3 +++ src/jvm/clojure/lang/Namespace.java | 3 +++ src/jvm/clojure/lang/Obj.java | 2 ++ src/jvm/clojure/lang/PersistentArrayMap.java | 2 ++ src/jvm/clojure/lang/PersistentHashMap.java | 2 ++ src/jvm/clojure/lang/PersistentHashSet.java | 2 ++ src/jvm/clojure/lang/PersistentList.java | 2 ++ src/jvm/clojure/lang/PersistentQueue.java | 2 ++ src/jvm/clojure/lang/PersistentStructMap.java | 2 ++ src/jvm/clojure/lang/PersistentVector.java | 2 ++ src/jvm/clojure/lang/Range.java | 2 ++ src/jvm/clojure/lang/Ratio.java | 3 +++ src/jvm/clojure/lang/Repeat.java | 2 ++ src/jvm/clojure/lang/RestFn.java | 3 +++ src/jvm/clojure/lang/StringSeq.java | 3 +++ src/jvm/clojure/lang/Symbol.java | 3 +++ src/jvm/clojure/lang/Var.java | 2 ++ 35 files changed, 83 insertions(+) diff --git a/src/jvm/clojure/lang/AFunction.java b/src/jvm/clojure/lang/AFunction.java index 2ef5cd9b3a..4ab8c6932b 100644 --- a/src/jvm/clojure/lang/AFunction.java +++ b/src/jvm/clojure/lang/AFunction.java @@ -17,6 +17,8 @@ public abstract class AFunction extends AFn implements IObj, Comparator, Fn, Serializable { +private static final long serialVersionUID = 4469383498184457675L; + public volatile MethodImplCache __methodImplCache; public IPersistentMap meta(){ diff --git a/src/jvm/clojure/lang/AMapEntry.java b/src/jvm/clojure/lang/AMapEntry.java index 41ae7563a1..56debb4f1c 100644 --- a/src/jvm/clojure/lang/AMapEntry.java +++ b/src/jvm/clojure/lang/AMapEntry.java @@ -16,6 +16,8 @@ public abstract class AMapEntry extends APersistentVector implements IMapEntry{ +private static final long serialVersionUID = -5007980429903443802L; + public Object nth(int i){ if(i == 0) return key(); diff --git a/src/jvm/clojure/lang/APersistentMap.java b/src/jvm/clojure/lang/APersistentMap.java index 7f96271278..3dfb73a5ae 100644 --- a/src/jvm/clojure/lang/APersistentMap.java +++ b/src/jvm/clojure/lang/APersistentMap.java @@ -14,6 +14,9 @@ import java.util.*; public abstract class APersistentMap extends AFn implements IPersistentMap, Map, Iterable, Serializable, MapEquivalence, IHashEq { + +private static final long serialVersionUID = 6736310834519110267L; + int _hash; int _hasheq; diff --git a/src/jvm/clojure/lang/APersistentSet.java b/src/jvm/clojure/lang/APersistentSet.java index 1c2ce8f46c..2c8caad85b 100644 --- a/src/jvm/clojure/lang/APersistentSet.java +++ b/src/jvm/clojure/lang/APersistentSet.java @@ -18,6 +18,9 @@ import java.util.Set; public abstract class APersistentSet extends AFn implements IPersistentSet, Collection, Set, Serializable, IHashEq { + +private static final long serialVersionUID = 889908853183699706L; + int _hash; int _hasheq; final IPersistentMap impl; diff --git a/src/jvm/clojure/lang/APersistentVector.java b/src/jvm/clojure/lang/APersistentVector.java index 3e88d14dbf..07115684aa 100644 --- a/src/jvm/clojure/lang/APersistentVector.java +++ b/src/jvm/clojure/lang/APersistentVector.java @@ -19,6 +19,9 @@ public abstract class APersistentVector extends AFn implements IPersistentVector List, RandomAccess, Comparable, Serializable, IHashEq { + +private static final long serialVersionUID = 4667575149454420891L; + int _hash; int _hasheq; diff --git a/src/jvm/clojure/lang/ASeq.java b/src/jvm/clojure/lang/ASeq.java index f0f8e5d447..ec1b4d67f4 100644 --- a/src/jvm/clojure/lang/ASeq.java +++ b/src/jvm/clojure/lang/ASeq.java @@ -14,6 +14,9 @@ import java.util.*; public abstract class ASeq extends Obj implements ISeq, Sequential, List, Serializable, IHashEq { + +private static final long serialVersionUID = 4748650717905139299L; + transient int _hash; transient int _hasheq; diff --git a/src/jvm/clojure/lang/ArityException.java b/src/jvm/clojure/lang/ArityException.java index 49b7914b70..5c0f384f1a 100644 --- a/src/jvm/clojure/lang/ArityException.java +++ b/src/jvm/clojure/lang/ArityException.java @@ -15,6 +15,8 @@ */ public class ArityException extends IllegalArgumentException { + private static final long serialVersionUID = 2265783180488869950L; + final public int actual; final public String name; diff --git a/src/jvm/clojure/lang/ArrayChunk.java b/src/jvm/clojure/lang/ArrayChunk.java index 97430839b9..ba6334cf54 100644 --- a/src/jvm/clojure/lang/ArrayChunk.java +++ b/src/jvm/clojure/lang/ArrayChunk.java @@ -16,6 +16,8 @@ public final class ArrayChunk implements IChunk, Serializable { +private static final long serialVersionUID = -8302142882294545702L; + final Object[] array; final int off; final int end; diff --git a/src/jvm/clojure/lang/BigInt.java b/src/jvm/clojure/lang/BigInt.java index a3ca969410..1f2b7580d5 100644 --- a/src/jvm/clojure/lang/BigInt.java +++ b/src/jvm/clojure/lang/BigInt.java @@ -17,6 +17,8 @@ public final class BigInt extends Number implements IHashEq{ +private static final long serialVersionUID = 5097771279236135022L; + final public long lpart; final public BigInteger bipart; diff --git a/src/jvm/clojure/lang/ChunkedCons.java b/src/jvm/clojure/lang/ChunkedCons.java index b52bc2b62a..25b32200d3 100644 --- a/src/jvm/clojure/lang/ChunkedCons.java +++ b/src/jvm/clojure/lang/ChunkedCons.java @@ -14,6 +14,8 @@ final public class ChunkedCons extends ASeq implements IChunkedSeq{ +private static final long serialVersionUID = 2773920188566401743L; + final IChunk chunk; final ISeq _more; diff --git a/src/jvm/clojure/lang/Cons.java b/src/jvm/clojure/lang/Cons.java index 88dceef395..9378881ddc 100644 --- a/src/jvm/clojure/lang/Cons.java +++ b/src/jvm/clojure/lang/Cons.java @@ -16,6 +16,8 @@ final public class Cons extends ASeq implements Serializable { +private static final long serialVersionUID = 6682587018567831263L; + private final Object _first; private final ISeq _more; diff --git a/src/jvm/clojure/lang/Cycle.java b/src/jvm/clojure/lang/Cycle.java index 877695558a..a605e8ca20 100644 --- a/src/jvm/clojure/lang/Cycle.java +++ b/src/jvm/clojure/lang/Cycle.java @@ -14,6 +14,8 @@ public class Cycle extends ASeq implements IReduce, IPending { +private static final long serialVersionUID = 4007270937279943908L; + private final ISeq all; // never null private final ISeq prev; private volatile ISeq _current; // lazily realized diff --git a/src/jvm/clojure/lang/EnumerationSeq.java b/src/jvm/clojure/lang/EnumerationSeq.java index 3616fa787c..acd13ca1e8 100644 --- a/src/jvm/clojure/lang/EnumerationSeq.java +++ b/src/jvm/clojure/lang/EnumerationSeq.java @@ -17,6 +17,9 @@ import java.util.Enumeration; public class EnumerationSeq extends ASeq{ + +private static final long serialVersionUID = 5227192199685595994L; + final Enumeration iter; final State state; diff --git a/src/jvm/clojure/lang/ExceptionInfo.java b/src/jvm/clojure/lang/ExceptionInfo.java index 92040d21e0..f7b704deab 100644 --- a/src/jvm/clojure/lang/ExceptionInfo.java +++ b/src/jvm/clojure/lang/ExceptionInfo.java @@ -16,6 +16,9 @@ * exception classes. */ public class ExceptionInfo extends RuntimeException implements IExceptionInfo { + + private static final long serialVersionUID = -1073473305916521986L; + public final IPersistentMap data; public ExceptionInfo(String s, IPersistentMap data) { diff --git a/src/jvm/clojure/lang/FnLoaderThunk.java b/src/jvm/clojure/lang/FnLoaderThunk.java index 692e45c752..1411bf4902 100644 --- a/src/jvm/clojure/lang/FnLoaderThunk.java +++ b/src/jvm/clojure/lang/FnLoaderThunk.java @@ -14,6 +14,8 @@ public class FnLoaderThunk extends RestFn{ +private static final long serialVersionUID = 2194257205455463687L; + final Var v; final ClassLoader loader; final String fnClassName; diff --git a/src/jvm/clojure/lang/Iterate.java b/src/jvm/clojure/lang/Iterate.java index aec0c14aa2..0bbe733d94 100644 --- a/src/jvm/clojure/lang/Iterate.java +++ b/src/jvm/clojure/lang/Iterate.java @@ -14,6 +14,8 @@ public class Iterate extends ASeq implements IReduce, IPending { +private static final long serialVersionUID = -78221705247226450L; + private static final Object UNREALIZED_SEED = new Object(); private final IFn f; // never null private final Object prevSeed; diff --git a/src/jvm/clojure/lang/IteratorSeq.java b/src/jvm/clojure/lang/IteratorSeq.java index 9ecdbc48df..18b9cf3503 100644 --- a/src/jvm/clojure/lang/IteratorSeq.java +++ b/src/jvm/clojure/lang/IteratorSeq.java @@ -15,6 +15,9 @@ import java.util.Iterator; public class IteratorSeq extends ASeq{ + +private static final long serialVersionUID = -2631916503522522760L; + final Iterator iter; final State state; diff --git a/src/jvm/clojure/lang/LazySeq.java b/src/jvm/clojure/lang/LazySeq.java index 0ca4e46223..f9f9bfb24e 100644 --- a/src/jvm/clojure/lang/LazySeq.java +++ b/src/jvm/clojure/lang/LazySeq.java @@ -16,6 +16,8 @@ public final class LazySeq extends Obj implements ISeq, Sequential, List, IPending, IHashEq{ +private static final long serialVersionUID = 7700080124382322592L; + private IFn fn; private Object sv; private ISeq s; diff --git a/src/jvm/clojure/lang/MapEntry.java b/src/jvm/clojure/lang/MapEntry.java index 310199c1db..777b262734 100644 --- a/src/jvm/clojure/lang/MapEntry.java +++ b/src/jvm/clojure/lang/MapEntry.java @@ -13,6 +13,9 @@ import java.util.Iterator; public class MapEntry extends AMapEntry{ + +private static final long serialVersionUID = -3752414622414469244L; + final Object _key; final Object _val; diff --git a/src/jvm/clojure/lang/Namespace.java b/src/jvm/clojure/lang/Namespace.java index 68cded632e..7fd465fc42 100644 --- a/src/jvm/clojure/lang/Namespace.java +++ b/src/jvm/clojure/lang/Namespace.java @@ -18,6 +18,9 @@ import java.util.concurrent.atomic.AtomicReference; public class Namespace extends AReference implements Serializable { + +private static final long serialVersionUID = -3134444395801383865L; + final public Symbol name; transient final AtomicReference mappings = new AtomicReference(); transient final AtomicReference aliases = new AtomicReference(); diff --git a/src/jvm/clojure/lang/Obj.java b/src/jvm/clojure/lang/Obj.java index bd7ee91878..655d09117d 100644 --- a/src/jvm/clojure/lang/Obj.java +++ b/src/jvm/clojure/lang/Obj.java @@ -16,6 +16,8 @@ public abstract class Obj implements IObj, Serializable { +private static final long serialVersionUID = 802029099426284526L; + final IPersistentMap _meta; public Obj(IPersistentMap meta){ diff --git a/src/jvm/clojure/lang/PersistentArrayMap.java b/src/jvm/clojure/lang/PersistentArrayMap.java index 73e8c023cb..18bbcaa7b3 100644 --- a/src/jvm/clojure/lang/PersistentArrayMap.java +++ b/src/jvm/clojure/lang/PersistentArrayMap.java @@ -29,6 +29,8 @@ public class PersistentArrayMap extends APersistentMap implements IObj, IEditableCollection, IMapIterable, IKVReduce, IDrop{ +private static final long serialVersionUID = -2074065891090893601L; + final Object[] array; static final int HASHTABLE_THRESHOLD = 16; diff --git a/src/jvm/clojure/lang/PersistentHashMap.java b/src/jvm/clojure/lang/PersistentHashMap.java index 0cb1259796..8f15944bc6 100644 --- a/src/jvm/clojure/lang/PersistentHashMap.java +++ b/src/jvm/clojure/lang/PersistentHashMap.java @@ -27,6 +27,8 @@ public class PersistentHashMap extends APersistentMap implements IEditableCollection, IObj, IMapIterable, IKVReduce { +private static final long serialVersionUID = -8682496769319143320L; + final int count; final INode root; final boolean hasNull; diff --git a/src/jvm/clojure/lang/PersistentHashSet.java b/src/jvm/clojure/lang/PersistentHashSet.java index d3a7162605..b481a9443c 100644 --- a/src/jvm/clojure/lang/PersistentHashSet.java +++ b/src/jvm/clojure/lang/PersistentHashSet.java @@ -16,6 +16,8 @@ public class PersistentHashSet extends APersistentSet implements IObj, IEditableCollection { +private static final long serialVersionUID = 6973890746204954938L; + static public final PersistentHashSet EMPTY = new PersistentHashSet(null, PersistentHashMap.EMPTY); final IPersistentMap _meta; diff --git a/src/jvm/clojure/lang/PersistentList.java b/src/jvm/clojure/lang/PersistentList.java index 618d52fca0..225651d663 100644 --- a/src/jvm/clojure/lang/PersistentList.java +++ b/src/jvm/clojure/lang/PersistentList.java @@ -15,6 +15,8 @@ public class PersistentList extends ASeq implements IPersistentList, IReduce, List, Counted { +private static final long serialVersionUID = -8833289659955219995L; + private final Object _first; private final IPersistentList _rest; private final int _count; diff --git a/src/jvm/clojure/lang/PersistentQueue.java b/src/jvm/clojure/lang/PersistentQueue.java index af916193e9..881c190028 100644 --- a/src/jvm/clojure/lang/PersistentQueue.java +++ b/src/jvm/clojure/lang/PersistentQueue.java @@ -24,6 +24,8 @@ public class PersistentQueue extends Obj implements IPersistentList, Collection, Counted, IHashEq{ +private static final long serialVersionUID = 8247184423915313132L; + final public static PersistentQueue EMPTY = new PersistentQueue(null, 0, null, null); //* diff --git a/src/jvm/clojure/lang/PersistentStructMap.java b/src/jvm/clojure/lang/PersistentStructMap.java index 734428c06c..7e9c92e317 100644 --- a/src/jvm/clojure/lang/PersistentStructMap.java +++ b/src/jvm/clojure/lang/PersistentStructMap.java @@ -19,6 +19,8 @@ public class PersistentStructMap extends APersistentMap implements IObj{ +private static final long serialVersionUID = -2701411408470234065L; + public static class Def implements Serializable{ final ISeq keys; final IPersistentMap keyslots; diff --git a/src/jvm/clojure/lang/PersistentVector.java b/src/jvm/clojure/lang/PersistentVector.java index 9f02353965..4b9f3260ad 100644 --- a/src/jvm/clojure/lang/PersistentVector.java +++ b/src/jvm/clojure/lang/PersistentVector.java @@ -21,6 +21,8 @@ public class PersistentVector extends APersistentVector implements IObj, IEditableCollection, IReduce, IKVReduce, IDrop{ +private static final long serialVersionUID = -7896022351281214157L; + public static class Node implements Serializable { transient public final AtomicReference edit; public final Object[] array; diff --git a/src/jvm/clojure/lang/Range.java b/src/jvm/clojure/lang/Range.java index 4f638e9f97..9408421da0 100644 --- a/src/jvm/clojure/lang/Range.java +++ b/src/jvm/clojure/lang/Range.java @@ -18,6 +18,8 @@ */ public class Range extends ASeq implements IChunkedSeq, IReduce { +private static final long serialVersionUID = -71973733672395145L; + private static final int CHUNK_SIZE = 32; // Invariants guarantee this is never an "empty" seq diff --git a/src/jvm/clojure/lang/Ratio.java b/src/jvm/clojure/lang/Ratio.java index 6c7a9bb6e2..02af3fdea2 100644 --- a/src/jvm/clojure/lang/Ratio.java +++ b/src/jvm/clojure/lang/Ratio.java @@ -17,6 +17,9 @@ import java.math.MathContext; public class Ratio extends Number implements Comparable{ + +private static final long serialVersionUID = -576272795628662988L; + final public BigInteger numerator; final public BigInteger denominator; diff --git a/src/jvm/clojure/lang/Repeat.java b/src/jvm/clojure/lang/Repeat.java index b874bea23f..934163902e 100644 --- a/src/jvm/clojure/lang/Repeat.java +++ b/src/jvm/clojure/lang/Repeat.java @@ -14,6 +14,8 @@ public class Repeat extends ASeq implements IReduce, IDrop { +private static final long serialVersionUID = -5140377547192202551L; + private static final long INFINITE = -1; private final long count; // always INFINITE or >0 diff --git a/src/jvm/clojure/lang/RestFn.java b/src/jvm/clojure/lang/RestFn.java index 98646835c3..f6d844302a 100644 --- a/src/jvm/clojure/lang/RestFn.java +++ b/src/jvm/clojure/lang/RestFn.java @@ -10,6 +10,9 @@ package clojure.lang; public abstract class RestFn extends AFunction{ + +private static final long serialVersionUID = -4319097849151802009L; + abstract public int getRequiredArity(); protected Object doInvoke(Object args) { diff --git a/src/jvm/clojure/lang/StringSeq.java b/src/jvm/clojure/lang/StringSeq.java index cc93dea55b..3163380898 100644 --- a/src/jvm/clojure/lang/StringSeq.java +++ b/src/jvm/clojure/lang/StringSeq.java @@ -16,6 +16,9 @@ import java.util.NoSuchElementException; public class StringSeq extends ASeq implements IndexedSeq,IDrop,IReduceInit{ + +private static final long serialVersionUID = 7975525539139301753L; + public final CharSequence s; public final int i; diff --git a/src/jvm/clojure/lang/Symbol.java b/src/jvm/clojure/lang/Symbol.java index 630ef1bb4d..5957bbebbb 100644 --- a/src/jvm/clojure/lang/Symbol.java +++ b/src/jvm/clojure/lang/Symbol.java @@ -17,6 +17,9 @@ public class Symbol extends AFn implements IObj, Comparable, Named, Serializable, IHashEq{ + +private static final long serialVersionUID = 1191039485148212259L; + final String ns; final String name; private int _hasheq; diff --git a/src/jvm/clojure/lang/Var.java b/src/jvm/clojure/lang/Var.java index 787661926c..96f0cee635 100644 --- a/src/jvm/clojure/lang/Var.java +++ b/src/jvm/clojure/lang/Var.java @@ -19,6 +19,8 @@ public final class Var extends ARef implements IFn, IRef, Settable, Serializable{ +private static final long serialVersionUID = 8368961370796295279L; + static class TBox{ volatile Object val; From 48e3292bb75015616ebce32de85428b71ac8dc1c Mon Sep 17 00:00:00 2001 From: Fogus Date: Wed, 1 Jun 2022 07:44:05 -0400 Subject: [PATCH 119/285] CLJ-2712: Revert "fix AOT bug preventing overriding of clojure.core functions" This reverts commit 59889fdeb7ef7f4f73e13fa6ecb627f62b7d2adb. Existing code handles the condition where a namespace mapping shadows an existing core name but does not handle the case where a var will shadow a future core var. New code to handle all cases is available in CLJ-2711. --- src/jvm/clojure/lang/Compiler.java | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 12cf1e5623..758108e8bc 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -410,7 +410,6 @@ static class DefExpr implements Expr{ public final Expr meta; public final boolean initProvided; public final boolean isDynamic; - public final boolean shadowsCoreMapping; public final String source; public final int line; public final int column; @@ -419,9 +418,8 @@ static class DefExpr implements Expr{ final static Method setMetaMethod = Method.getMethod("void setMeta(clojure.lang.IPersistentMap)"); final static Method setDynamicMethod = Method.getMethod("clojure.lang.Var setDynamic(boolean)"); final static Method symintern = Method.getMethod("clojure.lang.Symbol intern(String, String)"); - final static Method internVar = Method.getMethod("clojure.lang.Var refer(clojure.lang.Symbol, clojure.lang.Var)"); - public DefExpr(String source, int line, int column, Var var, Expr init, Expr meta, boolean initProvided, boolean isDynamic, boolean shadowsCoreMapping){ + public DefExpr(String source, int line, int column, Var var, Expr init, Expr meta, boolean initProvided, boolean isDynamic){ this.source = source; this.line = line; this.column = column; @@ -429,7 +427,6 @@ public DefExpr(String source, int line, int column, Var var, Expr init, Expr met this.init = init; this.meta = meta; this.isDynamic = isDynamic; - this.shadowsCoreMapping = shadowsCoreMapping; this.initProvided = initProvided; } @@ -475,18 +472,6 @@ public Object eval() { public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ objx.emitVar(gen, var); - - if (shadowsCoreMapping) - { - gen.dup(); - gen.getField(VAR_TYPE, "ns", NS_TYPE); - gen.swap(); - gen.dup(); - gen.getField(VAR_TYPE, "sym", SYMBOL_TYPE); - gen.swap(); - gen.invokeVirtual(NS_TYPE, internVar); - } - if(isDynamic) { gen.push(isDynamic); @@ -544,13 +529,11 @@ else if(!(RT.second(form) instanceof Symbol)) Var v = lookupVar(sym, true); if(v == null) throw Util.runtimeException("Can't refer to qualified var that doesn't exist"); - boolean shadowsCoreMapping = false; if(!v.ns.equals(currentNS())) { if(sym.ns == null) { v = currentNS().intern(sym); - shadowsCoreMapping = true; registerVar(v); } // throw Util.runtimeException("Name conflict, can't def " + sym + " because namespace: " + currentNS().name + @@ -594,7 +577,7 @@ else if(!(RT.second(form) instanceof Symbol)) Expr meta = mm.count()==0 ? null:analyze(context == C.EVAL ? context : C.EXPRESSION, mm); return new DefExpr((String) SOURCE.deref(), lineDeref(), columnDeref(), v, analyze(context == C.EVAL ? context : C.EXPRESSION, RT.third(form), v.sym.name), - meta, RT.count(form) == 3, isDynamic, shadowsCoreMapping); + meta, RT.count(form) == 3, isDynamic); } } } From 1e8fb8f51796b71d61a2992d4e2661827770158b Mon Sep 17 00:00:00 2001 From: Fogus Date: Wed, 8 Jun 2022 11:19:17 -0400 Subject: [PATCH 120/285] CLJ-2711: Implements namespace interning policy such that whenever interned vars (i.e. a mapping of sym => #'ns/sym in namespace ns) are defined, they cannot ever be replaced via refer or intern. Any attempt to replace interened vars will result in a warning and recommendation to use ns-unmap first. --- src/jvm/clojure/lang/Namespace.java | 75 ++++++++++++++++++++--------- test/clojure/test_clojure/rt.clj | 43 ++++++++--------- 2 files changed, 74 insertions(+), 44 deletions(-) diff --git a/src/jvm/clojure/lang/Namespace.java b/src/jvm/clojure/lang/Namespace.java index 7fd465fc42..359815778c 100644 --- a/src/jvm/clojure/lang/Namespace.java +++ b/src/jvm/clojure/lang/Namespace.java @@ -50,11 +50,22 @@ public IPersistentMap getMappings(){ return mappings.get(); } +/** + * An interned mapping is one where a var's ns matches the current ns and its sym matches the mapping key. + * Once established, interned mappings should never change. + */ +private boolean isInternedMapping(Symbol sym, Object o){ + return(o instanceof Var && + ((Var) o).ns == this && + ((Var) o).sym.equals(sym)); +} + public Var intern(Symbol sym){ if(sym.ns != null) { throw new IllegalArgumentException("Can't intern namespace-qualified symbol"); } + IPersistentMap map = getMappings(); Object o; Var v = null; @@ -66,32 +77,50 @@ public Var intern(Symbol sym){ mappings.compareAndSet(map, newMap); map = getMappings(); } - if(o instanceof Var && ((Var) o).ns == this) + if(isInternedMapping(sym, o)) return (Var) o; if(v == null) v = new Var(this, sym); - warnOrFailOnReplace(sym, o, v); - + if(checkReplacement(sym, o, v)){ + while (!mappings.compareAndSet(map, map.assoc(sym, v))) + map = getMappings(); - while(!mappings.compareAndSet(map, map.assoc(sym, v))) - map = getMappings(); + return v; + } - return v; + return (Var) o; } -private void warnOrFailOnReplace(Symbol sym, Object o, Object v){ - if (o instanceof Var) - { - Namespace ns = ((Var)o).ns; - if (ns == this || (v instanceof Var && ((Var)v).ns == RT.CLOJURE_NS)) - return; - if (ns != RT.CLOJURE_NS) - throw new IllegalStateException(sym + " already refers to: " + o + " in namespace: " + name); - } - RT.errPrintWriter().println("WARNING: " + sym + " already refers to: " + o + " in namespace: " + name - + ", being replaced by: " + v); +/* + This method checks if a namespace's mapping is applicable and warns on problematic cases. + It will return a boolean indicating if a mapping is replaceable. + The semantics of what constitutes a legal replacement mapping is summarized as follows: + +| classification | in namespace ns | newval = anything other than ns/name | newval = ns/name | +|----------------+------------------------+--------------------------------------+-------------------------------------| +| native mapping | name -> ns/name | no replace, warn-if newval not-core | no replace, warn-if newval not-core | +| alias mapping | name -> other/whatever | warn + replace | warn + replace | +*/ +private boolean checkReplacement(Symbol sym, Object old, Object neu){ + if(old instanceof Var) { + Namespace ons = ((Var)old).ns; + Namespace nns = neu instanceof Var ? ((Var) neu).ns : null; + + if(isInternedMapping(sym, old)){ + if(nns != RT.CLOJURE_NS){ + RT.errPrintWriter().println("REJECTED: attempt to replace interned var " + + old + " with " + neu + " in " + name + ", you must ns-unmap first"); + return false; + } + else + return false; + } + } + RT.errPrintWriter().println("WARNING: " + sym + " already refers to: " + old + " in namespace: " + name + + ", being replaced by: " + neu); + return true; } Object reference(Symbol sym, Object val){ @@ -99,6 +128,7 @@ Object reference(Symbol sym, Object val){ { throw new IllegalArgumentException("Can't intern namespace-qualified symbol"); } + IPersistentMap map = getMappings(); Object o; while((o = map.valAt(sym)) == null) @@ -110,13 +140,14 @@ Object reference(Symbol sym, Object val){ if(o == val) return o; - warnOrFailOnReplace(sym, o, val); - - while(!mappings.compareAndSet(map, map.assoc(sym, val))) - map = getMappings(); + if(checkReplacement(sym, o, val)){ + while (!mappings.compareAndSet(map, map.assoc(sym, val))) + map = getMappings(); - return val; + return val; + } + return o; } public static boolean areDifferentInstancesOfSameClassName(Class cls1, Class cls2) { diff --git a/test/clojure/test_clojure/rt.clj b/test/clojure/test_clojure/rt.clj index 39526975f8..298fcb00da 100644 --- a/test/clojure/test_clojure/rt.clj +++ b/test/clojure/test_clojure/rt.clj @@ -9,7 +9,8 @@ ; Author: Stuart Halloway (ns clojure.test-clojure.rt - (:require clojure.set) + (:require [clojure.string :as string] + clojure.set) (:use clojure.test clojure.test-helper)) (defn bare-rt-print @@ -75,31 +76,29 @@ (.bindRoot #'example-var 0) (is (not (contains? (meta #'example-var) :macro)))) -(deftest last-var-wins-for-core +(deftest ns-intern-policies (testing "you can replace a core name, with warning" (let [ns (temp-ns) - replacement (gensym)] - (with-err-string-writer (intern ns 'prefers replacement)) + replacement (gensym) + e1 (with-err-string-writer (intern ns 'prefers replacement))] + (is (string/starts-with? e1 "WARNING")) (is (= replacement @('prefers (ns-publics ns)))))) - (testing "you can replace a name you defined before" + (testing "you can replace a defined alias" (let [ns (temp-ns) s (gensym) v1 (intern ns 'foo s) - v2 (intern ns 'bar s)] - (with-err-string-writer (.refer ns 'flatten v1)) - (.refer ns 'flatten v2) + v2 (intern ns 'bar s) + e1 (with-err-string-writer (.refer ns 'flatten v1)) + e2 (with-err-string-writer (.refer ns 'flatten v2))] + (is (string/starts-with? e1 "WARNING")) + (is (string/starts-with? e2 "WARNING")) (is (= v2 (ns-resolve ns 'flatten))))) - (testing "you cannot intern over an existing non-core name" - (let [ns (temp-ns 'clojure.set) - replacement (gensym)] - (is (thrown? IllegalStateException - (intern ns 'subset? replacement))) - (is (nil? ('subset? (ns-publics ns)))) - (is (= #'clojure.set/subset? ('subset? (ns-refers ns)))))) - (testing "you cannot refer over an existing non-core name" - (let [ns (temp-ns 'clojure.set) - replacement (gensym)] - (is (thrown? IllegalStateException - (.refer ns 'subset? #'clojure.set/intersection))) - (is (nil? ('subset? (ns-publics ns)))) - (is (= #'clojure.set/subset? ('subset? (ns-refers ns))))))) + (testing "you cannot replace an interned var" + (let [ns1 (temp-ns) + ns2 (temp-ns) + v1 (intern ns1 'foo 1) + v2 (intern ns2 'foo 2) + e1 (with-err-string-writer (.refer ns1 'foo v2))] + (is (string/starts-with? e1 "REJECTED")) + (is (= v1 (ns-resolve ns1 'foo)))))) + From e6fce5a42ba78fadcde00186c0b0c3cd00f45435 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 10 May 2022 11:52:52 -0500 Subject: [PATCH 121/285] CLJ-1872 Extend empty? to counted? colls that arent seqable, such as transients --- src/clj/clojure/core.clj | 17 ++++++++++------- test/clojure/test_clojure/sequences.clj | 10 ++++++++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index db5641339d..1e48fcc9c6 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -6244,13 +6244,6 @@ fails, attempts to require sym's namespace and retries." ([m k f x y z & more] (assoc m k (apply f (get m k) x y z more)))) -(defn empty? - "Returns true if coll has no items - same as (not (seq coll)). - Please use the idiom (seq x) rather than (not (empty? x))" - {:added "1.0" - :static true} - [coll] (not (seq coll))) - (defn coll? "Returns true if x implements IPersistentCollection" {:added "1.0" @@ -6306,6 +6299,16 @@ fails, attempts to require sym's namespace and retries." :static true} [coll] (instance? clojure.lang.Counted coll)) +(defn empty? + "Returns true if coll has no items. To check the emptiness of a seq, + please use the idiom (seq x) rather than (not (empty? x))" + {:added "1.0" + :static true} + [coll] + (if (counted? coll) + (zero? (count coll)) + (not (seq coll)))) + (defn reversible? "Returns true if coll implements Reversible" {:added "1.0" diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj index c684a6b298..7565c6fb8a 100644 --- a/test/clojure/test_clojure/sequences.clj +++ b/test/clojure/test_clojure/sequences.clj @@ -1136,7 +1136,10 @@ {} #{} "" - (into-array []) ) + (into-array []) + (transient []) + (transient #{}) + (transient {})) (are [x] (not (empty? x)) '(1 2) @@ -1145,7 +1148,10 @@ {:a 1 :b 2} #{1 2} "abc" - (into-array [1 2]) )) + (into-array [1 2]) + (transient [1]) + (transient #{1}) + (transient {1 2}))) (deftest test-every? From 7b738af51c1ce52b91d7e9fb7399289a349d18c6 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 30 Jun 2022 15:56:35 -0500 Subject: [PATCH 122/285] Fix javadoc html entity in IDrop --- src/jvm/clojure/lang/IDrop.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/IDrop.java b/src/jvm/clojure/lang/IDrop.java index ce4341ce02..336c0a8270 100644 --- a/src/jvm/clojure/lang/IDrop.java +++ b/src/jvm/clojure/lang/IDrop.java @@ -20,7 +20,7 @@ public interface IDrop{ * useful if the returned coll implements IDrop for subsequent use in a * partition-like scenario. * - * If n is <= 0, return this. + * If n is <= 0, return this. * If n drops to or past the end of the collection, return null. * * @param n Items to drop From 52bb71bb615e2ad2cd75b3d47fce541d5b37c1ec Mon Sep 17 00:00:00 2001 From: Clojure Build Date: Thu, 30 Jun 2022 16:07:41 -0500 Subject: [PATCH 123/285] [maven-release-plugin] prepare release clojure-1.12.0-alpha1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2dd37faaad..709a83e952 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0-alpha1 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0-alpha1 From 5ffe3833508495ca7c635d47ad7a1c8b820eab76 Mon Sep 17 00:00:00 2001 From: Clojure Build Date: Thu, 30 Jun 2022 16:07:41 -0500 Subject: [PATCH 124/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 709a83e952..2dd37faaad 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-alpha1 + 1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0-alpha1 + HEAD From ca1768bcefbea46c43c659780501aa7bfda94ddf Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 6 Sep 2022 09:19:56 -0500 Subject: [PATCH 125/285] CLJ-2721 Fix invalid arg order when adding meta to non-long range --- src/jvm/clojure/lang/Range.java | 2 +- test/clojure/test_clojure/sequences.clj | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/Range.java b/src/jvm/clojure/lang/Range.java index 9408421da0..1e4fbf6e01 100644 --- a/src/jvm/clojure/lang/Range.java +++ b/src/jvm/clojure/lang/Range.java @@ -101,7 +101,7 @@ public static ISeq create(final Object start, Object end, Object step) { public Obj withMeta(IPersistentMap meta){ if(meta == _meta) return this; - return new Range(meta, end, start, step, boundsCheck, _chunk, _chunkNext); + return new Range(meta, start, end, step, boundsCheck, _chunk, _chunkNext); } public Object first(){ diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj index 7565c6fb8a..7a7e6d413c 100644 --- a/test/clojure/test_clojure/sequences.clj +++ b/test/clojure/test_clojure/sequences.clj @@ -1075,6 +1075,15 @@ (reduce + (iterator-seq (.iterator (range 100)))) 4950 (reduce + (iterator-seq (.iterator (range 0.0 100.0 1.0)))) 4950.0 )) +(deftest range-meta + (are [r] (= r (with-meta r {:a 1})) + (range 10) + (range 5 10) + (range 5 10 1) + (range 10.0) + (range 5.0 10.0) + (range 5.0 10.0 1.0))) + (deftest range-test (let [threads 10 n 1000 From 09887382ac5f0bde2ceda0c137cd4aad94b2225d Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 18 Aug 2022 13:28:46 -0500 Subject: [PATCH 126/285] CLJ-2718 Fix bug in drop of repeat that goes to or past end of sequence --- src/jvm/clojure/lang/Repeat.java | 11 +++++++---- test/clojure/test_clojure/sequences.clj | 7 ++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/jvm/clojure/lang/Repeat.java b/src/jvm/clojure/lang/Repeat.java index 934163902e..1190b1e5d7 100644 --- a/src/jvm/clojure/lang/Repeat.java +++ b/src/jvm/clojure/lang/Repeat.java @@ -100,12 +100,15 @@ public Object reduce(IFn f, Object start){ } public Sequential drop(int n) { - if(count > 1) { - return new Repeat(count-n, val); - } else if(count == INFINITE) { + if(count == INFINITE) { return this; } else { - return null; + long droppedCount = count-n; + if(droppedCount > 0) { + return new Repeat(droppedCount, val); + } else { + return null; + } } } diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj index 7a7e6d413c..fd3382ebd8 100644 --- a/test/clojure/test_clojure/sequences.clj +++ b/test/clojure/test_clojure/sequences.clj @@ -1003,7 +1003,12 @@ () '(1 2) [] [1 2] {} {:a 1 :b 2} - #{} #{1 2} )) + #{} #{1 2}) + + ; CLJ-2718 + (is (= '(:a) (drop 1 (repeat 2 :a)))) + (is (= () (drop 2 (repeat 2 :a)))) + (is (= () (drop 3 (repeat 2 :a))))) (defspec longrange-equals-range 1000 (prop/for-all [start gen/int From 527b330045ef35b47a968d80ed3dc4999cfa2623 Mon Sep 17 00:00:00 2001 From: Steve Miner Date: Wed, 12 Oct 2022 13:21:47 -0500 Subject: [PATCH 127/285] CLJ-2715 partitionv - group last padded partition for inclusion in seq of partitions --- src/clj/clojure/core.clj | 2 +- test/clojure/test_clojure/sequences.clj | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 1e48fcc9c6..a146fcfa63 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -7375,7 +7375,7 @@ fails, attempts to require sym's namespace and retries." (let [p (into [] (take n) s)] (if (= n (count p)) (cons p (partitionv n step pad (nthrest s step))) - (into [] (take n) (concat p pad)))))))) + (list (into [] (take n) (concat p pad))))))))) (defn partitionv-all "Returns a lazy sequence of vector partitions, but may include diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj index fd3382ebd8..bc79c1f62e 100644 --- a/test/clojure/test_clojure/sequences.clj +++ b/test/clojure/test_clojure/sequences.clj @@ -781,6 +781,8 @@ (partition 5 [1 2 3]) () + (partition 4 4 [0 0 0] (range 10)) '((0 1 2 3) (4 5 6 7) (8 9 0 0)) + ; (partition 0 [1 2 3]) (repeat nil) ; infinite sequence of nil (partition -1 [1 2 3]) () (partition -2 [1 2 3]) () ) @@ -809,6 +811,8 @@ (partitionv 1 []) () (partitionv 1 [1 2 3]) '((1) (2) (3)) + (partitionv 4 4 [0 0 0] (range 10)) '([0 1 2 3] [4 5 6 7] [8 9 0 0]) + (partitionv 5 [1 2 3]) () (partitionv -1 [1 2 3]) () From cdba5c88a6dca17a37cd652357e044fc351b0172 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 11 Jan 2022 08:37:03 -0600 Subject: [PATCH 128/285] CLJ-2683 Fix with-open macro to not qualify the close method on expansion --- src/clj/clojure/core.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index a146fcfa63..00ccda1072 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -3852,7 +3852,7 @@ (try (with-open ~(subvec bindings 2) ~@body) (finally - (. ~(bindings 0) close)))) + (. ~(bindings 0) ~'close)))) :else (throw (IllegalArgumentException. "with-open only allows Symbols in bindings")))) From b9a51c4232fbc600fea86cd737d8d7a9e6c8c653 Mon Sep 17 00:00:00 2001 From: Fogus Date: Tue, 10 May 2022 14:28:37 -0400 Subject: [PATCH 129/285] CLJ-2709: Check arguments to range to see if they are fixed-precision integers and if so upcast them to Long when creating the LongRange instance. --- src/clj/clojure/core.clj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 00ccda1072..d43135dee6 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -3045,15 +3045,15 @@ ([] (iterate inc' 0)) ([end] - (if (instance? Long end) + (if (int? end) (clojure.lang.LongRange/create end) (clojure.lang.Range/create end))) ([start end] - (if (and (instance? Long start) (instance? Long end)) + (if (and (int? start) (int? end)) (clojure.lang.LongRange/create start end) (clojure.lang.Range/create start end))) ([start end step] - (if (and (instance? Long start) (instance? Long end) (instance? Long step)) + (if (and (int? start) (int? end) (int? step)) (clojure.lang.LongRange/create start end step) (clojure.lang.Range/create start end step)))) From f296aa6c27eb40b7012534bee8de353591f3fa56 Mon Sep 17 00:00:00 2001 From: Fogus Date: Tue, 20 Sep 2022 16:43:29 -0400 Subject: [PATCH 130/285] CLJ-2724: fixed improper do-copy hint on output to match multimethod match type --- src/clj/clojure/java/io.clj | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/clj/clojure/java/io.clj b/src/clj/clojure/java/io.clj index 72a30ed7a6..f0715abfd4 100644 --- a/src/clj/clojure/java/io.clj +++ b/src/clj/clojure/java/io.clj @@ -21,6 +21,8 @@ CharArrayReader Closeable) (java.net URI URL MalformedURLException Socket URLDecoder URLEncoder))) +(set! *warn-on-reflection* true) + (def ^{:doc "Type object for a Java primitive byte array." :private true @@ -385,7 +387,7 @@ (defmethod do-copy [byte-array-type Writer] [^"[B" input ^Writer output opts] (do-copy (ByteArrayInputStream. input) output opts)) -(defmethod do-copy [byte-array-type File] [^"[B" input ^Writer output opts] +(defmethod do-copy [byte-array-type File] [^"[B" input ^File output opts] (do-copy (ByteArrayInputStream. input) output opts)) (defn copy From 9f8628f2c20fb9b7bcef35bb9e57b92ffe9c348f Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 29 Sep 2022 17:08:58 -0500 Subject: [PATCH 131/285] CLJ-2726 #uuid data reader throws IllegalArgumentException rather than AssertionError for better error reporting as reader error --- src/clj/clojure/uuid.clj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/uuid.clj b/src/clj/clojure/uuid.clj index dbaa9d141e..4ffbdf60d5 100644 --- a/src/clj/clojure/uuid.clj +++ b/src/clj/clojure/uuid.clj @@ -9,8 +9,9 @@ (ns clojure.uuid) (defn- default-uuid-reader [form] - {:pre [(string? form)]} - (java.util.UUID/fromString form)) + (if (string? form) + (java.util.UUID/fromString form) + (throw (IllegalArgumentException. "#uuid data reader expected string")))) (defmethod print-method java.util.UUID [uuid ^java.io.Writer w] (.write w (str "#uuid \"" (str uuid) "\""))) From 861a5efc136dc4ca52066dcf38f0965367631e7d Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 8 Dec 2022 11:09:19 -0600 Subject: [PATCH 132/285] CLJ-2739 Fix error message when function called with arg count >20 --- src/jvm/clojure/lang/ArityException.java | 2 +- test/clojure/test_clojure/keywords.clj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jvm/clojure/lang/ArityException.java b/src/jvm/clojure/lang/ArityException.java index 5c0f384f1a..89d2c8f4fe 100644 --- a/src/jvm/clojure/lang/ArityException.java +++ b/src/jvm/clojure/lang/ArityException.java @@ -26,7 +26,7 @@ public ArityException(int actual, String name) { } public ArityException(int actual, String name, Throwable cause) { - super("Wrong number of args (" + actual + ") passed to: " + Compiler.demunge(name), cause); + super("Wrong number of args (" + (actual <= 20 ? actual : "> 20") + ") passed to: " + Compiler.demunge(name), cause); this.actual = actual; this.name = name; } diff --git a/test/clojure/test_clojure/keywords.clj b/test/clojure/test_clojure/keywords.clj index 614fbc14e2..b486a067ab 100644 --- a/test/clojure/test_clojure/keywords.clj +++ b/test/clojure/test_clojure/keywords.clj @@ -27,5 +27,5 @@ (deftest arity-exceptions (is (thrown-with-msg? IllegalArgumentException #"Wrong number of args \(0\) passed to: :kw" (:kw))) (is (thrown-with-msg? IllegalArgumentException #"Wrong number of args \(20\) passed to: :foo/bar" (apply :foo/bar (range 20)))) - (is (thrown-with-msg? IllegalArgumentException #"Wrong number of args \(21\) passed to: :foo/bar" (apply :foo/bar (range 21)))) - (is (thrown-with-msg? IllegalArgumentException #"Wrong number of args \(22\) passed to: :foo/bar" (apply :foo/bar (range 22))))) + (is (thrown-with-msg? IllegalArgumentException #"Wrong number of args \(> 20\) passed to: :foo/bar" (apply :foo/bar (range 21)))) + (is (thrown-with-msg? IllegalArgumentException #"Wrong number of args \(> 20\) passed to: :foo/bar" (apply :foo/bar (range 22))))) From adfad027ec5b0ade65f507dbeb917710d95e9949 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 5 Dec 2022 16:40:01 -0600 Subject: [PATCH 133/285] CLJ-2740 Eliminate unneeded call in new fast drop support --- src/jvm/clojure/lang/PersistentVector.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/jvm/clojure/lang/PersistentVector.java b/src/jvm/clojure/lang/PersistentVector.java index 4b9f3260ad..973cb2a31a 100644 --- a/src/jvm/clojure/lang/PersistentVector.java +++ b/src/jvm/clojure/lang/PersistentVector.java @@ -500,7 +500,6 @@ public Sequential drop(int n) { } else { int i = this.i +o; if(i < vec.cnt) { // in vec - Object[] array = vec.arrayFor(i); int newOffset = i%32; return new ChunkedSeq(vec, vec.arrayFor(i), i-newOffset, newOffset); } else { From 8adf5bce1ecb45a940f6b4233aff075be5448a5b Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Wed, 11 May 2022 20:34:19 +0100 Subject: [PATCH 134/285] CLJ-2521: hoist loop bodies in statement position --- src/jvm/clojure/lang/Compiler.java | 2 +- test/clojure/test_clojure/compilation.clj | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 758108e8bc..b7d0dfff8c 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -6342,7 +6342,7 @@ public Expr parse(C context, Object frm) { ISeq body = RT.next(RT.next(form)); if(context == C.EVAL - || (context == C.EXPRESSION && isLoop)) + || (context != C.RETURN && isLoop)) return analyze(context, RT.list(RT.list(FNONCE, PersistentVector.EMPTY, form))); ObjMethod method = (ObjMethod) METHOD.deref(); diff --git a/test/clojure/test_clojure/compilation.clj b/test/clojure/test_clojure/compilation.clj index 999d33f91b..3aae891759 100644 --- a/test/clojure/test_clojure/compilation.clj +++ b/test/clojure/test_clojure/compilation.clj @@ -443,3 +443,7 @@ (testing "CLJ-2580 Correctly calculate exit branches of case" (is (zero? (let [d (case nil :x nil 0)] d))) (is (nil? (let [d (case nil :x 0 nil)] d))))) + +(deftest CLJ-2521 + (testing "CLJ-2521 Can nest loop->try when in statement position" + (is (= "ret" ((fn [] (loop [] (try "" (catch Throwable _))) "ret")))))) From 1e835a9d9fb4498a5cf643df861565c07701b18b Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 15 Dec 2022 17:52:18 -0600 Subject: [PATCH 135/285] CLJ-2742 Revert range to use chunking as before the IDrop changes in CLJ-2713 --- src/jvm/clojure/lang/LongRange.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/jvm/clojure/lang/LongRange.java b/src/jvm/clojure/lang/LongRange.java index d1bfba2fe0..10381cc29b 100644 --- a/src/jvm/clojure/lang/LongRange.java +++ b/src/jvm/clojure/lang/LongRange.java @@ -116,16 +116,23 @@ public ISeq next() { } } +private static final int CHUNK_SIZE = 32; + public IChunk chunkedFirst() { - return new LongChunk(start, step, count); + return new LongChunk(start, step, Math.min(count, CHUNK_SIZE)); } public ISeq chunkedNext() { - return null; + return chunkedMore().seq(); } public ISeq chunkedMore() { - return PersistentList.EMPTY; + if(count <= CHUNK_SIZE) { + return PersistentList.EMPTY; + } else { + return LongRange.create(start + (step * CHUNK_SIZE), end, step); + } + } public Sequential drop(int n) { From b7d87dcd729628a2e80038d05023eb7c7786bb11 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 31 Mar 2023 09:49:21 -0500 Subject: [PATCH 136/285] CLJ-2757 clojure.java.basis - api for accessing basis --- src/clj/clojure/java/basis.clj | 47 ++++++++++++++++++++++++++ src/clj/clojure/java/basis/impl.clj | 51 +++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 src/clj/clojure/java/basis.clj create mode 100644 src/clj/clojure/java/basis/impl.clj diff --git a/src/clj/clojure/java/basis.clj b/src/clj/clojure/java/basis.clj new file mode 100644 index 0000000000..9567801962 --- /dev/null +++ b/src/clj/clojure/java/basis.clj @@ -0,0 +1,47 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. + +(ns clojure.java.basis + "The lib basis includes which libraries and versions were loaded both + for direct dependencies and transitive dependencies, as well as the + classpath and possibly other information from the resolution process. + This basis will be known if the runtime was started by the Clojure CLI. + + The Clojure CLI or tools.deps merge a set of deps maps (often from + deps.edn files). Additional runtime modifications are supplied via argmap + keys, provided via alias maps in the merged deps. Deps maps typically have + :paths, :deps, and :aliases keys. + + The basis is a superset of merged deps.edn files with the following + additional keys: + :basis-config - params used to configure basis deps sources, can be + string path, deps map, nil, or :default + :root - default = loaded as a resource from tools.deps) + :user - default = ~/.clojure/deps.edn) + :project - default = ./deps.edn) + :extra - default = nil + :aliases - coll of keyword aliases to include during dep calculation + :argmap - effective argmap (after resolving and merging argmaps from aliases) + :libs - map of lib to coord for all included libraries + :classpath - classpath map, keys are paths (to directory or .jar), values + are maps with source identifier (either :lib-name or :path-key) + :classpath-roots - vector of paths in classpath order (keys of :classpath)" + (:require + [clojure.java.basis.impl :as impl])) + +(defn initial-basis + "Initial runtime basis at launch, nil if unknown (process not started by CLI)" + {:added "1.12"} + [] + @impl/init-basis) + +(defn current-basis + "Return the current basis, which may have been modified since runtime launch." + {:added "1.12"} + [] + @@impl/the-basis) diff --git a/src/clj/clojure/java/basis/impl.clj b/src/clj/clojure/java/basis/impl.clj new file mode 100644 index 0000000000..5402a9e201 --- /dev/null +++ b/src/clj/clojure/java/basis/impl.clj @@ -0,0 +1,51 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. + +(ns clojure.java.basis.impl + (:require + [clojure.edn :as edn] + [clojure.java.io :as jio]) + (:import + [java.io PushbackReader])) + +(set! *warn-on-reflection* true) + +(defn- read-edn + "Coerce f to a reader via clojure.java.io/reader and read one edn value. + The reader should contain a single value. Empty input returns nil. + The reader will be read to EOF and closed." + [f] + (let [reader (jio/reader f) + EOF (Object.)] + (with-open [rdr (PushbackReader. reader)] + (let [val (edn/read {:default tagged-literal :eof EOF} rdr)] + (if (identical? EOF val) + nil + (if (not (identical? EOF (edn/read {:eof EOF} rdr))) + (throw (ex-info "Invalid file, expected edn to contain a single value." {})) + val)))))) + +(defn- read-basis + "Read basis edn from basis file or throw" + [basis-file] + (when-let [f (jio/file basis-file)] + (when (.exists f) + (read-edn f)))) + +;; delay construction until needed, access via initial-basis +(def init-basis + (delay (read-basis (System/getProperty "clojure.basis")))) + +;; delay construction until needed, access via current-basis +(def the-basis + (delay (atom @init-basis))) + +(defn update-basis! + "Update the runtime basis by applying f with args" + [f & args] + (apply swap! @the-basis f args)) From 65ea3e7688dfb492403f615cb0a5694f5ccefadc Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 6 Apr 2023 12:15:31 -0500 Subject: [PATCH 137/285] CLJ-2759 Java process api --- src/clj/clojure/java/process.clj | 161 +++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 src/clj/clojure/java/process.clj diff --git a/src/clj/clojure/java/process.clj b/src/clj/clojure/java/process.clj new file mode 100644 index 0000000000..881b69413b --- /dev/null +++ b/src/clj/clojure/java/process.clj @@ -0,0 +1,161 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. + +(ns clojure.java.process + "A process invocation API wrapping the Java process API. + + The primary function here is 'start' which starts a process and handles the + streams as directed. It returns a map that contains keys to access the streams + (if available) and the Java Process object. It is also deref-able to wait for + process exit. + + Helper functions are available to 'capture' the output of the process stdout + and to wait for an 'ok?' non-error exit. The 'exec' function handles the common + case of `start'ing a process, waiting for process exit, capture and return + stdout." + (:require + [clojure.java.io :as jio] + [clojure.string :as str]) + (:import + [java.io StringWriter File] + [java.lang ProcessBuilder ProcessBuilder$Redirect Process] + [java.util List] + [clojure.lang IDeref IBlockingDeref])) + +(set! *warn-on-reflection* true) + +;; this is built into Java 9, backfilled here for Java 8 +(def ^:private ^File null-file + (delay + (jio/file + (if (.startsWith (System/getProperty "os.name") "Windows") + "NUL" + "/dev/null")))) + +(defn to-file + "Coerce f to a file per clojure.java.io/file and return a ProcessBuilder.Redirect writing to the file. + Set ':append' in opts to append. This can be passed to 'start' in :out or :err." + {:added "1.12"} + ^ProcessBuilder$Redirect [file & {:keys [append] :as opts}] + (let [f (jio/file file)] + (if append + (ProcessBuilder$Redirect/appendTo f) + (ProcessBuilder$Redirect/to f)))) + +(defn from-file + "Coerce f to a file per clojure.java.io/file and return a ProcessBuilder.Redirect reading from the file. + This can be passed to 'start' in :in." + {:added "1.12"} + ^ProcessBuilder$Redirect [file] + (ProcessBuilder$Redirect/from (jio/file file))) + +(defn start + "Starts an external command as args and optional leading opts map: + + :in - a ProcessBuilder.Redirect (default = :pipe) or :inherit + :out - a ProcessBuilder.Redirect (default = :pipe) or :inherit :discard + :err - a ProcessBuilder.Redirect (default = :pipe) or :inherit :discard :stdout + :dir - directory to run the command from, default=\".\" + :env - {env-var value} of environment variables (all strings) + + Returns an ILookup containing the java.lang.Process in :process and the + streams :in :out :err. The map is also an IDeref that waits for process exit + and returns the exit code." + {:added "1.12"} + [& opts+args] + (let [[opts command] (if (map? (first opts+args)) + [(first opts+args) (rest opts+args)] + [{} opts+args]) + {:keys [in out err dir env] + :or {in :pipe, out :pipe, err :pipe, dir "."}} opts + pb (ProcessBuilder. ^List command) + to-redirect (fn to-redirect + [x] + (case x + :pipe ProcessBuilder$Redirect/PIPE + :inherit ProcessBuilder$Redirect/INHERIT + :discard (ProcessBuilder$Redirect/to @null-file) + ;; in Java 9+, just use ProcessBuilder$Redirect/DISCARD + x))] + (.directory pb (jio/file (or dir "."))) + (when in (.redirectInput pb ^ProcessBuilder$Redirect (to-redirect in))) + (when out (.redirectOutput pb ^ProcessBuilder$Redirect (to-redirect out))) + (cond + (= err :stdout) (.redirectErrorStream pb) + err (.redirectError pb ^ProcessBuilder$Redirect (to-redirect err))) + (when env + (let [pb-env (.environment pb)] + (run! (fn [[k v]] (.put pb-env k v)) env))) + (let [proc (.start pb) + m {:process proc + :in (.getOutputStream proc) + :out (.getInputStream proc) + :err (.getErrorStream proc)}] + (reify + clojure.lang.ILookup + (valAt [_ key] (get m key)) + (valAt [_ key not-found] (get m key not-found)) + + IDeref + (deref [_] (.waitFor proc)) + + IBlockingDeref + (deref [_ timeout unit] (.waitFor proc timeout unit)))))) + +(defn ok? + "Given the map returned from 'start', wait for the process to exit + and then return true on success" + {:added "1.12"} + [process-map] + (zero? (.waitFor ^Process (:process process-map)))) + +(defn capture + "Read from input-stream until EOF and return a String (or nil if 0 length). + Takes same opts as clojure.java.io/copy - :buffer and :encoding" + {:added "1.12"} + [input-stream & opts] + (let [writer (StringWriter.)] + (apply jio/copy input-stream writer opts) + (let [s (str/trim (.toString writer))] + (when-not (zero? (.length s)) + s)))) + +(defn exec + "Execute a command and on successful exit, return the captured output, + else throw RuntimeException. Args are the same as 'start' and options + if supplied override the default 'exec' settings." + {:added "1.12"} + [& opts+args] + (let [[opts command] (if (map? (first opts+args)) + [(first opts+args) (rest opts+args)] + [{} opts+args]) + opts (merge opts {:err :inherit})] + (let [state (apply start opts command) + out-promise (promise) + capture-fn #(deliver out-promise (capture (:out state)))] + (doto (Thread. ^Runnable capture-fn) (.setDaemon true) (.start)) + (if (ok? state) + @out-promise + (throw (RuntimeException. (str "Process failed with exit=" (.exitValue ^Process (:process state))))))))) + +(comment + ;; shell out and inherit the i/o + (start {:out :inherit, :err :stdout} "ls" "-l") + + ;; write out and err to files, wait for process to exit, return exit code + @(start {:out (to-file "out") :err (to-file "err")} "ls" "-l") + + ;; capture output to string + (-> (start "ls" "-l") :out capture) + + ;; with exec + (exec "ls" "-l") + + ;; read input from file + (exec {:in (from-file "deps.edn")} "wc" "-l") + ) From d1ae2781d71fc7f79c52e0730b0d65e89850da5c Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 31 Mar 2023 09:55:19 -0500 Subject: [PATCH 138/285] CLJ-2760 Add api to invoke an external function via the Clojure CLI --- src/clj/clojure/tools/deps/interop.clj | 61 ++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/clj/clojure/tools/deps/interop.clj diff --git a/src/clj/clojure/tools/deps/interop.clj b/src/clj/clojure/tools/deps/interop.clj new file mode 100644 index 0000000000..54449b731a --- /dev/null +++ b/src/clj/clojure/tools/deps/interop.clj @@ -0,0 +1,61 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. +(ns clojure.tools.deps.interop + "Functions for invoking Java processes and invoking tools via the Clojure CLI." + (:require + [clojure.java.process :as proc] + [clojure.edn :as edn])) + +(defn ^:dynamic invoke-tool + "Invoke tool using Clojure CLI. Args (one of :tool-alias or :tool-name, and :fn + are required): + :tool-alias - Tool alias to invoke (keyword) + :tool-name - Name of installed tool to invoke (string or symbol) + :fn - Function (symbol) + :args - map of args to pass to function + + Options: + :command - CLI command, default=\"clojure\" + :preserve-envelope - if true, return the full invocation envelope, default=false" + {:added "1.12"} + [{:keys [tool-name tool-alias fn args command preserve-envelope] + :or {command "clojure", preserve-envelope false} + :as opts}] + (when-not (or tool-name tool-alias) (throw (ex-info "Either :tool-alias or :tool-name must be provided" (or opts {})))) + (when-not (symbol? fn) (throw (ex-info (str "fn should be a symbol " fn) (or opts {})))) + (let [args (assoc args :clojure.exec/invoke :fn) + _ (when (:debug opts) (println "args" args)) + command-strs [command (str "-T" (or tool-alias tool-name)) (pr-str fn) (pr-str args)] + _ (when (:debug opts) (apply println "Invoking: " command-strs)) + envelope (edn/read-string (apply proc/exec command-strs))] + (if preserve-envelope + envelope + (let [{:keys [tag val]} envelope + parsed-val (edn/read-string val)] + (if (= :ret tag) + parsed-val + (throw (ex-info (:cause parsed-val) (or parsed-val {})))))))) + +(comment + ;; regular invocation, should return {:hi :there} + (invoke-tool {:tool-alias :deps, :fn 'clojure.core/identity, :args {:hi :there}}) + + ;; invocation throws, should return throwable map data + (try + (invoke-tool {:tool-alias :deps, :fn 'clojure.core/+, :args {:fail :here}}) + (catch clojure.lang.ExceptionInfo e (ex-data e))) + + ;; capture stdout in returned envelope + (let [resp (invoke-tool {:tool-alias :deps, + :fn 'list + :args {:format :edn + :clojure.exec/out :capture} + :preserve-envelope true})] + (edn/read-string (:out resp))) + + ) From d0175370c05ef12304aa46236012bc56059c3ddc Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 6 Apr 2023 12:20:38 -0500 Subject: [PATCH 139/285] CLJ-2761 - add-libs, add-lib, sync-deps for the repl --- build.xml | 5 ++ src/clj/clojure/core.clj | 5 ++ src/clj/clojure/main.clj | 9 ++-- src/clj/clojure/repl/deps.clj | 94 +++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 src/clj/clojure/repl/deps.clj diff --git a/build.xml b/build.xml index 34fd65b2c6..1464b69ed3 100644 --- a/build.xml +++ b/build.xml @@ -77,7 +77,10 @@ + + + @@ -86,6 +89,8 @@ + + diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index d43135dee6..caa1fb387e 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -6340,6 +6340,11 @@ fails, attempts to require sym's namespace and retries." :added "1.0"} *e) +(def ^:dynamic + ^{:doc "Bound to true in a repl thread" + :added "1.12"} + *repl*) + (defn trampoline "trampoline can be used to convert algorithms requiring mutual recursion without stack consumption. Calls f with supplied args, if diff --git a/src/clj/clojure/main.clj b/src/clj/clojure/main.clj index e769ee56ea..bb72673107 100644 --- a/src/clj/clojure/main.clj +++ b/src/clj/clojure/main.clj @@ -73,7 +73,6 @@ " (" (.getFileName el) ":" (.getLineNumber el) ")"))) ;;;;;;;;;;;;;;;;;;; end of redundantly copied from clojure.repl to avoid dep ;;;;;;;;;;;;;; - (defmacro with-bindings "Executes body in the context of thread-local bindings for several vars that often need to be set!: *ns* *warn-on-reflection* *math-context* @@ -94,6 +93,7 @@ *unchecked-math* *unchecked-math* *assert* *assert* clojure.spec.alpha/*explain-out* clojure.spec.alpha/*explain-out* + *repl* true *1 nil *2 nil *3 nil @@ -356,7 +356,8 @@ by default when a new command-line REPL is started."} repl-requires '[[clojure.repl :refer (source apropos dir pst doc find-doc)] [clojure.java.javadoc :refer (javadoc)] - [clojure.pprint :refer (pp pprint)]]) + [clojure.pprint :refer (pp pprint)] + [clojure.repl.deps :refer (add-libs add-lib sync-deps)]]) (defmacro with-read-known "Evaluates body with *read-eval* set to a \"known\" value, @@ -454,7 +455,7 @@ by default when a new command-line REPL is started."} repl-requires (prompt) (flush) (loop [] - (when-not + (when-not (try (identical? (read-eval-print) request-exit) (catch Throwable e (caught e) @@ -670,6 +671,6 @@ java -cp clojure.jar clojure.main -i init.clj script.clj args...") (catch Throwable t (report-error t :target "file") (System/exit 1)))) - (finally + (finally (flush)))) diff --git a/src/clj/clojure/repl/deps.clj b/src/clj/clojure/repl/deps.clj new file mode 100644 index 0000000000..1ed8365a1c --- /dev/null +++ b/src/clj/clojure/repl/deps.clj @@ -0,0 +1,94 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. +(ns clojure.repl.deps + "clojure.repl.deps provides facilities for dynamically modifying the available + libraries in the runtime when running at the REPL, without restarting" + (:require + [clojure.java.io :as jio] + [clojure.java.basis :as basis] + [clojure.java.basis.impl :as basis-impl] + [clojure.tools.deps.interop :as tool]) + (:import + [clojure.lang DynamicClassLoader] + [java.io File])) + +(set! *warn-on-reflection* true) + +(defn- add-loader-url + "Add url string or URL to the highest level DynamicClassLoader url set." + [url] + (let [u (if (string? url) (java.net.URL. url) url) + loader (loop [loader (.getContextClassLoader (Thread/currentThread))] + (let [parent (.getParent loader)] + (if (instance? DynamicClassLoader parent) + (recur parent) + loader)))] + (if (instance? DynamicClassLoader loader) + (.addURL ^DynamicClassLoader loader u) + (throw (IllegalAccessError. "Context classloader is not a DynamicClassLoader"))))) + +(defn add-libs + "Given lib-coords, a map of lib to coord, will resolve all transitive deps for the libs + together and add them to the repl classpath, unlike separate calls to add-lib." + {:added "1.12"} + [lib-coords] + (when-not *repl* (throw (RuntimeException. "add-libs is only available at the REPL"))) + (let [{:keys [libs] :as basis} (basis/current-basis) + current-libs (set (keys libs)) + lib-coords (reduce-kv #(if (contains? current-libs %2) %1 (assoc %1 %2 %3)) + {} lib-coords)] + (when-not (empty? lib-coords) + (let [procurer (dissoc basis [:basis-config :paths :deps :aliases :argmap :classpath :classpath-roots]) + tool-args {:existing libs, :add lib-coords, :procurer procurer} + {:keys [added] :as _res} (tool/invoke-tool {:tool-alias :deps, :fn 'clojure.tools.deps/resolve-added-libs, :args tool-args}) + ;_ (clojure.pprint/pprint _res) + paths (mapcat :paths (vals added)) + urls (->> paths (map jio/file) (map #(.toURL ^File %)))] + (run! add-loader-url urls) + (basis-impl/update-basis! update :libs merge added) + (let [ret (-> added keys sort vec)] + (when (seq ret) ret)))))) + +(defn add-lib + "Given a lib that is not yet on the repl classpath, make it available by + downloading the library if necessary and adding it to the classloader. + Libs already on the classpath are not updated. Requires a valid parent + DynamicClassLoader. + + lib - symbol identifying a library, for Maven: groupId/artifactId + coord - optional map of location information specific to the procurer, + or latest if not supplied + + Returns coll of libs loaded, including transitive (or nil if none). + + For info on libs, coords, and versions, see: + https://clojure.org/reference/deps_and_cli" + {:added "1.12"} + ([lib coord] + (add-libs {lib coord})) + ([lib] + (let [procurer (select-keys (basis/current-basis) [:mvn/repos :mvn/local-repo]) + coord (tool/invoke-tool {:tool-alias :deps + :fn 'clojure.tools.deps/find-latest-version + :args {:lib lib, :procurer procurer}})] + (if coord + (add-libs {lib coord}) + (throw (ex-info (str "No version found for lib " lib) {})))))) + +(defn sync-deps + "Calls add-libs with any libs present in deps.edn but not yet present on the classpath. + + :aliases - coll of alias keywords to use during the sync" + {:added "1.12"} + [& {:as opts}] + (let [{:keys [aliases]} opts + basis-config (:basis-config (basis/current-basis)) + new-basis-config (update basis-config :aliases (fnil into []) aliases) + new-basis (tool/invoke-tool {:tool-alias :deps, :fn 'clojure.tools.deps/create-basis, :args new-basis-config}) + new-libs (:libs new-basis)] + (add-libs new-libs))) From bde257d1f44d65d623c687481d86a102f9142006 Mon Sep 17 00:00:00 2001 From: Clojure Build Date: Fri, 14 Apr 2023 07:38:00 -0500 Subject: [PATCH 140/285] [maven-release-plugin] prepare release clojure-1.12.0-alpha2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2dd37faaad..5e1118a13b 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0-alpha2 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0-alpha2 From 16a17e9f9bbc26e996dc893941cef09410c39f41 Mon Sep 17 00:00:00 2001 From: Clojure Build Date: Fri, 14 Apr 2023 07:38:00 -0500 Subject: [PATCH 141/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5e1118a13b..2dd37faaad 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-alpha2 + 1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0-alpha2 + HEAD From 4090f405466ea90bbaf3addbe41f0a6acb164dbb Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 18 Apr 2023 09:22:23 -0500 Subject: [PATCH 142/285] Revert "CLJ-2521: hoist loop bodies in statement position" This reverts commit 8adf5bce1ecb45a940f6b4233aff075be5448a5b. --- src/jvm/clojure/lang/Compiler.java | 2 +- test/clojure/test_clojure/compilation.clj | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index b7d0dfff8c..758108e8bc 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -6342,7 +6342,7 @@ public Expr parse(C context, Object frm) { ISeq body = RT.next(RT.next(form)); if(context == C.EVAL - || (context != C.RETURN && isLoop)) + || (context == C.EXPRESSION && isLoop)) return analyze(context, RT.list(RT.list(FNONCE, PersistentVector.EMPTY, form))); ObjMethod method = (ObjMethod) METHOD.deref(); diff --git a/test/clojure/test_clojure/compilation.clj b/test/clojure/test_clojure/compilation.clj index 3aae891759..999d33f91b 100644 --- a/test/clojure/test_clojure/compilation.clj +++ b/test/clojure/test_clojure/compilation.clj @@ -443,7 +443,3 @@ (testing "CLJ-2580 Correctly calculate exit branches of case" (is (zero? (let [d (case nil :x nil 0)] d))) (is (nil? (let [d (case nil :x 0 nil)] d))))) - -(deftest CLJ-2521 - (testing "CLJ-2521 Can nest loop->try when in statement position" - (is (= "ret" ((fn [] (loop [] (try "" (catch Throwable _))) "ret")))))) From 1d704118d83d2550b050826b6fb505ab41a8ac7d Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 8 Jun 2023 14:18:13 -0500 Subject: [PATCH 143/285] Add workflows --- .github/workflows/release.yml | 19 +++++++++++++++++++ .github/workflows/snapshot.yml | 8 ++++++++ .github/workflows/test.yml | 23 +++++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/snapshot.yml create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..e2718bd3ef --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,19 @@ +name: Release on demand + +on: + workflow_dispatch: + inputs: + releaseVersion: + description: "Version to release" + required: true + snapshotVersion: + description: "Snapshot version after release" + required: true + +jobs: + call-release: + uses: clojure/build.ci/.github/workflows/release.yml@master + with: + releaseVersion: ${{ github.event.inputs.releaseVersion }} + snapshotVersion: ${{ github.event.inputs.snapshotVersion }} + secrets: inherit \ No newline at end of file diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml new file mode 100644 index 0000000000..24729578c1 --- /dev/null +++ b/.github/workflows/snapshot.yml @@ -0,0 +1,8 @@ +name: Snapshot on demand + +on: [workflow_dispatch] + +jobs: + call-snapshot: + uses: clojure/build.ci/.github/workflows/snapshot.yml@master + secrets: inherit diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000000..a6c3b6bf1a --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,23 @@ +name: Test + +on: [push] + +jobs: + test: + strategy: + matrix: + os: [ubuntu-latest] # macOS-latest, windows-latest] + java-version: ["8", "11", "17"] + distribution: ["temurin", "oracle", "corretto"] + profile: ["test-direct", "test-no-direct"] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - name: Set up Java + uses: actions/setup-java@v3 + with: + java-version: ${{ matrix.java-version }} + distribution: ${{ matrix.distribution }} + cache: 'maven' + - name: Build with Maven + run: mvn -ntp -B -P${{ matrix.profile }} clean test From 21150ff92afe61ac7b2c206d70870cc8e84b9801 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 8 Jun 2023 14:21:14 -0500 Subject: [PATCH 144/285] narrow test matrix JDK distributions --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a6c3b6bf1a..6d8bb247e3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: matrix: os: [ubuntu-latest] # macOS-latest, windows-latest] java-version: ["8", "11", "17"] - distribution: ["temurin", "oracle", "corretto"] + distribution: ["temurin", "corretto"] profile: ["test-direct", "test-no-direct"] runs-on: ${{ matrix.os }} steps: From c72f833d40e19717c88bafa54c9e76e60520f11d Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 9 May 2023 16:23:58 -0500 Subject: [PATCH 145/285] CLJ-2772 Fix regression in drop nthrest nthnext on n != positive integer --- src/clj/clojure/core.clj | 14 ++++-- src/jvm/clojure/lang/IDrop.java | 7 +-- src/jvm/clojure/lang/PersistentVector.java | 6 +-- test/clojure/test_clojure/sequences.clj | 50 +++++++++++++++++++++- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index caa1fb387e..688f5dd7fb 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -2942,7 +2942,11 @@ (rf result input)))))))) ([n coll] (if (instance? clojure.lang.IDrop coll) - (or (.drop ^clojure.lang.IDrop coll n) ()) + (or + (if (pos? n) + (.drop ^clojure.lang.IDrop coll (if (int? n) n (Math/ceil n))) + (seq coll)) + ()) (let [step (fn [n coll] (let [s (seq coll)] (if (and (pos? n) s) @@ -3170,7 +3174,9 @@ :static true} [coll n] (if (instance? clojure.lang.IDrop coll) - (.drop ^clojure.lang.IDrop coll n) + (if (pos? n) + (.drop ^clojure.lang.IDrop coll (if (int? n) n (Math/ceil n))) + (seq coll)) (loop [n n xs (seq coll)] (if (and xs (pos? n)) (recur (dec n) (next xs)) @@ -3182,7 +3188,9 @@ :static true} [coll n] (if (instance? clojure.lang.IDrop coll) - (or (.drop ^clojure.lang.IDrop coll n) ()) + (if (pos? n) + (or (.drop ^clojure.lang.IDrop coll (if (int? n) n (Math/ceil n))) ()) + coll) (loop [n n xs coll] (if-let [xs (and (pos? n) (seq xs))] (recur (dec n) (rest xs)) diff --git a/src/jvm/clojure/lang/IDrop.java b/src/jvm/clojure/lang/IDrop.java index 336c0a8270..fb9c9f746f 100644 --- a/src/jvm/clojure/lang/IDrop.java +++ b/src/jvm/clojure/lang/IDrop.java @@ -20,11 +20,8 @@ public interface IDrop{ * useful if the returned coll implements IDrop for subsequent use in a * partition-like scenario. * - * If n is <= 0, return this. - * If n drops to or past the end of the collection, return null. - * - * @param n Items to drop - * @return Collection that is Sequential, ISeq, and IReduceInit + * @param n Items to drop, must be > 0 + * @return Collection that is Sequential, ISeq, and IReduceInit, or null if past the end */ Sequential drop(int n); } diff --git a/src/jvm/clojure/lang/PersistentVector.java b/src/jvm/clojure/lang/PersistentVector.java index 973cb2a31a..a68e5c6a62 100644 --- a/src/jvm/clojure/lang/PersistentVector.java +++ b/src/jvm/clojure/lang/PersistentVector.java @@ -366,9 +366,7 @@ public Object kvreduce(IFn f, Object init){ } public Sequential drop(int n) { - if(n < 0) { - return this; - } else if(n < cnt) { + if(n < cnt) { int offset = n%32; return new ChunkedSeq(this, this.arrayFor(n), n-offset, offset); } else { @@ -617,7 +615,7 @@ public int count(){ ensureEditable(); return cnt; } - + Node ensureEditable(Node node){ if(node.edit == root.edit) return node; diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj index bc79c1f62e..0ce1122bf5 100644 --- a/test/clojure/test_clojure/sequences.clj +++ b/test/clojure/test_clojure/sequences.clj @@ -855,7 +855,9 @@ (take 0 [1 2 3 4 5]) () (take -1 [1 2 3 4 5]) () - (take -2 [1 2 3 4 5]) () )) + (take -2 [1 2 3 4 5]) () + + (take 1/4 [1 2 3 4 5]) '(1) )) (deftest test-drop @@ -867,8 +869,52 @@ (drop 0 [1 2 3 4 5]) '(1 2 3 4 5) (drop -1 [1 2 3 4 5]) '(1 2 3 4 5) - (drop -2 [1 2 3 4 5]) '(1 2 3 4 5) )) + (drop -2 [1 2 3 4 5]) '(1 2 3 4 5) + + (drop 1/4 [1 2 3 4 5]) '(2 3 4 5) ) + + (are [coll] (= (drop 4 coll) (drop -2 (drop 4 coll))) + [0 1 2 3 4 5] + (seq [0 1 2 3 4 5]) + (range 6) + (repeat 6 :x)) + ) + +(deftest test-nthrest + (are [x y] (= x y) + (nthrest [1 2 3 4 5] 1) '(2 3 4 5) + (nthrest [1 2 3 4 5] 3) '(4 5) + (nthrest [1 2 3 4 5] 5) () + (nthrest [1 2 3 4 5] 9) () + + (nthrest [1 2 3 4 5] 0) '(1 2 3 4 5) + (nthrest [1 2 3 4 5] -1) '(1 2 3 4 5) + (nthrest [1 2 3 4 5] -2) '(1 2 3 4 5) + + (nthrest [1 2 3 4 5] 1/4) '(2 3 4 5) + (nthrest [1 2 3 4 5] 1.2) '(3 4 5) ) + + ;; (nthrest coll 0) should return coll + (are [coll] (let [r (nthrest coll 0)] (and (= coll r) (= (class coll) (class r)))) + [1 2 3] + (seq [1 2 3]) + (range 10) + (repeat 10 :x) + (seq "abc") )) + +(deftest test-nthnext + (are [x y] (= x y) + (nthnext [1 2 3 4 5] 1) '(2 3 4 5) + (nthnext [1 2 3 4 5] 3) '(4 5) + (nthnext [1 2 3 4 5] 5) nil + (nthnext [1 2 3 4 5] 9) nil + + (nthnext [1 2 3 4 5] 0) '(1 2 3 4 5) + (nthnext [1 2 3 4 5] -1) '(1 2 3 4 5) + (nthnext [1 2 3 4 5] -2) '(1 2 3 4 5) + (nthnext [1 2 3 4 5] 1/4) '(2 3 4 5) + (nthnext [1 2 3 4 5] 1.2) '(3 4 5) )) (deftest test-take-nth (are [x y] (= x y) From 307eb04df551f9bdf7d155799ad922f8d9a531d1 Mon Sep 17 00:00:00 2001 From: Frank Yin Date: Mon, 5 Jun 2023 11:53:28 -0500 Subject: [PATCH 146/285] CLJ-2686: Fixes ConcurrentModificationException by iterating through Java properties in a thread-safe manner --- src/clj/clojure/core/server.clj | 17 ++++++++++------- test/clojure/test_clojure/server.clj | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/clj/clojure/core/server.clj b/src/clj/clojure/core/server.clj index 3cda4d1f74..05a5a20999 100644 --- a/src/clj/clojure/core/server.clj +++ b/src/clj/clojure/core/server.clj @@ -16,6 +16,7 @@ [clojure.lang LineNumberingPushbackReader] [java.net InetAddress Socket ServerSocket SocketException] [java.io Reader Writer PrintWriter BufferedWriter BufferedReader InputStreamReader OutputStreamWriter] + [java.util Properties] [java.util.concurrent.locks ReentrantLock])) (set! *warn-on-reflection* true) @@ -145,14 +146,16 @@ (defn- parse-props "Parse clojure.server.* from properties to produce a map of server configs." - [props] + [^Properties props] (reduce - (fn [acc [^String k ^String v]] - (let [[k1 k2 k3] (str/split k #"\.")] - (if (and (= k1 "clojure") (= k2 "server")) - (conj acc (merge {:name k3} (edn/read-string v))) - acc))) - [] props)) + (fn [acc ^String k] + (let [[k1 k2 k3] (str/split k #"\.")] + (if (and (= k1 "clojure") (= k2 "server")) + (let [v (get props k)] + (conj acc (merge {:name k3} (edn/read-string v)))) + acc))) + [] + (.stringPropertyNames props))) (defn start-servers "Start all servers specified in the system properties." diff --git a/test/clojure/test_clojure/server.clj b/test/clojure/test_clojure/server.clj index 1d24d0b2dd..4d4f20a480 100644 --- a/test/clojure/test_clojure/server.clj +++ b/test/clojure/test_clojure/server.clj @@ -9,6 +9,7 @@ ; Author: Alex Miller (ns clojure.test-clojure.server + (:import java.util.Random) (:require [clojure.test :refer :all]) (:require [clojure.core.server :as s])) @@ -21,9 +22,26 @@ (is (= (ex-data e) opts)) (is (= msg (.getMessage e)))))) +(defn create-random-thread + [] + (Thread. + (fn [] + (let [random (new Random)] + (while (not (.isInterrupted (Thread/currentThread))) + (System/setProperty (Integer/toString (.nextInt random)) (Integer/toString (.nextInt random)))))))) + (deftest test-validate-opts (check-invalid-opts {} "Missing required socket server property :name") (check-invalid-opts {:name "a" :accept 'clojure.core/+} "Missing required socket server property :port") (doseq [port [-1 "5" 999999]] (check-invalid-opts {:name "a" :port port :accept 'clojure.core/+} (str "Invalid socket server port: " port))) (check-invalid-opts {:name "a" :port 5555} "Missing required socket server property :accept")) + +(deftest test-parse-props + (let [thread (create-random-thread)] + (.start thread) + (Thread/sleep 1000) + (try + (is (>= (count + (#'s/parse-props (System/getProperties))) 0)) + (finally (.interrupt thread))))) From 61778b8761d4a60e48ff6ebcd238002081715ac2 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 1 Feb 2022 20:20:03 -0600 Subject: [PATCH 147/285] CLJ-2694 Fix ratio cases due to use of Long/MIN_VALUE to defer to bigint impl --- src/jvm/clojure/lang/Numbers.java | 4 ++++ test/clojure/test_clojure/numbers.clj | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/Numbers.java b/src/jvm/clojure/lang/Numbers.java index 82d8e6914c..661c051d36 100644 --- a/src/jvm/clojure/lang/Numbers.java +++ b/src/jvm/clojure/lang/Numbers.java @@ -530,6 +530,10 @@ static long gcd(long u, long v){ public Number divide(Number x, Number y){ long n = x.longValue(); long val = y.longValue(); + + if(n == Long.MIN_VALUE || val == Long.MIN_VALUE) + return BIGINT_OPS.divide(x, y); + long gcd = gcd(n, val); if(gcd == 0) return num(0); diff --git a/test/clojure/test_clojure/numbers.clj b/test/clojure/test_clojure/numbers.clj index bf822cc947..be4f7a0a60 100644 --- a/test/clojure/test_clojure/numbers.clj +++ b/test/clojure/test_clojure/numbers.clj @@ -598,7 +598,17 @@ Math/pow overflows to Infinity." (is (== (denominator 1/2) 2)) (is (== (numerator 1/2) 1)) (is (= (bigint (/ 100000000000000000000 3)) 33333333333333333333)) - (is (= (long 10000000000000000000/3) 3333333333333333333))) + (is (= (long 10000000000000000000/3) 3333333333333333333)) + + ;; special cases around Long/MIN_VALUE + (is (= (/ 1 Long/MIN_VALUE) -1/9223372036854775808)) + (is (true? (< (/ 1 Long/MIN_VALUE) 0))) + (is (true? (< (* 1 (/ 1 Long/MIN_VALUE)) 0))) + (is (= (abs (/ 1 Long/MIN_VALUE)) 1/9223372036854775808)) + (is (false? (< (abs (/ 1 Long/MIN_VALUE)) 0))) + (is (false? (< (* 1 (abs (/ 1 Long/MIN_VALUE))) 0))) + (is (= (/ Long/MIN_VALUE -3) 9223372036854775808/3)) + (is (false? (< (/ Long/MIN_VALUE -3) 0)))) (deftest test-arbitrary-precision-subtract (are [x y] (= x y) From 595e6dd1674304ace56c14b19bc816410bf6687c Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 11 Apr 2023 14:42:44 -0500 Subject: [PATCH 148/285] CLJ-2741 Revert change in metadata on string sequence drop --- src/jvm/clojure/lang/StringSeq.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/StringSeq.java b/src/jvm/clojure/lang/StringSeq.java index 3163380898..dbad70810e 100644 --- a/src/jvm/clojure/lang/StringSeq.java +++ b/src/jvm/clojure/lang/StringSeq.java @@ -61,7 +61,7 @@ public int count(){ public Sequential drop(int n) { int ii = i + n; if (ii < s.length()) { - return new StringSeq(_meta, s, ii); + return new StringSeq(null, s, ii); } else { return null; } From e10105134e30917c369d92476f95dbb58906ee29 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 11 May 2023 16:30:29 -0500 Subject: [PATCH 149/285] CLJ-2773 Fix param names in c.j.process/[to,from]-file to match docstring --- src/clj/clojure/java/process.clj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/clj/clojure/java/process.clj b/src/clj/clojure/java/process.clj index 881b69413b..b8d2e6cba4 100644 --- a/src/clj/clojure/java/process.clj +++ b/src/clj/clojure/java/process.clj @@ -41,18 +41,18 @@ "Coerce f to a file per clojure.java.io/file and return a ProcessBuilder.Redirect writing to the file. Set ':append' in opts to append. This can be passed to 'start' in :out or :err." {:added "1.12"} - ^ProcessBuilder$Redirect [file & {:keys [append] :as opts}] - (let [f (jio/file file)] + ^ProcessBuilder$Redirect [f & {:keys [append] :as opts}] + (let [fo (jio/file f)] (if append - (ProcessBuilder$Redirect/appendTo f) - (ProcessBuilder$Redirect/to f)))) + (ProcessBuilder$Redirect/appendTo fo) + (ProcessBuilder$Redirect/to fo)))) (defn from-file "Coerce f to a file per clojure.java.io/file and return a ProcessBuilder.Redirect reading from the file. This can be passed to 'start' in :in." {:added "1.12"} - ^ProcessBuilder$Redirect [file] - (ProcessBuilder$Redirect/from (jio/file file))) + ^ProcessBuilder$Redirect [f] + (ProcessBuilder$Redirect/from (jio/file f))) (defn start "Starts an external command as args and optional leading opts map: From 3ba6473ca3f44015fa425f6b1c135dcec583dadc Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 17 May 2023 11:20:49 -0500 Subject: [PATCH 150/285] CLJ-2776 Fix redirect err stream to out stream in c.j.process --- src/clj/clojure/java/process.clj | 4 ++-- test/clojure/test_clojure/java/process.clj | 25 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 test/clojure/test_clojure/java/process.clj diff --git a/src/clj/clojure/java/process.clj b/src/clj/clojure/java/process.clj index b8d2e6cba4..1b375c176f 100644 --- a/src/clj/clojure/java/process.clj +++ b/src/clj/clojure/java/process.clj @@ -86,7 +86,7 @@ (when in (.redirectInput pb ^ProcessBuilder$Redirect (to-redirect in))) (when out (.redirectOutput pb ^ProcessBuilder$Redirect (to-redirect out))) (cond - (= err :stdout) (.redirectErrorStream pb) + (= err :stdout) (.redirectErrorStream pb true) err (.redirectError pb ^ProcessBuilder$Redirect (to-redirect err))) (when env (let [pb-env (.environment pb)] @@ -134,7 +134,7 @@ (let [[opts command] (if (map? (first opts+args)) [(first opts+args) (rest opts+args)] [{} opts+args]) - opts (merge opts {:err :inherit})] + opts (merge {:err :inherit} opts)] (let [state (apply start opts command) out-promise (promise) capture-fn #(deliver out-promise (capture (:out state)))] diff --git a/test/clojure/test_clojure/java/process.clj b/test/clojure/test_clojure/java/process.clj new file mode 100644 index 0000000000..170e801cd1 --- /dev/null +++ b/test/clojure/test_clojure/java/process.clj @@ -0,0 +1,25 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. + +(ns clojure.test-clojure.java.process + (:require + [clojure.test :refer :all] + [clojure.java.process :as p] + [clojure.string :as str])) + +(deftest test-stderr-redirect + ;; capture to stdout and return string + (is (not (str/blank? (p/exec "bash" "-c" "ls")))) + + ;; print to stderr, capture nil + (is (nil? (p/exec "bash" "-c" "ls >&2"))) + + ;; redirect, then capture to string + (is (not (str/blank? (p/exec {:err :stdout} "bash" "-c" "ls >&2"))))) + + From 23be02537c6413064d4e55f3c8842846d627938b Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 17 May 2023 11:31:00 -0500 Subject: [PATCH 151/285] CLJ-2778 Fix docstring options for c.j.process/capture --- src/clj/clojure/java/process.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clj/clojure/java/process.clj b/src/clj/clojure/java/process.clj index 1b375c176f..3b8f41f11e 100644 --- a/src/clj/clojure/java/process.clj +++ b/src/clj/clojure/java/process.clj @@ -116,7 +116,7 @@ (defn capture "Read from input-stream until EOF and return a String (or nil if 0 length). - Takes same opts as clojure.java.io/copy - :buffer and :encoding" + Takes same opts as clojure.java.io/copy - :buffer-size and :encoding" {:added "1.12"} [input-stream & opts] (let [writer (StringWriter.)] From ef3cd497dc881021a80cad3a9d44925dcb3a0f4e Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 19 May 2023 12:50:05 -0500 Subject: [PATCH 152/285] CLJ-2779 c.j.process/start - remove unnecessary nil arg handling --- src/clj/clojure/java/process.clj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/clj/clojure/java/process.clj b/src/clj/clojure/java/process.clj index 3b8f41f11e..8dce0a6a63 100644 --- a/src/clj/clojure/java/process.clj +++ b/src/clj/clojure/java/process.clj @@ -82,12 +82,12 @@ :discard (ProcessBuilder$Redirect/to @null-file) ;; in Java 9+, just use ProcessBuilder$Redirect/DISCARD x))] - (.directory pb (jio/file (or dir "."))) - (when in (.redirectInput pb ^ProcessBuilder$Redirect (to-redirect in))) - (when out (.redirectOutput pb ^ProcessBuilder$Redirect (to-redirect out))) - (cond + (.directory pb (jio/file dir)) + (.redirectInput pb ^ProcessBuilder$Redirect (to-redirect in)) + (.redirectOutput pb ^ProcessBuilder$Redirect (to-redirect out)) + (if (= err :stdout) (.redirectErrorStream pb true) - err (.redirectError pb ^ProcessBuilder$Redirect (to-redirect err))) + (.redirectError pb ^ProcessBuilder$Redirect (to-redirect err))) (when env (let [pb-env (.environment pb)] (run! (fn [[k v]] (.put pb-env k v)) env))) From 5fd97af9a4370bbf2075a53d9c3bf83decf289ce Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 12 Jun 2023 20:46:53 -0500 Subject: [PATCH 153/285] update test workflow to support workflow dispatch, not fail fast, and to add oracle distribution --- .github/workflows/test.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6d8bb247e3..6bb91f2a39 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,15 +1,21 @@ name: Test -on: [push] +on: + push: + workflow_dispatch: jobs: test: strategy: + fail-fast: false matrix: os: [ubuntu-latest] # macOS-latest, windows-latest] java-version: ["8", "11", "17"] distribution: ["temurin", "corretto"] profile: ["test-direct", "test-no-direct"] + include: + - distribution: "oracle" + java-version: "17" runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 From 1b3a5065b7f533d4fd7109686fcc4489163b916c Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 12 Jun 2023 21:14:36 -0500 Subject: [PATCH 154/285] test workflow - remove extra distribution --- .github/workflows/test.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6bb91f2a39..0197cfdd91 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,9 +13,6 @@ jobs: java-version: ["8", "11", "17"] distribution: ["temurin", "corretto"] profile: ["test-direct", "test-no-direct"] - include: - - distribution: "oracle" - java-version: "17" runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 From b81660ee9cc50d830c33f943dbda8606ebac3806 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 19 May 2023 15:48:27 -0500 Subject: [PATCH 155/285] CLJ-2767 Fix initialization and setting of *repl* --- src/clj/clojure/core.clj | 2 +- src/clj/clojure/main.clj | 38 ++++++++++++------------- test/clojure/test_clojure/repl/deps.clj | 30 +++++++++++++++++++ 3 files changed, 50 insertions(+), 20 deletions(-) create mode 100644 test/clojure/test_clojure/repl/deps.clj diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 688f5dd7fb..b8d9ff9f54 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -6351,7 +6351,7 @@ fails, attempts to require sym's namespace and retries." (def ^:dynamic ^{:doc "Bound to true in a repl thread" :added "1.12"} - *repl*) + *repl* false) (defn trampoline "trampoline can be used to convert algorithms requiring mutual diff --git a/src/clj/clojure/main.clj b/src/clj/clojure/main.clj index bb72673107..89baed7f81 100644 --- a/src/clj/clojure/main.clj +++ b/src/clj/clojure/main.clj @@ -93,7 +93,6 @@ *unchecked-math* *unchecked-math* *assert* *assert* clojure.spec.alpha/*explain-out* clojure.spec.alpha/*explain-out* - *repl* true *1 nil *2 nil *3 nil @@ -447,24 +446,25 @@ by default when a new command-line REPL is started."} repl-requires (caught e) (set! *e e))))] (with-bindings - (try - (init) - (catch Throwable e - (caught e) - (set! *e e))) - (prompt) - (flush) - (loop [] - (when-not - (try (identical? (read-eval-print) request-exit) - (catch Throwable e - (caught e) - (set! *e e) - nil)) - (when (need-prompt) - (prompt) - (flush)) - (recur)))))) + (binding [*repl* true] + (try + (init) + (catch Throwable e + (caught e) + (set! *e e))) + (prompt) + (flush) + (loop [] + (when-not + (try (identical? (read-eval-print) request-exit) + (catch Throwable e + (caught e) + (set! *e e) + nil)) + (when (need-prompt) + (prompt) + (flush)) + (recur))))))) (defn load-script "Loads Clojure source from a file or resource given its path. Paths diff --git a/test/clojure/test_clojure/repl/deps.clj b/test/clojure/test_clojure/repl/deps.clj new file mode 100644 index 0000000000..010d041fea --- /dev/null +++ b/test/clojure/test_clojure/repl/deps.clj @@ -0,0 +1,30 @@ +(ns clojure.test-clojure.repl.deps + (:use clojure.test) + (:require [clojure.string :as str] + [clojure.repl.deps :as deps] + [clojure.main :as main])) + +(defmacro with-dynamic-loader + "Ensure or install a DynamicClassLoader as the current thread's + context classloader and execute the body." + [& body] + `(let [t# (Thread/currentThread) + cl# (.getContextClassLoader t#)] + (if (instance? ~'clojure.lang.DynamicClassLoader cl#) + (do ~@body) + (try + (.setContextClassLoader t# (clojure.lang.DynamicClassLoader. cl#)) + ~@body + (finally + (.setContextClassLoader t# cl#)))))) + +(deftest test-no-add-libs-outside-repl + (try + (deps/add-lib 'org.clojure/data.json {:mvn/version "2.4.0"}) + (is false "add-libs outside repl should throw") + (catch Throwable t (str/includes? (ex-message t) "add-libs"))) + + (with-dynamic-loader + (binding [*repl* true] + (is (some #{'org.clojure/data.json} (deps/add-lib 'org.clojure/data.json {:mvn/version "2.4.0"}))))) + ) From 5d81bb40dc3c48340c461b0d85c7363831140e24 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 15 Jun 2023 13:06:17 -0500 Subject: [PATCH 156/285] CLJ-2769 Pass invoke-tool args over stdin rather than in command --- src/clj/clojure/java/process.clj | 43 +++++++++++++++++++++++--- src/clj/clojure/tools/deps/interop.clj | 29 ++++++++++------- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/clj/clojure/java/process.clj b/src/clj/clojure/java/process.clj index 8dce0a6a63..74f87af7b6 100644 --- a/src/clj/clojure/java/process.clj +++ b/src/clj/clojure/java/process.clj @@ -25,7 +25,8 @@ [java.io StringWriter File] [java.lang ProcessBuilder ProcessBuilder$Redirect Process] [java.util List] - [clojure.lang IDeref IBlockingDeref])) + [clojure.lang IDeref IBlockingDeref] + [java.util.concurrent Executors ExecutorService ThreadFactory])) (set! *warn-on-reflection* true) @@ -125,6 +126,40 @@ (when-not (zero? (.length s)) s)))) +;; A thread factory for daemon threads +(defonce ^:private io-thread-factory + (let [counter (atom 0)] + (reify ThreadFactory + (newThread [_ r] + (doto (Thread. r) + (.setName (str "Clojure Process IO " (swap! counter inc))) + (.setDaemon true)))))) + +;; An ExecutorService for cached, daemon threads +(defonce ^:private io-executor + (Executors/newCachedThreadPool ^ThreadFactory io-thread-factory)) + +(defn io-task + {:skip-wiki true} + [^Runnable f] + (let [f (bound-fn* f) + fut (.submit ^ExecutorService io-executor ^Callable f)] + (reify + clojure.lang.IDeref + (deref [_] (#'clojure.core/deref-future fut)) + clojure.lang.IBlockingDeref + (deref + [_ timeout-ms timeout-val] + (#'clojure.core/deref-future fut timeout-ms timeout-val)) + clojure.lang.IPending + (isRealized [_] (.isDone fut)) + java.util.concurrent.Future + (get [_] (.get fut)) + (get [_ timeout unit] (.get fut timeout unit)) + (isCancelled [_] (.isCancelled fut)) + (isDone [_] (.isDone fut)) + (cancel [_ interrupt?] (.cancel fut interrupt?))))) + (defn exec "Execute a command and on successful exit, return the captured output, else throw RuntimeException. Args are the same as 'start' and options @@ -136,11 +171,9 @@ [{} opts+args]) opts (merge {:err :inherit} opts)] (let [state (apply start opts command) - out-promise (promise) - capture-fn #(deliver out-promise (capture (:out state)))] - (doto (Thread. ^Runnable capture-fn) (.setDaemon true) (.start)) + captured (io-task #(capture (:out state)))] (if (ok? state) - @out-promise + @captured (throw (RuntimeException. (str "Process failed with exit=" (.exitValue ^Process (:process state))))))))) (comment diff --git a/src/clj/clojure/tools/deps/interop.clj b/src/clj/clojure/tools/deps/interop.clj index 54449b731a..3d0bdf1d7a 100644 --- a/src/clj/clojure/tools/deps/interop.clj +++ b/src/clj/clojure/tools/deps/interop.clj @@ -9,7 +9,8 @@ "Functions for invoking Java processes and invoking tools via the Clojure CLI." (:require [clojure.java.process :as proc] - [clojure.edn :as edn])) + [clojure.edn :as edn] + [clojure.java.io :as jio])) (defn ^:dynamic invoke-tool "Invoke tool using Clojure CLI. Args (one of :tool-alias or :tool-name, and :fn @@ -28,18 +29,24 @@ :as opts}] (when-not (or tool-name tool-alias) (throw (ex-info "Either :tool-alias or :tool-name must be provided" (or opts {})))) (when-not (symbol? fn) (throw (ex-info (str "fn should be a symbol " fn) (or opts {})))) - (let [args (assoc args :clojure.exec/invoke :fn) + (let [args (conj [fn] (assoc args :clojure.exec/invoke :fn)) _ (when (:debug opts) (println "args" args)) - command-strs [command (str "-T" (or tool-alias tool-name)) (pr-str fn) (pr-str args)] + command-strs [command (str "-T" (or tool-alias tool-name)) "-"] _ (when (:debug opts) (apply println "Invoking: " command-strs)) - envelope (edn/read-string (apply proc/exec command-strs))] - (if preserve-envelope - envelope - (let [{:keys [tag val]} envelope - parsed-val (edn/read-string val)] - (if (= :ret tag) - parsed-val - (throw (ex-info (:cause parsed-val) (or parsed-val {})))))))) + {:keys [in out]} (apply proc/start command-strs)] + (proc/io-task + #(with-open [w (jio/writer in)] + (doseq [a args] + (.write w (pr-str a)) + (.write w " ")))) + (let [envelope (edn/read-string (proc/capture out))] + (if preserve-envelope + envelope + (let [{:keys [tag val]} envelope + parsed-val (edn/read-string val)] + (if (= :ret tag) + parsed-val + (throw (ex-info (:cause parsed-val) (or parsed-val {}))))))))) (comment ;; regular invocation, should return {:hi :there} From 1e317674fce4c60a2fba0b7147bc7fa3240a3fe6 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 28 Jun 2023 14:09:33 -0500 Subject: [PATCH 157/285] Test workflow - add Clojure CLI --- .github/workflows/test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0197cfdd91..12e4d74ef3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,5 +22,9 @@ jobs: java-version: ${{ matrix.java-version }} distribution: ${{ matrix.distribution }} cache: 'maven' + - name: Set up Clojure CLI + uses: DeLaGuardo/setup-clojure@11.0 + with: + cli: latest - name: Build with Maven run: mvn -ntp -B -P${{ matrix.profile }} clean test From a0c75edfd13bf274309b500e5179cc4af70ddc09 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 28 Jun 2023 15:55:42 -0500 Subject: [PATCH 158/285] Revert "Test workflow - add Clojure CLI" This reverts commit 1e317674fce4c60a2fba0b7147bc7fa3240a3fe6. --- .github/workflows/test.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 12e4d74ef3..0197cfdd91 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,9 +22,5 @@ jobs: java-version: ${{ matrix.java-version }} distribution: ${{ matrix.distribution }} cache: 'maven' - - name: Set up Clojure CLI - uses: DeLaGuardo/setup-clojure@11.0 - with: - cli: latest - name: Build with Maven run: mvn -ntp -B -P${{ matrix.profile }} clean test From 451428121695564de8390053a04a500c068cd668 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 28 Jun 2023 15:56:22 -0500 Subject: [PATCH 159/285] Remove add-lib test --- test/clojure/test_clojure/repl/deps.clj | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/clojure/test_clojure/repl/deps.clj b/test/clojure/test_clojure/repl/deps.clj index 010d041fea..a2a69078d1 100644 --- a/test/clojure/test_clojure/repl/deps.clj +++ b/test/clojure/test_clojure/repl/deps.clj @@ -18,13 +18,13 @@ (finally (.setContextClassLoader t# cl#)))))) -(deftest test-no-add-libs-outside-repl - (try - (deps/add-lib 'org.clojure/data.json {:mvn/version "2.4.0"}) - (is false "add-libs outside repl should throw") - (catch Throwable t (str/includes? (ex-message t) "add-libs"))) - - (with-dynamic-loader - (binding [*repl* true] - (is (some #{'org.clojure/data.json} (deps/add-lib 'org.clojure/data.json {:mvn/version "2.4.0"}))))) - ) +;(deftest test-no-add-libs-outside-repl +; (try +; (deps/add-lib 'org.clojure/data.json {:mvn/version "2.4.0"}) +; (is false "add-libs outside repl should throw") +; (catch Throwable t (str/includes? (ex-message t) "add-libs"))) +; +; (with-dynamic-loader +; (binding [*repl* true] +; (is (some #{'org.clojure/data.json} (deps/add-lib 'org.clojure/data.json {:mvn/version "2.4.0"}))))) +; ) From 155511362a9fed75b6f18058c1bbc455ab81eb47 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 28 Jun 2023 16:55:25 -0500 Subject: [PATCH 160/285] Fix bad character in Javadoc --- src/jvm/clojure/lang/IDrop.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/IDrop.java b/src/jvm/clojure/lang/IDrop.java index fb9c9f746f..153ab0858f 100644 --- a/src/jvm/clojure/lang/IDrop.java +++ b/src/jvm/clojure/lang/IDrop.java @@ -20,7 +20,7 @@ public interface IDrop{ * useful if the returned coll implements IDrop for subsequent use in a * partition-like scenario. * - * @param n Items to drop, must be > 0 + * @param n Items to drop, must be > 0 * @return Collection that is Sequential, ISeq, and IReduceInit, or null if past the end */ Sequential drop(int n); From 5bc453ec87116e2732a3dd31f05ba519563a2bfc Mon Sep 17 00:00:00 2001 From: clojure-build Date: Wed, 28 Jun 2023 22:03:20 +0000 Subject: [PATCH 161/285] [maven-release-plugin] prepare release clojure-1.12.0-alpha4 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2dd37faaad..f91f362548 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0-alpha4 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0-alpha4 From 501348deb1e49736f3c49f2c177bcff947fe3a17 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Wed, 28 Jun 2023 22:03:20 +0000 Subject: [PATCH 162/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f91f362548..2dd37faaad 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-alpha4 + 1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0-alpha4 + HEAD From 2a058814e5fa3e8fb630ae507c3fa7dc865138c6 Mon Sep 17 00:00:00 2001 From: JarrodCTaylor Date: Mon, 31 Jul 2023 16:15:44 -0500 Subject: [PATCH 163/285] Add github action to build api docs --- .github/workflows/doc-build.yml | 72 +++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 .github/workflows/doc-build.yml diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml new file mode 100644 index 0000000000..819cba1268 --- /dev/null +++ b/.github/workflows/doc-build.yml @@ -0,0 +1,72 @@ +name: Build API Docs + +on: + workflow_dispatch: + inputs: + commit: + description: 'Commit changes to gh-pages branch' + type: boolean + required: true + default: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + + - name: Set up Java + uses: actions/setup-java@v3 + with: + java-version: 8 + distribution: 'temurin' + + - name: Set up Clojure + uses: DeLaGuardo/setup-clojure@11.0 + with: + cli: 'latest' + + - name: Cache clojure dependencies + uses: actions/cache@v3 + with: + path: | + ~/.m2/repository + ~/.gitlibs + key: cljdeps-${{ hashFiles('deps.edn') }} + restore-keys: cljdeps- + + - name: Clone clojure api doc repo + uses: actions/checkout@v3 + with: + repository: clojure/clojure-api-doc + path: clojure-api-doc + fetch-depth: 0 + + - name: Clone clojure source code repo into clojure-api-doc + uses: actions/checkout@v3 + with: + path: clojure-api-doc/repo + fetch-depth: 0 + + - name: Clone clojure gh-pages branch into clojure-api-doc + uses: actions/checkout@v3 + with: + repository: clojure/clojure + path: clojure-api-doc/repo-docs + ref: 'gh-pages' + fetch-depth: 0 + + - name: Install markdown + run: sudo apt install markdown + + - name: Call clojure-api-doc build.sh + run: bash ${GITHUB_WORKSPACE}/clojure-api-doc/build.sh + + - name: Commit + if: ${{inputs.commit}} + run: | + git config --global user.name clojure-build + git config --global user.email "clojure-build@users.noreply.github.com" + cd clojure-api-doc/repo-docs + git add -u -v + git commit -m "Autodoc commit" + git push origin gh-pages From 6975553804b0f8da9e196e6fb97838ea4e153564 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 29 Aug 2023 17:18:30 -0500 Subject: [PATCH 164/285] update links in readme - fix feedback and license links --- readme.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.txt b/readme.txt index 815cf9126d..f91653f8b5 100644 --- a/readme.txt +++ b/readme.txt @@ -1,14 +1,14 @@ * Clojure * Copyright (c) Rich Hickey. All rights reserved. * The use and distribution terms for this software are covered by the - * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) + * Eclipse Public License 1.0 (https://opensource.org/license/epl-1-0/) * which can be found in the file epl-v10.html at the root of this distribution. * By using this software in any fashion, you are agreeing to be bound by * the terms of this license. * You must not remove this notice, or any other, from this software. Docs: https://clojure.org -Feedback: http://groups.google.com/group/clojure +Feedback: https://ask.clojure.org Getting Started: https://clojure.org/guides/getting_started To build and run locally with Ant: @@ -76,7 +76,7 @@ under the Apache License: Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION From 496f60ab6b90a535afef562fed4b9af753bc8e15 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 20 Oct 2023 15:51:45 -0500 Subject: [PATCH 165/285] CLJ-2804 - to avoid i/o blocking under synchronized, replace with ReentrantLock in LazySeq and Delay Signed-off-by: Alex Miller --- src/jvm/clojure/lang/Delay.java | 64 ++++++++++-------- src/jvm/clojure/lang/LazySeq.java | 104 +++++++++++++++++++++++------- 2 files changed, 115 insertions(+), 53 deletions(-) diff --git a/src/jvm/clojure/lang/Delay.java b/src/jvm/clojure/lang/Delay.java index ffd418962d..f0aa855d20 100644 --- a/src/jvm/clojure/lang/Delay.java +++ b/src/jvm/clojure/lang/Delay.java @@ -12,15 +12,20 @@ package clojure.lang; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + public class Delay implements IDeref, IPending{ -volatile Object val; -volatile Throwable exception; -volatile IFn fn; - -public Delay(IFn fn){ - this.fn = fn; - this.val = null; - this.exception = null; +Object val; +Throwable exception; +IFn fn; +volatile Lock lock; + +public Delay(IFn f){ + fn = f; + val = null; + exception = null; + lock = new ReentrantLock(); } static public Object force(Object x) { @@ -29,32 +34,35 @@ static public Object force(Object x) { : x; } -public Object deref() { - if(fn != null) - { - synchronized(this) - { - //double check - if(fn!=null) - { - try - { - val = fn.invoke(); - } - catch(Throwable t) - { - exception = t; - } - fn = null; - } - } +private void realize() { + Lock l = lock; + if(l != null) { + l.lock(); + try { + if(fn!=null) { + try { + val = fn.invoke(); + } catch (Throwable t) { + exception = t; + } + fn = null; + lock = null; + } + } finally { + l.unlock(); } + } +} + +public Object deref() { + if(lock != null) + realize(); if(exception != null) throw Util.sneakyThrow(exception); return val; } public boolean isRealized(){ - return fn == null; + return lock == null; } } diff --git a/src/jvm/clojure/lang/LazySeq.java b/src/jvm/clojure/lang/LazySeq.java index f9f9bfb24e..5c243c1ebb 100644 --- a/src/jvm/clojure/lang/LazySeq.java +++ b/src/jvm/clojure/lang/LazySeq.java @@ -12,24 +12,30 @@ package clojure.lang; +import java.io.IOException; +import java.io.ObjectInputStream; import java.util.*; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; public final class LazySeq extends Obj implements ISeq, Sequential, List, IPending, IHashEq{ -private static final long serialVersionUID = 7700080124382322592L; +private static final long serialVersionUID = -7345643944998411680L; private IFn fn; private Object sv; private ISeq s; +private Lock lock; -public LazySeq(IFn fn){ - this.fn = fn; +public LazySeq(IFn f){ + fn = f; + lock = new ReentrantLock(); } -private LazySeq(IPersistentMap meta, ISeq s){ +private LazySeq(IPersistentMap meta, ISeq seq){ super(meta); - this.fn = null; - this.s = s; + fn = null; + s = seq; } public Obj withMeta(IPersistentMap meta){ @@ -38,29 +44,66 @@ public Obj withMeta(IPersistentMap meta){ return new LazySeq(meta, seq()); } -final synchronized Object sval(){ - if(fn != null) - { - sv = fn.invoke(); - fn = null; +// MUST be locked when called! +final private void force() { + if (fn != null) { + sv = fn.invoke(); + fn = null; + } +} + +final private void lockAndForce() { + Lock l = lock; + if(l != null) { + l.lock(); + try { + force(); + } finally { + l.unlock(); } + } +} + +final private Object sval() { + if(fn != null) + lockAndForce(); if(sv != null) return sv; return s; } -final synchronized public ISeq seq(){ - sval(); - if(sv != null) - { - Object ls = sv; - sv = null; - while(ls instanceof LazySeq) - { - ls = ((LazySeq)ls).sval(); - } - s = RT.seq(ls); +final private Object unwrap(Object ls){ + while(ls instanceof LazySeq) { + ls = ((LazySeq) ls).sval(); + } + return ls; +} + +final private void realize() { + Lock l = lock; + if(l != null) { + l.lock(); + try { + //must re-examine under lock + if(lock != null) { + force(); + Object ls = sv; + sv = null; + if(ls instanceof LazySeq) + ls = unwrap(ls); + s = RT.seq(ls); + lock = null; + } + } + finally { + l.unlock(); } + } +} + +public final ISeq seq(){ + if(lock != null) + realize(); return s; } @@ -243,8 +286,19 @@ public boolean addAll(int index, Collection c){ throw new UnsupportedOperationException(); } - -synchronized public boolean isRealized(){ - return fn == null; +public boolean isRealized(){ + if(lock != null) { + Lock l = lock; + if(l != null) { + l.lock(); + try { + return lock == null; + } finally { + l.unlock(); + } + } + } + return true; } } + From c6122ebe26ba25a33f44190dc8994614d4cf13f4 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 20 Oct 2023 16:23:09 -0500 Subject: [PATCH 166/285] Add Java 21 to test matrix --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0197cfdd91..b50a9813d1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] # macOS-latest, windows-latest] - java-version: ["8", "11", "17"] + java-version: ["8", "11", "17", "21"] distribution: ["temurin", "corretto"] profile: ["test-direct", "test-no-direct"] runs-on: ${{ matrix.os }} From 5dbf142e0d734e617154f143cd02e3078955ea86 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Fri, 20 Oct 2023 21:34:37 +0000 Subject: [PATCH 167/285] [maven-release-plugin] prepare release clojure-1.12.0-alpha5 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2dd37faaad..d790670455 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0-alpha5 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0-alpha5 From 08a2d9bdd013143a87e50fa82e9740e2ab4ee2c2 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Fri, 20 Oct 2023 21:34:37 +0000 Subject: [PATCH 168/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d790670455..2dd37faaad 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-alpha5 + 1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0-alpha5 + HEAD From e0efe77eb39f3868ba02c5951f036a48262e80ff Mon Sep 17 00:00:00 2001 From: fogus Date: Thu, 8 Feb 2024 13:10:12 -0500 Subject: [PATCH 169/285] CLJ-2806: Add support for a param-tags metadata via the special metadata field :param-tags taking a vector of symbols corresponding to types and a new reader for supporting it of ^[T U]. Also, added support for using param-tags at compile time to specify a single method for invocation or acccess of qualified class members Class/member and constructors via Class/new. Also implemented method values by expanding the meaning of qualified class member symbolic representation. Added compiler macro to identify Class/method and Class/new member symbols and emit a single-arity function with type hints and coercions on args to fully resolve target constructor, instance method, or static method call. There is no way to specify bound methods. --- src/clj/clojure/gvec.clj | 4 +- src/jvm/clojure/lang/Compiler.java | 349 +++++++++++++++++++- src/jvm/clojure/lang/LispReader.java | 4 +- src/jvm/clojure/lang/RT.java | 1 + test/clojure/test_clojure/java_interop.clj | 2 +- test/clojure/test_clojure/method_thunks.clj | 53 +++ test/clojure/test_clojure/param_tags.clj | 52 +++ 7 files changed, 450 insertions(+), 15 deletions(-) create mode 100644 test/clojure/test_clojure/method_thunks.clj create mode 100644 test/clojure/test_clojure/param_tags.clj diff --git a/src/clj/clojure/gvec.clj b/src/clj/clojure/gvec.clj index 52075c420e..590cfcecf9 100644 --- a/src/clj/clojure/gvec.clj +++ b/src/clj/clojure/gvec.clj @@ -87,7 +87,7 @@ (.chunkedNext this))) (more [this] (let [s (.next this)] - (or s (clojure.lang.PersistentList/EMPTY)))) + (or s clojure.lang.PersistentList/EMPTY))) (cons [this o] (clojure.lang.Cons. o this)) (count [this] @@ -124,7 +124,7 @@ (new VecSeq am vec (.arrayFor vec nexti) nexti 0 nil)))) (chunkedMore [this] (let [s (.chunkedNext this)] - (or s (clojure.lang.PersistentList/EMPTY)))) + (or s clojure.lang.PersistentList/EMPTY))) clojure.lang.IMeta (meta [_] diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 758108e8bc..4bb066c92d 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -15,15 +15,18 @@ //* import clojure.asm.*; +import clojure.asm.Type; import clojure.asm.commons.GeneratorAdapter; import clojure.asm.commons.Method; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; +import java.lang.reflect.Executable; import java.util.*; import java.util.regex.Pattern; import java.util.regex.Matcher; +import java.util.stream.Collectors; //*/ /* @@ -1113,6 +1116,264 @@ static Class tagToClass(Object tag) { } } +// In invocation position +// direct invocation of resolved constructor, static, or instance method +// OR legacy static method invocation with inference +// this is the ONLY valid case where method is unresolved by end of constructor +// In value position, will emit as a method thunk (error if not resolved) +static class MethodValueExpr implements Expr { + private final Class c; + private final List hintedSig; + private final Executable method; + private final Symbol methodSymbol; + private final String methodName; + + public MethodValueExpr(Class methodClass, Symbol sym){ + c = methodClass; + methodSymbol = sym; + methodName = sym.name; + + List methods = methodsWithName(c, methodName); + if(methods.isEmpty()) + throw noMethodWithNameException(c, methodName); + + hintedSig = tagsToClasses(paramTagsOf(sym)); + if(hintedSig != null) { + method = resolveHintedMethod(c, methodName, hintedSig, methods); + } else { + Executable maybeMethod = null; + if(methods.size() == 1) { + // Only 1 method - no inference needed + maybeMethod = methods.get(0); + } + else if(methods.size() > 1) { + // Only statics supported at this point (needs inference) + + if(methodNamesConstructor(c, methodName)) + throw overloadNeedsParamTagsException(c, methodName); + + // Filter out instance methods (no inference allowed) + List staticMethods = methods.stream() + .filter(m -> Modifier.isStatic(m.getModifiers())) + .collect(Collectors.toList()); + if(staticMethods.size() == 1) + maybeMethod = staticMethods.get(0); + else if(staticMethods.isEmpty()) + throw overloadNeedsParamTagsException(c, methodName); + // else not resolved, static method w/inference + } + method = maybeMethod; + } + } + + private static Executable resolveHintedMethod(Class c, String methodName, List hintedSig, List methods) { + final int arity = hintedSig.size(); + List filteredMethods = methods.stream() + .filter(m -> m.getParameterCount() == arity) + .filter(m -> !m.isSynthetic()) // remove bridge/lambda methods + .filter(m -> signatureMatches(hintedSig, m)) + .collect(Collectors.toList()); + + if(filteredMethods.size() == 1) + return filteredMethods.get(0); + else + throw paramTagsDontResolveException(c, methodName, hintedSig, filteredMethods.size()); + } + + private static boolean methodNamesConstructor(Class c, String methodName) { + return c != null && methodName.equals("new"); + } + + private static List methodsWithName(Class c, String name) { + final Executable[] methods; + final String methodName; + if (methodNamesConstructor(c, name)) { + methods = c.getConstructors(); + methodName = c.getName(); + } + else { + methods = c.getMethods(); + methodName = name; + } + + return Arrays.stream(methods) + .filter(m -> m.getName().equals(methodName)) + .collect(Collectors.toList()); + } + + public boolean isResolved() { + return method != null; + } + + @Override + public Object eval() { + return toFnExpr(this).eval(); + } + + @Override + public void emit(C context, ObjExpr objx, GeneratorAdapter gen) { + toFnExpr(this).emit(context, objx, gen); + } + + @Override + public boolean hasJavaClass() { + return true; + } + + @Override + public Class getJavaClass() { + return AFn.class; + } + + private static FnExpr toFnExpr(MethodValueExpr mexpr) { + // If not resolved by this point we were not given param-tags + // and named method was overloaded. + if(!mexpr.isResolved()) { + throw overloadNeedsParamTagsException(mexpr.c, mexpr.methodName); + } + + // return hint symbol + Symbol retTag = null; + Class retClass = mexpr.method instanceof Constructor ? mexpr.c + : ((java.lang.reflect.Method)mexpr.method).getReturnType(); + if (isHintablePrimitive(retClass) || !retClass.isPrimitive()) { + retTag = primTag(retClass); + retTag = (retTag != null) ? retTag : Symbol.intern(null, retClass.getName()); + } + + return buildThunk(mexpr.c, mexpr.method, mexpr.methodSymbol, + isInstanceMethod(mexpr.method) ? THIS : null, retTag); + } + + private static boolean isHintablePrimitive(Class c) { + return Long.TYPE.equals(c) || Double.TYPE.equals(c); + } + + private static Symbol primTag(Class c) { + String t = null; + if(c.isPrimitive()) { + t = c.getName(); + } + else if(c.isArray() && c.getComponentType().isPrimitive()) { + t = c.getName() + "s"; + } + return (t == null) ? null : Symbol.intern(null, t); + } + + // All buildThunk methods currently return a new FnExpr on every call + // TBD: caching/reuse of thunks + private static FnExpr buildThunk(Class c, Executable method, Symbol methodSymbol, Symbol instanceParam, Symbol retHint) { + // (fn invoke__Class_meth (^retHint? [this? primHintedArgs*] (methodSymbol this? primHintedArgs*))) + IPersistentVector params = PersistentVector.EMPTY; + if(instanceParam != null) params = params.cons(instanceParam); + // hinted params + Class[] paramTypes = method.getParameterTypes(); + for(int i = 0; i hintedSig) { + return PersistentVector.create(hintedSig.stream() + .map(tag -> tag == null ? PARAM_TAG_ANY : tag) + .collect(Collectors.toList())); + } + + static IllegalArgumentException noMethodWithNameException(Class c, String methodName) { + return new IllegalArgumentException("Could not find " + + methodDescription(c, methodName)); + } + + static IllegalArgumentException overloadNeedsParamTagsException(Class c, String methodName) { + return new IllegalArgumentException("Multiple matches for " + + methodDescription(c, methodName) + + ", use param-tags to specify"); + } + + static IllegalArgumentException paramTagsDontResolveException(Class c, String methodName, List hintedSig, int found) { + return new IllegalArgumentException("Expected to find 1 matching signature for " + + methodDescription(c, methodName) + + " but found " + found + + " with param-tags " + toParamTags(hintedSig)); + } +} + +final static Symbol PARAM_TAG_ANY = Symbol.intern(null, "_"); + +private static IPersistentVector paramTagsOf(Symbol sym){ + Object paramTags = RT.get(RT.meta(sym), RT.PARAM_TAGS_KEY); + + if(paramTags != null && !(paramTags instanceof IPersistentVector)) + throw new IllegalArgumentException("param-tags of symbol " + + sym + " should be a vector."); + + return (IPersistentVector) paramTags; +} + +// calls tagToClass on every element, unless it encounters _ which becomes null +private static List tagsToClasses(IPersistentVector paramTags) { + if(paramTags == null) return null; + + List sig = new ArrayList<>(); + for (ISeq s = RT.seq(paramTags); s!=null; s = s.next()) { + Object t = s.first(); + if (t.equals(PARAM_TAG_ANY)) + sig.add(null); + else + sig.add(HostExpr.tagToClass(t)); + } + return sig; +} + +private static boolean signatureMatches(List sig, Executable method) +{ + Class[] methodSig = method.getParameterTypes(); + if(methodSig.length != sig.size()) return false; + + for (int i = 0; i < methodSig.length; i++) + if (sig.get(i) != null && !sig.get(i).equals(methodSig[i])) + return false; + + return true; +}; + +static boolean isStaticMethod(Executable method) { + return method instanceof java.lang.reflect.Method && Modifier.isStatic(method.getModifiers()); +} + +static boolean isInstanceMethod(Executable method) { + return method instanceof java.lang.reflect.Method && !Modifier.isStatic(method.getModifiers()); +} + +static boolean isConstructor(Executable method) { + return method instanceof Constructor; +} + +private static void checkMethodArity(Executable method, int argCount) { + if(method.getParameterCount() != argCount) + throw new IllegalArgumentException("Invocation of " + + MethodValueExpr.methodDescription(method.getDeclaringClass(), method.getName()) + + " expected " + method.getParameterCount() + " arguments, but received " + argCount); +} + static abstract class FieldExpr extends HostExpr{ } @@ -1456,6 +1717,21 @@ static class InstanceMethodExpr extends MethodExpr{ final static Method invokeInstanceMethodMethod = Method.getMethod("Object invokeInstanceMethod(Object,String,Object[])"); + public InstanceMethodExpr(String source, int line, int column, Symbol tag, Expr target, + String methodName, java.lang.reflect.Method preferredMethod, IPersistentVector args, boolean tailPosition) + { + checkMethodArity(preferredMethod, RT.count(args)); + + this.source = source; + this.line = line; + this.column = column; + this.args = args; + this.methodName = methodName; + this.target = target; + this.tag = tag; + this.tailPosition = tailPosition; + this.method = preferredMethod; + } public InstanceMethodExpr(String source, int line, int column, Symbol tag, Expr target, String methodName, IPersistentVector args, boolean tailPosition) @@ -1652,6 +1928,29 @@ static class StaticMethodExpr extends MethodExpr{ final static Keyword warnOnBoxedKeyword = Keyword.intern("warn-on-boxed"); Class jc; + public StaticMethodExpr(String source, int line, int column, Symbol tag, Class c, + String methodName, java.lang.reflect.Method preferredMethod, IPersistentVector args, boolean tailPosition) + { + checkMethodArity(preferredMethod, RT.count(args)); + + this.c = c; + this.methodName = methodName; + this.args = args; + this.source = source; + this.line = line; + this.column = column; + this.tag = tag; + this.tailPosition = tailPosition; + this.method = preferredMethod; + + if(method != null && warnOnBoxedKeyword.equals(RT.UNCHECKED_MATH.deref()) && isBoxedMath(method)) + { + RT.errPrintWriter() + .format("Boxed math warning, %s:%d:%d - call: %s.\n", + SOURCE_PATH.deref(), line, column, method.toString()); + } + } + public StaticMethodExpr(String source, int line, int column, Symbol tag, Class c, String methodName, IPersistentVector args, boolean tailPosition) { @@ -2563,6 +2862,13 @@ public static class NewExpr implements Expr{ Method.getMethod("Object invokeConstructor(Class,Object[])"); final static Method forNameMethod = Method.getMethod("Class classForName(String)"); + public NewExpr(Class c, Constructor preferredConstructor, IPersistentVector args, int line, int column) { + checkMethodArity(preferredConstructor, RT.count(args)); + + this.args = args; + this.c = c; + this.ctor = preferredConstructor; + } public NewExpr(Class c, IPersistentVector args, int line, int column) { this.args = args; @@ -3877,17 +4183,46 @@ static public Expr parse(C context, ISeq form) { return new KeywordInvokeExpr((String) SOURCE.deref(), lineDeref(), columnDeref(), tagOf(form), (KeywordExpr) fexpr, target); } + + // Preserving the existing static field bug that replaces a reference in parens with + // the field itself rather than trying to invoke the value in the field. This is + // an exception to the uniform Class/member qualification per CLJ-2806 ticket. + if(fexpr instanceof StaticFieldExpr) + return fexpr; + PersistentVector args = PersistentVector.EMPTY; for(ISeq s = RT.seq(form.next()); s != null; s = s.next()) { args = args.cons(analyze(context, s.first())); } + + if(fexpr instanceof MethodValueExpr) + return toHostExpr((MethodValueExpr)fexpr, (String) SOURCE.deref(), lineDeref(), columnDeref(), tagOf(form), tailPosition, args); + // if(args.count() > MAX_POSITIONAL_ARITY) // throw new IllegalArgumentException( // String.format("No more than %d args supported", MAX_POSITIONAL_ARITY)); return new InvokeExpr((String) SOURCE.deref(), lineDeref(), columnDeref(), tagOf(form), fexpr, args, tailPosition); } + + private static Expr toHostExpr(MethodValueExpr mexpr, String source, int line, int column, Symbol tag, boolean tailPosition, IPersistentVector args) { + if(!mexpr.isResolved()) { + // default to static method with inference + return new StaticMethodExpr(source, line, column, tag, mexpr.c, munge(mexpr.methodName), args, tailPosition); + } + + if(isConstructor(mexpr.method)) + return new NewExpr(mexpr.c, (Constructor) mexpr.method, args, line, column); + + if(isInstanceMethod(mexpr.method)) + return new InstanceMethodExpr(source, line, column, tag, (Expr) RT.first(args), + munge(mexpr.methodName), (java.lang.reflect.Method) mexpr.method, PersistentVector.create(RT.next(args)), + tailPosition); + + return new StaticMethodExpr(source, line, column, tag, mexpr.c, + munge(mexpr.methodName), (java.lang.reflect.Method) mexpr.method, args, tailPosition); + } } static class SourceDebugExtensionAttribute extends Attribute{ @@ -7039,16 +7374,6 @@ public static Object macroexpand1(Object x) { } return preserveTag(form, RT.listStar(DOT, target, meth, form.next().next())); } - else if(namesStaticMember(sym)) - { - Symbol target = Symbol.intern(sym.ns); - Class c = HostExpr.maybeClass(target, false); - if(c != null) - { - Symbol meth = Symbol.intern(sym.name); - return preserveTag(form, RT.listStar(DOT, target, meth, form.next())); - } - } else { //(s.substring 2 5) => (. s substring 2 5) @@ -7308,8 +7633,10 @@ private static Expr analyzeSymbol(Symbol sym) { { if(Reflector.getField(c, sym.name, true) != null) return new StaticFieldExpr(lineDeref(), columnDeref(), c, sym.name, tag); - throw Util.runtimeException("Unable to find static field: " + sym.name + " in " + c); + else + return new MethodValueExpr(c, sym); } + } } //Var v = lookupVar(sym, false); diff --git a/src/jvm/clojure/lang/LispReader.java b/src/jvm/clojure/lang/LispReader.java index 9fcb7b5aa9..104b05d1a2 100644 --- a/src/jvm/clojure/lang/LispReader.java +++ b/src/jvm/clojure/lang/LispReader.java @@ -956,8 +956,10 @@ public Object invoke(Object reader, Object caret, Object opts, Object pendingFor meta = RT.map(RT.TAG_KEY, meta); else if (meta instanceof Keyword) meta = RT.map(meta, RT.T); + else if (meta instanceof IPersistentVector) + meta = RT.map(RT.PARAM_TAGS_KEY, meta); else if(!(meta instanceof IPersistentMap)) - throw new IllegalArgumentException("Metadata must be Symbol,Keyword,String or Map"); + throw new IllegalArgumentException("Metadata must be Symbol,Keyword,String,Vector or Map"); Object o = read(r, true, null, true, opts, pendingForms); if(o instanceof IMeta) diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index 5d20ef4964..86c89d69fb 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -189,6 +189,7 @@ else if(s.equals("false")) Var.intern(CLOJURE_NS, Symbol.intern("*err*"), new PrintWriter(new OutputStreamWriter(System.err), true)).setDynamic(); final static Keyword TAG_KEY = Keyword.intern(null, "tag"); +final static Keyword PARAM_TAGS_KEY = Keyword.intern(null, "param-tags"); final static Keyword CONST_KEY = Keyword.intern(null, "const"); final static public Var AGENT = Var.intern(CLOJURE_NS, Symbol.intern("*agent*"), null).setDynamic(); static Object readeval = readTrueFalseUnknown(System.getProperty("clojure.read.eval","true")); diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj index 4925284cc2..da7075d138 100644 --- a/test/clojure/test_clojure/java_interop.clj +++ b/test/clojure/test_clojure/java_interop.clj @@ -408,7 +408,7 @@ (to-array [1 2 3]) )) (defn queue [& contents] - (apply conj (clojure.lang.PersistentQueue/EMPTY) contents)) + (apply conj clojure.lang.PersistentQueue/EMPTY contents)) (defn array-typed-equals [expected actual] (and (= (class expected) (class actual)) diff --git a/test/clojure/test_clojure/method_thunks.clj b/test/clojure/test_clojure/method_thunks.clj new file mode 100644 index 0000000000..06ac5a3f6e --- /dev/null +++ b/test/clojure/test_clojure/method_thunks.clj @@ -0,0 +1,53 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. +; Authors: Fogus + +(ns clojure.test-clojure.method-thunks + (:use clojure.test) + (:import (clojure.lang Compiler Tuple) + (java.util Arrays UUID Locale) + clojure.lang.IFn$LL)) + +(set! *warn-on-reflection* true) + +(deftest method-arity-selection + (is (= '([] [] []) + (take 3 (repeatedly ^[] Tuple/create)))) + (is (= '([1] [2] [3]) + (map ^[_] Tuple/create [1 2 3]))) + (is (= '([1 4] [2 5] [3 6]) + (map ^[_ _] Tuple/create [1 2 3] [4 5 6]))) + (is (thrown? Exception (eval 'clojure.lang.Tuple/create)))) + +(deftest method-signature-selection + (is (= [1.23 3.14] + (map ^[double] Math/abs [1.23 -3.14]))) + (is (= [(float 1.23) (float 3.14)] + (map ^[float] Math/abs [1.23 -3.14]))) + (is (= [1 2 3] + (map ^[long] Math/abs [1 2 -3]))) + (is (= [#uuid "00000000-0000-0001-0000-000000000002"] + (map ^[long long] UUID/new [1] [2]))) + (is (= '("a" "12") + (map ^[Object] String/valueOf ["a" 12]))) + (is (= ["A" "B" "C"] + (map ^[java.util.Locale] String/toUpperCase ["a" "b" "c"] (repeat java.util.Locale/ENGLISH)))) + (is (thrown? ClassCastException + (doall (map ^[long] String/valueOf [12 "a"]))))) + +(def mt ^[_] Tuple/create) +(def mts {:fromString ^[_] UUID/fromString}) + +(deftest method-thunks-in-structs + (is (= #uuid "00000000-0000-0001-0000-000000000002" + ((:fromString mts) "00000000-0000-0001-0000-000000000002"))) + (is (= [1] (mt 1)))) + +(deftest primitive-hinting + (is (instance? clojure.lang.IFn$DO ^[double] String/valueOf)) + (is (instance? clojure.lang.IFn$LL ^[long] Math/abs))) diff --git a/test/clojure/test_clojure/param_tags.clj b/test/clojure/test_clojure/param_tags.clj new file mode 100644 index 0000000000..2b6f1bffe2 --- /dev/null +++ b/test/clojure/test_clojure/param_tags.clj @@ -0,0 +1,52 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. +; Authors: Fogus + +(ns clojure.test-clojure.param-tags + (:use clojure.test) + (:require [clojure.test-helper :refer [should-not-reflect]]) + (:import (clojure.lang Tuple) + (java.util Arrays UUID Locale))) + +(set! *warn-on-reflection* true) + +(deftest no-hints-with-param-tags + (should-not-reflect + (defn touc-no-reflect [s] + (^[] String/toUpperCase s))) + (should-not-reflect + (defn touc-no-reflectq [s] + (^[] java.lang.String/toUpperCase s))) + (should-not-reflect + (defn touc-no-reflect-arg-tags [s] + (^[java.util.Locale] String/toUpperCase s java.util.Locale/ENGLISH)))) + +(deftest param-tags-in-invocation-positions + (testing "qualified static method invocation" + (is (= 3 (^[long] Math/abs -3))) + (is (= [1 2] (^[_ _] Tuple/create 1 2))) + (is (= "42" (Long/toString 42)))) + (testing "qualified ctor invocation" + (is (= (^[long long] UUID/new 1 2) #uuid "00000000-0000-0001-0000-000000000002")) + (is (= (^[long long] java.util.UUID/new 1 2) #uuid "00000000-0000-0001-0000-000000000002")) + (is (= "a" (^[String] String/new "a")))) + (testing "qualified instance method invocation" + (is (= \A (String/charAt "A" 0))) + (is (= "A" (^[java.util.Locale] String/toUpperCase "a" java.util.Locale/ENGLISH))) + (is (= "A" (^[Locale] String/toUpperCase "a" java.util.Locale/ENGLISH))) + (is (= 65 (aget (^[String] String/getBytes "A" "US-ASCII") 0))) + (is (= "42" (^[] Long/toString 42)))) + (testing "string repr array type resolutions" + (let [lary (long-array [1 2 3 4 99 100]) + oary (into-array [1 2 3 4 99 100]) + sary (into-array String ["a" "b" "c"])] + (is (= 4 (^[longs long] Arrays/binarySearch lary (long 99)))) + (is (= 4 (^[objects _] Arrays/binarySearch oary 99))) + (is (= 4 (^["[Ljava.lang.Object;" _] Arrays/binarySearch oary 99))) + (is (= 1 (^["[Ljava.lang.Object;" _] Arrays/binarySearch sary "b")))))) + From a6937fd02a9f0833dd4b2a352fd481b577584cae Mon Sep 17 00:00:00 2001 From: JarrodCTaylor Date: Sat, 3 Feb 2024 10:29:56 -0600 Subject: [PATCH 170/285] Expanded param-tags tests --- test/clojure/test_clojure/param_tags.clj | 138 ++++++++++++++++++- test/java/clojure/test/ConcreteClass.java | 8 ++ test/java/clojure/test/GenericInterface.java | 5 + test/java/clojure/test/SwissArmy.java | 39 ++++++ 4 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 test/java/clojure/test/ConcreteClass.java create mode 100644 test/java/clojure/test/GenericInterface.java create mode 100644 test/java/clojure/test/SwissArmy.java diff --git a/test/clojure/test_clojure/param_tags.clj b/test/clojure/test_clojure/param_tags.clj index 2b6f1bffe2..c4c57d60e1 100644 --- a/test/clojure/test_clojure/param_tags.clj +++ b/test/clojure/test_clojure/param_tags.clj @@ -9,9 +9,14 @@ (ns clojure.test-clojure.param-tags (:use clojure.test) - (:require [clojure.test-helper :refer [should-not-reflect]]) - (:import (clojure.lang Tuple) - (java.util Arrays UUID Locale))) + (:require + [clojure.string :as str] + [clojure.reflect :as r] + [clojure.test-helper :refer [should-not-reflect]]) + (:import + (clojure.test SwissArmy ConcreteClass) + (clojure.lang Tuple Compiler Compiler$CompilerException) + (java.util Arrays UUID Locale))) (set! *warn-on-reflection* true) @@ -50,3 +55,130 @@ (is (= 4 (^["[Ljava.lang.Object;" _] Arrays/binarySearch oary 99))) (is (= 1 (^["[Ljava.lang.Object;" _] Arrays/binarySearch sary "b")))))) + +;; Mapping of symbols returned from reflect call to :parameter-type used as arguments to .getDeclaredMethod, +;; :arg-type used as arguments to the methods and constructors being tested, :arg-tag used as arg-tags +;; to the methods and constructors being tested. +(def reflected-parameter-types {'int {:parameter-type Integer/TYPE + :arg-type "(int 42)" + :arg-tag "int"} + 'boolean {:parameter-type Boolean/TYPE + :arg-type "true" + :arg-tag "boolean"} + 'long {:parameter-type Long/TYPE + :arg-type "42" + :arg-tag "long"} + 'long<> {:parameter-type (Class/forName "[J") + :arg-type "(long-array [1 2])" + :arg-tag "long*"} + 'int<><> {:parameter-type (Class/forName "[[I") + :arg-type "(make-array Integer/TYPE 1 2)" + :arg-tag "int**"} + 'java.lang.Object<> {:parameter-type (Class/forName "[Ljava.lang.Object;") + :arg-type "(into-array [1 2])" + :arg-tag "\"[Ljava.lang.Object;\""} + 'java.lang.String<> {:parameter-type (Class/forName "[Ljava.lang.String;") + :arg-type "(into-array [\"a\" \"b\"])" + :arg-tag "\"[Ljava.lang.String;\""}}) + +(defn is-static-method? [class method-name params] + (let [method (.getDeclaredMethod ^Class class ^String (name method-name) ^"[Ljava.lang.Object;" params)] + (java.lang.reflect.Modifier/isStatic (.getModifiers method)))) + +(defn get-methods + "Reflect the class located at `path`, filter out the public members, add a :type + of :constructor, :static, or :instance to each." + [path] + (let [reflected-class (r/reflect (resolve path)) + public (filter #(contains? (:flags %) :public) (:members reflected-class))] + (reduce (fn [res m] + (let [class (-> m :declaring-class resolve) + params (into-array Class (map #(-> % reflected-parameter-types :parameter-type) (:parameter-types m)))] + (cond + (not (contains? m :return-type)) (conj res (assoc m :type :constructor)) + (is-static-method? class (:name m) params) (conj res (assoc m :type :static)) + :else (conj res (assoc m :type :instance))))) + [] public))) + +(defn exercise-constructor + "Provided a map of data returned from a call to reflect representing a constructor. + Construct a new instance of the class providing the appropriate arg-tags and return + a map containing the new instance and expected target class" + [{:keys [declaring-class parameter-types] :as m}] + (let [target-class (-> declaring-class str Class/forName) + args (str/join " " (map #(-> % reflected-parameter-types :arg-type) parameter-types)) + arg-tags (str/join " " (map #(-> % reflected-parameter-types :arg-tag) parameter-types)) + fun-call-str (read-string (str "(^[" arg-tags "] " declaring-class ". " args ")")) + _ (should-not-reflect #(eval 'fun-call-str)) + new-instance (eval fun-call-str)] + {:expected target-class :actual new-instance})) + +(defn exercise-static-method + "Provided a map of data returned from a call to reflect representing a static class method. + Call the static method providing the appropriate arg-tags and return a map containing + the actual and expected response." + [{:keys [name declaring-class parameter-types]}] + (let [class (str declaring-class) + method (str name) + args (str/join " " (map #(-> % reflected-parameter-types :arg-type) parameter-types)) + arg-tags (str/join " " (map #(-> % reflected-parameter-types :arg-tag) parameter-types)) + expected-response (str/join "-" parameter-types) + fun-call-str (read-string (str "(^[" arg-tags "] " class "/" method " " args ")")) + _ (should-not-reflect #(eval 'fun-call-str)) + response (eval fun-call-str)] + {:expected expected-response :actual response})) + +(defn exercise-instance-method + "Provided a map of data returned from a call to reflect representing a class instance method. + Call the method providing the appropriate arg-tags and return a map containing + the actual and expected response." + [{:keys [name declaring-class parameter-types]}] + (let [method (str name) + args (str/join " " (map #(-> % reflected-parameter-types :arg-type) parameter-types)) + arg-tags (str/join " " (map #(-> % reflected-parameter-types :arg-tag) parameter-types)) + expected-response (str/join "-" parameter-types) + fun-call-str (read-string (str "(^[" arg-tags "] " declaring-class "/" method " " "(" declaring-class ".)" " " args ")")) + _ (should-not-reflect #(eval 'fun-call-str)) + response (eval fun-call-str)] + {:expected expected-response :actual response})) + +(deftest arg-tags-in-constructors-and-static-and-instance-methods + (doseq [m (get-methods 'clojure.test.SwissArmy)] + (case (:type m) + :constructor (let [{:keys [expected actual]} (exercise-constructor m)] + (is (instance? expected actual))) + :static (let [{:keys [expected actual]} (exercise-static-method m)] + (is (= expected actual))) + :instance (let [{:keys [expected actual]} (exercise-instance-method m)] + (is (= expected actual)))))) + +(defmacro arg-tags-called-in-macro + [a-type b-type a b] + `(^[~a-type ~b-type] SwissArmy/staticArityOverloadMethod ~a ~b)) + +(deftest arg-tags-in-macro + (is (= "int-int" (arg-tags-called-in-macro int int 1 2)))) + +(deftest bridge-methods + (testing "Allows correct intended usage." + (let [concrete (ConcreteClass.)] + (is (= 42 (^[Integer] ConcreteClass/stampWidgets concrete (int 99)))))) + (testing "Will not call bridge method." + (is (thrown? Compiler$CompilerException + (eval '(let [concrete (clojure.test.ConcreteClass.)] + (^[Object] ConcreteClass/stampWidgets concrete (int 99)))))))) + + +(deftest incorrect-arity-invocation-error-messages + + (testing "Invocation with param-tags having incorrect number of args" + (let [e (try + (eval '(^[long] Math/abs -1 -2 -3)) + (catch Compiler$CompilerException e (str "-> " (.getMessage (.getCause e)))))] + (is (not (nil? (re-find #"expected 1.*received 3" e))) "Error message was expected to indicate 1 argument was expected but 2 were provided"))) + + (testing "Invocation without param-tags having incorrect number of args" + (let [e (try + (eval '(java.util.UUID/fromString "a" 1)) + (catch Compiler$CompilerException e (str "-> " (.getMessage (.getCause e)))))] + (is (not (nil? (re-find #"expected 1.*received 2" e))) "Error message was expected to indicate 1 argument was expected but 2 were provided")))) \ No newline at end of file diff --git a/test/java/clojure/test/ConcreteClass.java b/test/java/clojure/test/ConcreteClass.java new file mode 100644 index 0000000000..69dde53538 --- /dev/null +++ b/test/java/clojure/test/ConcreteClass.java @@ -0,0 +1,8 @@ +package clojure.test; + +public class ConcreteClass implements GenericInterface { + @Override + public Integer stampWidgets(Integer val) { + return 42; + } +} \ No newline at end of file diff --git a/test/java/clojure/test/GenericInterface.java b/test/java/clojure/test/GenericInterface.java new file mode 100644 index 0000000000..a20496ab1a --- /dev/null +++ b/test/java/clojure/test/GenericInterface.java @@ -0,0 +1,5 @@ +package clojure.test; + +public interface GenericInterface { + T stampWidgets(T val); +} \ No newline at end of file diff --git a/test/java/clojure/test/SwissArmy.java b/test/java/clojure/test/SwissArmy.java new file mode 100644 index 0000000000..339c3723c4 --- /dev/null +++ b/test/java/clojure/test/SwissArmy.java @@ -0,0 +1,39 @@ +package clojure.test; + +public class SwissArmy { + public String ctorId; + + public SwissArmy() {this.ctorId = "1";} + public SwissArmy(int a, long b) {this.ctorId = "2";} + public SwissArmy(long a, int b) {this.ctorId = "3";} + public SwissArmy(boolean a, boolean b) {this.ctorId = "4";} + public SwissArmy(long[] a, int b) {this.ctorId = "5";} + public SwissArmy(String[] a, long b) {this.ctorId = "6";} + public SwissArmy(int[][] a, long b) {this.ctorId = "7";} + + public String noArgs() {return "";} + public String twoArgsIL(int a, long b) {return "int-long";} + public String twoArgsLI(long a, int b) {return "long-int";} + public String twoArgsBB(boolean a, boolean b) {return "boolean-boolean";} +// public String twoArgsLAI(long[] a, int b) {return "long<>-int";} + public String twoArgsSAL(String[] a, long b) {return "java.lang.String<>-long";} +// public String twoArgsMDIL(int[][] a, long b) {return "int<><>-long";} + public String arityOverloadMethod(int a) {return "int";} + public String arityOverloadMethod(int a, int b) {return "int-int";} + public String arityOverloadMethod(int a, int b, int c) {return "int-int-int";} + public String doppelganger(int a, int b) {return "int-int";} + + public static String staticNoArgs() {return "";} + public static String staticOneArg(boolean a) {return "boolean";} + public static String staticTwoArgsIL(int a, long b) {return "int-long";} + public static String staticTwoArgsLI(long a, int b) {return "long-int";} + public static String staticTwoArgsBB(boolean a, boolean b) {return "boolean-boolean";} + public static String staticTwoArgsSAL(String[] a, long b) {return "java.lang.String<>-long";} +// public static String staticTwoArgsMDIL(int[][] a, long b) {return "int<><>-long";} +// public static String couldReflect(long[] a, int b) {return "long<>-int";} + public static String couldReflect(Object[] a, int b) {return "java.lang.Object<>-int";} + public static String staticArityOverloadMethod(int a) {return "int";} + public static String staticArityOverloadMethod(int a, int b) {return "int-int";} + public static String staticArityOverloadMethod(int a, int b, int c) {return "int-int-int";} + public static String doppelganger(int a, int b, long c) {return "int-int-long";} +} \ No newline at end of file From b2a914355589acad3aed6d724fbd6a995fd2610b Mon Sep 17 00:00:00 2001 From: fogus Date: Wed, 10 Jan 2024 11:01:32 -0600 Subject: [PATCH 171/285] CLJ-2807: Add support for a symbol comprising the name of the array component type (primitive, full-qualified class, or import aliases accepted) followed by an asterisk for each dimension of the array (1 or more). --- src/jvm/clojure/lang/Compiler.java | 87 ++++++++++++++++++++-- test/clojure/test_clojure/java_interop.clj | 20 +++++ test/clojure/test_clojure/numbers.clj | 17 +++++ 3 files changed, 119 insertions(+), 5 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 4bb066c92d..4baf9cb72c 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -395,7 +395,12 @@ static Symbol resolveSymbol(Symbol sym){ } Object o = currentNS().getMapping(sym); if(o == null) + { + Class ac = HostExpr.maybeArrayClass(sym); + if(ac != null) + return HostExpr.arrayTypeToSymbol(ac); return Symbol.intern(currentNS().name.name, sym.name); + } else if(o instanceof Class) return Symbol.intern(null, ((Class) o).getName()); else if(o instanceof Var) @@ -1023,8 +1028,12 @@ public static Class maybeClass(Object form, boolean stringOk) { { if(Util.equals(sym,COMPILE_STUB_SYM.get())) return (Class) COMPILE_STUB_CLASS.get(); - if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[') - c = RT.classForNameNonLoading(sym.name); + else if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[') + { + c = maybeArrayClass(sym); + if (c == null) + c = RT.classForNameNonLoading(sym.name); + } else { Object o = currentNS().getMapping(sym); @@ -1035,7 +1044,12 @@ else if(LOCAL_ENV.deref() != null && ((java.util.Map)LOCAL_ENV.deref()).contains else { try{ - c = RT.classForNameNonLoading(sym.name); + if(c == null) + { + c = maybeArrayClass(sym); + if(c == null) + c = RT.classForNameNonLoading(sym.name); + } } catch(Exception e){ // aargh @@ -1097,6 +1111,60 @@ else if(sym.name.equals("booleans")) return c; } + static String getArrayComponentClassDescriptor(Class c) { + if (c.isPrimitive()) + return Type.getType(c).getDescriptor(); + + return "L" + c.getName() + ";"; + } + + // componentArrayType (maybe qualified or prim) ending in 1+ *'s, e.g. java.lang.String** + // capture group 1 = componentArrayType, group 2 = dimension *'s + final static Pattern ARRAY_TYPE_PATTERN = Pattern.compile("([^*]+)(\\*+)"); + + public static Class maybeArrayClass(Symbol sym) { + if(!sym.name.endsWith("*")) return null; + + Matcher matcher = ARRAY_TYPE_PATTERN.matcher(sym.name); + + if(!matcher.matches()) return null; + + Symbol rootSymbol = Symbol.intern(matcher.group(1)); + String stars = matcher.group(2); + Class componentClass = maybeClass(rootSymbol, false); + + if(componentClass == null) + componentClass = primClass(rootSymbol); + + if(componentClass == null) return null; + + String componentDescriptor = getArrayComponentClassDescriptor(componentClass); + StringBuilder arrayDescriptor = new StringBuilder(); + arrayDescriptor.append(stars.replace('*', '[')); + arrayDescriptor.append(componentDescriptor); + return maybeClass(arrayDescriptor.toString(), true); + } + + public static Symbol arrayTypeToSymbol(Class c) { + if(!c.isArray()) return null; + + int dim = 1; + + Class componentClass = c.getComponentType(); + + while(componentClass.isArray()) { + dim++; + componentClass = componentClass.getComponentType(); + } + + String componentClassName = componentClass.getName(); + StringBuilder repr = new StringBuilder(componentClassName.length() + dim); + repr.append(componentClassName); + for(int i=0; i 0 || sym.name.charAt(0) == '[') { - return RT.classForName(sym.name); + Class ac = HostExpr.maybeArrayClass(sym); + if(ac != null) + return ac; + else + return RT.classForName(sym.name); } else if(sym.equals(NS)) return RT.NS_VAR; @@ -7732,7 +7804,12 @@ else if(sym.equals(IN_NS)) Object o = n.getMapping(sym); if(o == null) { - if(RT.booleanCast(RT.ALLOW_UNRESOLVED_VARS.deref())) + o = HostExpr.maybeArrayClass(sym); + if(o != null) + { + return o; + } + else if(RT.booleanCast(RT.ALLOW_UNRESOLVED_VARS.deref())) { return sym; } diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj index da7075d138..dae092f641 100644 --- a/test/clojure/test_clojure/java_interop.clj +++ b/test/clojure/test_clojure/java_interop.clj @@ -639,3 +639,23 @@ (deftest test-boxing-prevention-when-compiling-statements (is (= 1 (.get (doto (AtomicInteger. 0) inc-atomic-int)))) (is (= 1 (.get (doto (AtomicLong. 0) inc-atomic-long))))) + +(deftest array-type-symbols + (is (= long* (class (make-array Long/TYPE 0)))) + (is (= int* (class (make-array Integer/TYPE 0)))) + (is (= double* (class (make-array Double/TYPE 0)))) + (is (= short* (class (make-array Short/TYPE 0)))) + (is (= boolean* (class (make-array Boolean/TYPE 0)))) + (is (= byte* (class (make-array Byte/TYPE 0)))) + (is (= float* (class (make-array Float/TYPE 0)))) + (is (= String* (class (make-array String 0)))) + (is (= java.lang.String* (class (make-array String 0)))) + (is (= java.util.UUID* (class (make-array java.util.UUID 0)))) + (is (= `byte* 'byte*)) + (is (= `byte*** 'byte***)) + (is (= `java.util.UUID* 'java.util.UUID*)) + (is (= `String* 'java.lang.String*)) + (is (= `java.lang.String* 'java.lang.String*)) + (is (= `[NotAClassThatWasImported*] '[clojure.test-clojure.java-interop/NotAClassThatWasImported*])) + (is (= [long**] `[~long**])) + (is (= [42] (let [long** 42] `[~long**])))) diff --git a/test/clojure/test_clojure/numbers.clj b/test/clojure/test_clojure/numbers.clj index be4f7a0a60..ec0fa04e34 100644 --- a/test/clojure/test_clojure/numbers.clj +++ b/test/clojure/test_clojure/numbers.clj @@ -593,6 +593,23 @@ Math/pow overflows to Infinity." "[I" (int-array 1) (ints (int-array 1 1)) "[J" (long-array 1) (longs (long-array 1 1)))) +(deftest test-array-type-symbols + (are [str-repr klass] (= (Class/forName str-repr) klass) + "[Z" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'boolean*) + "[B" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'byte*) + "[C" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'char*) + "[S" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'short*) + "[F" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'float*) + "[D" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'double*) + "[I" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'int*) + "[J" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'long*) + "[[J" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'long**) + "[Ljava.lang.Object;" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'Object*) + "[Ljava.lang.String;" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'String*) + "[[Ljava.lang.String;" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'String**)) + (is (nil? (clojure.lang.Compiler$HostExpr/maybeArrayClass 'Object))) + (is (nil? (clojure.lang.Compiler$HostExpr/maybeArrayClass 'ThisIsNotAClassThatCouldBeFound138))) + (is (nil? (clojure.lang.Compiler$HostExpr/maybeArrayClass 'String-*IJ*)))) (deftest test-ratios (is (== (denominator 1/2) 2)) From 619b576022cdd5fae899a8418bc568ab1dac3472 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 7 Feb 2024 11:48:07 -0600 Subject: [PATCH 172/285] CLJ-2775: Added support for java.util.stream streams including stream-reduce, stream-seq, stream-transduce, and stream-into. --- src/clj/clojure/core.clj | 42 ++++++++++- src/clj/clojure/core/protocols.clj | 39 +++++----- test/clojure/test_clojure/streams.clj | 103 ++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 22 deletions(-) create mode 100644 test/clojure/test_clojure/streams.clj diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index b8d9ff9f54..ebca84d40c 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -6830,8 +6830,6 @@ fails, attempts to require sym's namespace and retries." `(let [~ge ~e] (case* ~ge ~shift ~mask ~default ~imap ~switch-type :hash-identity ~skip-check)))))))) -;; redefine reduce with internal-reduce - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; helper files ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (alter-meta! (find-ns 'clojure.core) assoc :doc "Fundamental library of the Clojure language") (load "core_proxy") @@ -6841,6 +6839,45 @@ fails, attempts to require sym's namespace and retries." (load "core/protocols") (load "gvec") +(defn stream-reduce! + "Works like reduce but takes a java.util.stream.BaseStream as its source. + Honors 'reduced', is a terminal operation on the stream" + {:added "1.12"} + ([f ^java.util.stream.BaseStream s] + (clojure.core.protocols/iterator-reduce! (.iterator s) f)) + ([f init ^java.util.stream.BaseStream s] + (clojure.core.protocols/iterator-reduce! (.iterator s) f init))) + +(defn stream-seq! + "Takes a java.util.stream.BaseStream instance s and returns a seq of its + contents. This is a terminal operation on the stream." + {:added "1.12"} + [^java.util.stream.BaseStream stream] + (iterator-seq (.iterator stream))) + +(defn stream-transduce! + "Works like transduce but takes a java.util.stream.BaseStream as its source. + This is a terminal operation on the stream." + {:added "1.12"} + ([xform f ^java.util.stream.BaseStream stream] (stream-transduce! xform f (f) stream)) + ([xform f init ^java.util.stream.BaseStream stream] + (let [f (xform f) + ret (stream-reduce! f init stream)] + (f ret)))) + +(defn stream-into! + "Returns a new coll consisting of coll with all of the items of the + stream conjoined. This is a terminal operation on the stream." + {:added "1.12"} + ([to ^java.util.stream.BaseStream stream] + (if (instance? clojure.lang.IEditableCollection to) + (with-meta (persistent! (stream-reduce! conj! (transient to) stream)) (meta to)) + (stream-reduce! conj to stream))) + ([to xform ^java.util.stream.BaseStream stream] + (if (instance? clojure.lang.IEditableCollection to) + (with-meta (persistent! (stream-transduce! xform conj! (transient to) stream)) (meta to)) + (stream-transduce! xform conj to stream)))) + (defmacro ^:private when-class [class-name & body] `(try (Class/forName ^String ~class-name) @@ -6887,6 +6924,7 @@ fails, attempts to require sym's namespace and retries." :added "1.11"} ^java.util.UUID [] (java.util.UUID/randomUUID)) +;; redefine reduce with internal-reduce (defn reduce "f should be a function of 2 arguments. If val is not supplied, returns the result of applying f to the first 2 items in coll, then diff --git a/src/clj/clojure/core/protocols.clj b/src/clj/clojure/core/protocols.clj index 10c022911d..2ed43152b6 100644 --- a/src/clj/clojure/core/protocols.clj +++ b/src/clj/clojure/core/protocols.clj @@ -30,27 +30,26 @@ (let [s (seq coll)] (internal-reduce s f val)))) -(defn- iter-reduce - ([^java.lang.Iterable coll f] - (let [iter (.iterator coll)] +;; mutates the iterator, respects reduced +(defn iterator-reduce! + ([^java.util.Iterator iter f] + (if (.hasNext iter) + (iterator-reduce! iter f (.next iter)) + (f))) + ([^java.util.Iterator iter f val] + (loop [ret val] (if (.hasNext iter) - (loop [ret (.next iter)] - (if (.hasNext iter) - (let [ret (f ret (.next iter))] - (if (reduced? ret) - @ret - (recur ret))) - ret)) - (f)))) - ([^java.lang.Iterable coll f val] - (let [iter (.iterator coll)] - (loop [ret val] - (if (.hasNext iter) - (let [ret (f ret (.next iter))] - (if (reduced? ret) - @ret - (recur ret))) - ret))))) + (let [ret (f ret (.next iter))] + (if (reduced? ret) + @ret + (recur ret))) + ret)))) + +(defn- iter-reduce + ([^Iterable coll f] + (iterator-reduce! (.iterator coll) f)) + ([^Iterable coll f val] + (iterator-reduce! (.iterator coll) f val))) (defn- naive-seq-reduce "Reduces a seq, ignoring any opportunities to switch to a more diff --git a/test/clojure/test_clojure/streams.clj b/test/clojure/test_clojure/streams.clj new file mode 100644 index 0000000000..c5462a1aa0 --- /dev/null +++ b/test/clojure/test_clojure/streams.clj @@ -0,0 +1,103 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. + +(ns clojure.test-clojure.streams + (:use clojure.test) + (:import [java.util.stream Stream LongStream] + [java.util.function Consumer Predicate Supplier])) + +(deftest test-stream-reduce! + (is (= :only-val (stream-reduce! + (.stream [:only-val])))) + (is (= 0 (stream-reduce! + (.stream [])))) + (is (= 5 (stream-reduce! + (.stream [1 4])))) + (is (= 6 (stream-reduce! + (.stream [1 2 3])))) + (is (= [2 3 4] + (stream-reduce! (fn [v i] (conj v (inc i))) + [] + (.stream [1 2 3])))) + + (is (= 15 (stream-reduce! + (LongStream/rangeClosed 1 5)))) + + (is (= 9 (stream-reduce! + (-> (Stream/of (to-array [1 2 3 4 5])) + (.filter (reify Predicate (test [_ v] (odd? v)))))))) + (is (= {:a 1} + (meta + (stream-reduce! (fn [v i] (conj v (inc i))) + (with-meta [] {:a 1}) + (.stream [1 2 3])))))) + +(deftest test-stream-reduced! + (is (= 5 (stream-reduce! + (fn [x y] (reduced (+ x y))) + (.stream [1 4])))) + + (is (= 45 (stream-reduce! + (fn [acc v] + (if (= v 10) + (reduced acc) + (+ acc v))) + (LongStream/rangeClosed 1 10))))) + +(deftest stream-seq!-test + (let [none (.stream []) + one (Stream/of "a") + n (.stream ["a" "b" "c"]) + inf (Stream/generate (reify Supplier (get [_] 42))) + st (stream-seq! one) + l100 (LongStream/range 0 100)] + (is (empty? (map identity (stream-seq! none)))) + (is (seq? st)) + (is (= ["a"] (map identity st))) + (is (= ["a" "b" "c"] (map identity (stream-seq! n)))) + (is (= [42 42 42 42 42] (take 5 (stream-seq! inf)))) + (is (= 4950 (reduce + (stream-seq! l100)))) 4950)) + +(deftest stream-transduce!-test + (let [xf (comp (filter odd?) (take 5))] + (let [st (Stream/of (to-array [1 2 3 4 5 6 7 8 9]))] + (is (= [1 3 5 7 9] (stream-transduce! xf conj st)))) + + (let [inf (Stream/generate (reify Supplier (get [_] 0)))] + (is (empty? (stream-transduce! xf conj (.limit inf 50))))) + + (let [inf (Stream/generate (reify Supplier (get [_] 43)))] + (is (= [43 43 43 43 43] (stream-transduce! xf conj (.limit inf 50))))) + + (let [inf (Stream/generate (reify Supplier (get [_] 43)))] + (is (= 215 (stream-transduce! xf + (.limit inf 50))))) + + (let [inf (Stream/generate (reify Supplier (get [_] 43)))] + (is (= 315 (stream-transduce! xf + 100 (.limit inf 50))))) + + (let [inf (Stream/generate (reify Supplier (get [_] 43)))] + (is (= "4343434343" (stream-transduce! xf str (.limit inf 50))))))) + +(deftest stream-into!-test + (let [none (.stream []) + one (Stream/of "a") + n (.stream ["a" "b" "c"]) + inf (Stream/generate (reify Supplier (get [_] 42))) + par (-> (LongStream/rangeClosed 1 10) .boxed .parallel) + xf (comp (map #(+ 2 %)) (filter odd?)) + par2 (-> (LongStream/rangeClosed 1 10) .boxed .parallel)] + (is (empty? (stream-into! [] none))) + (is (= ["a"] (stream-into! [] one))) + (is (= ["a" "b" "c"] (stream-into! [] n))) + (is (= [42 42 42 42 42] + (stream-into! [] (.limit inf 5)))) + (is (= [1 2 3 4 5 6 7 8 9 10] + (stream-into! [] par))) + (is (= {:a 1} + (meta + (stream-into! (with-meta [] {:a 1}) + (.stream [1 2 3]))))) + (is (= {:a 1} + (meta + (stream-into! (with-meta clojure.lang.PersistentQueue/EMPTY {:a 1}) + (.stream [1 2 3]))))) + (is (= [-1 -2 3 5 7 9 11] (stream-into! [-1 -2] xf par2))))) From 8895fef132bd064032e737e55d54d9ba2c07a0c6 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 17 Jul 2023 21:14:16 -0500 Subject: [PATCH 173/285] CLJ-2568 clojure.walk now retains metadata when walking lists and seqs --- src/clj/clojure/walk.clj | 4 ++-- test/clojure/test_clojure/clojure_walk.clj | 11 +++++++++++ test/clojure/test_clojure/reader.cljc | 5 +++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/clj/clojure/walk.clj b/src/clj/clojure/walk.clj index fe8fb631bd..0f027e7ad0 100644 --- a/src/clj/clojure/walk.clj +++ b/src/clj/clojure/walk.clj @@ -41,10 +41,10 @@ the sorting function."} {:added "1.1"} [inner outer form] (cond - (list? form) (outer (apply list (map inner form))) + (list? form) (outer (with-meta (apply list (map inner form)) (meta form))) (instance? clojure.lang.IMapEntry form) (outer (clojure.lang.MapEntry/create (inner (key form)) (inner (val form)))) - (seq? form) (outer (doall (map inner form))) + (seq? form) (outer (with-meta (doall (map inner form)) (meta form))) (instance? clojure.lang.IRecord form) (outer (reduce (fn [r x] (conj r (inner x))) form form)) (coll? form) (outer (into (empty form) (map inner form))) diff --git a/test/clojure/test_clojure/clojure_walk.clj b/test/clojure/test_clojure/clojure_walk.clj index 6c6f866332..fa2f3e6492 100644 --- a/test/clojure/test_clojure/clojure_walk.clj +++ b/test/clojure/test_clojure/clojure_walk.clj @@ -63,3 +63,14 @@ (let [coll [:html {:a ["b" 1]} ""] f (fn [e] (if (and (vector? e) (not (map-entry? e))) (apply list e) e))] (is (= (list :html {:a (list "b" 1)} "") (w/postwalk f coll))))) + +(defrecord RM [a]) +(deftest retain-meta + (let [m {:foo true}] + (are [o] (= m (meta (w/postwalk identity (with-meta o m)))) + '(1 2) + [1 2] + #{1 2} + {1 2} + (map inc (range 3)) + (->RM 1)))) \ No newline at end of file diff --git a/test/clojure/test_clojure/reader.cljc b/test/clojure/test_clojure/reader.cljc index 522a27928a..513b8dfe90 100644 --- a/test/clojure/test_clojure/reader.cljc +++ b/test/clojure/test_clojure/reader.cljc @@ -428,8 +428,9 @@ (doseq [form top-levels] (clojure.walk/postwalk #(when (list? %) - (is (= (expected-metadata (first %)) - (meta %))) + (when (contains? expected-metadata (first %)) + (is (= (expected-metadata (first %)) + (meta %)))) (is (->> (meta %) vals (filter number?) From 213c50e7a34a27901b6db835b87f840a8b2a36ee Mon Sep 17 00:00:00 2001 From: JarrodCTaylor Date: Fri, 26 Jan 2024 13:22:37 -0600 Subject: [PATCH 174/285] clj-2803 update #inst printer to use thread safe java.time.format.DateTimeFormatter --- src/clj/clojure/instant.clj | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/clj/clojure/instant.clj b/src/clj/clojure/instant.clj index 2c052c03fa..3efc8b6026 100644 --- a/src/clj/clojure/instant.clj +++ b/src/clj/clojure/instant.clj @@ -159,22 +159,18 @@ with invalid arguments." ;;; ------------------------------------------------------------------------ ;;; print integration - -(def ^:private ^ThreadLocal thread-local-utc-date-format - ;; SimpleDateFormat is not thread-safe, so we use a ThreadLocal proxy for access. - ;; http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4228335 - (proxy [ThreadLocal] [] - (initialValue [] - (doto (java.text.SimpleDateFormat. "yyyy-MM-dd'T'HH:mm:ss.SSS-00:00") - ;; RFC3339 says to use -00:00 when the timezone is unknown (+00:00 implies a known GMT) - (.setTimeZone (java.util.TimeZone/getTimeZone "GMT")))))) +(def ^:private ^java.time.format.DateTimeFormatter UTC_DATE_FORMATTER + ;; RFC3339 says to use -00:00 when the timezone is unknown (+00:00 implies a known GMT) + (.withZone (java.time.format.DateTimeFormatter/ofPattern "yyyy-MM-dd'T'HH:mm:ss.SSS-00:00") + (java.time.ZoneId/of "GMT"))) (defn- print-date "Print a java.util.Date as RFC3339 timestamp, always in UTC." [^java.util.Date d, ^java.io.Writer w] - (let [^java.text.DateFormat utc-format (.get thread-local-utc-date-format)] + (let [instant (.toInstant d) + formatted-date (.format UTC_DATE_FORMATTER instant)] (.write w "#inst \"") - (.write w (.format utc-format d)) + (.write w formatted-date) (.write w "\""))) (defmethod print-method java.util.Date @@ -206,23 +202,19 @@ with invalid arguments." (print-calendar c w)) -(def ^:private ^ThreadLocal thread-local-utc-timestamp-format - ;; SimpleDateFormat is not thread-safe, so we use a ThreadLocal proxy for access. - ;; http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4228335 - (proxy [ThreadLocal] [] - (initialValue [] - (doto (java.text.SimpleDateFormat. "yyyy-MM-dd'T'HH:mm:ss") - (.setTimeZone (java.util.TimeZone/getTimeZone "GMT")))))) +(def ^:private ^java.time.format.DateTimeFormatter UTC_TIMESTAMP_FORMATTER + (.withZone (java.time.format.DateTimeFormatter/ofPattern "yyyy-MM-dd'T'HH:mm:ss.nnnnnnnnn") + (java.time.ZoneId/of "UTC"))) (defn- print-timestamp "Print a java.sql.Timestamp as RFC3339 timestamp, always in UTC." [^java.sql.Timestamp ts, ^java.io.Writer w] - (let [^java.text.DateFormat utc-format (.get thread-local-utc-timestamp-format)] + (let [instant (.toInstant ts) + formatted-date (.format UTC_TIMESTAMP_FORMATTER instant)] (.write w "#inst \"") - (.write w (.format utc-format ts)) - ;; add on nanos and offset + (.write w formatted-date) ;; RFC3339 says to use -00:00 when the timezone is unknown (+00:00 implies a known GMT) - (.write w (format ".%09d-00:00" (.getNanos ts))) + (.write w "-00:00") (.write w "\""))) (defmethod print-method java.sql.Timestamp @@ -292,3 +284,4 @@ fractional seconds with nanosecond precision. The timezone offset will be used to convert into UTC." [^CharSequence cs] (parse-timestamp (validated construct-timestamp) cs)) + From 92b8fc7769bdb3be1b572b4c0c879d5a968a2557 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 6 Jul 2021 13:44:15 -0500 Subject: [PATCH 175/285] CLJ-2640 ex-info does not fail on nil data --- src/jvm/clojure/lang/ExceptionInfo.java | 6 +----- test/clojure/test_clojure/errors.clj | 6 +++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/jvm/clojure/lang/ExceptionInfo.java b/src/jvm/clojure/lang/ExceptionInfo.java index f7b704deab..28f845b7c3 100644 --- a/src/jvm/clojure/lang/ExceptionInfo.java +++ b/src/jvm/clojure/lang/ExceptionInfo.java @@ -28,11 +28,7 @@ public ExceptionInfo(String s, IPersistentMap data) { public ExceptionInfo(String s, IPersistentMap data, Throwable throwable) { // null cause is equivalent to not passing a cause super(s, throwable); - if (data != null) { - this.data = data; - } else { - throw new IllegalArgumentException("Additional data must be non-nil."); - } + this.data = (data == null) ? PersistentArrayMap.EMPTY: data; } public IPersistentMap getData() { diff --git a/test/clojure/test_clojure/errors.clj b/test/clojure/test_clojure/errors.clj index cebe0392e3..0ee958786d 100644 --- a/test/clojure/test_clojure/errors.clj +++ b/test/clojure/test_clojure/errors.clj @@ -107,9 +107,9 @@ (with-out-str (pr t)) (catch Throwable t (is nil))))))) -(deftest ex-info-disallows-nil-data - (is (thrown? IllegalArgumentException (ex-info "message" nil))) - (is (thrown? IllegalArgumentException (ex-info "message" nil (Throwable. "cause"))))) +(deftest ex-info-allows-nil-data + (is (= {} (ex-data (ex-info "message" nil)))) + (is (= {} (ex-data (ex-info "message" nil (Throwable. "cause")))))) (deftest ex-info-arities-construct-equivalent-exceptions (let [ex1 (ex-info "message" {:foo "bar"}) From 39ac70c82ea0c2e5c15d992d319d65523bc60b59 Mon Sep 17 00:00:00 2001 From: JarrodCTaylor Date: Thu, 26 Oct 2023 16:06:50 -0500 Subject: [PATCH 176/285] CLJ-2777 Add :clear-env option to c.j.process/start --- src/clj/clojure/java/process.clj | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/clj/clojure/java/process.clj b/src/clj/clojure/java/process.clj index 74f87af7b6..5974f6325d 100644 --- a/src/clj/clojure/java/process.clj +++ b/src/clj/clojure/java/process.clj @@ -56,13 +56,17 @@ (ProcessBuilder$Redirect/from (jio/file f))) (defn start - "Starts an external command as args and optional leading opts map: + "Start an external command, defined in args. + The process environment vars are inherited from the parent by + default (use :clear-env to clear them). + If needed, provide options in map as first arg: :in - a ProcessBuilder.Redirect (default = :pipe) or :inherit :out - a ProcessBuilder.Redirect (default = :pipe) or :inherit :discard :err - a ProcessBuilder.Redirect (default = :pipe) or :inherit :discard :stdout - :dir - directory to run the command from, default=\".\" - :env - {env-var value} of environment variables (all strings) + :dir - current directory when the process runs (default=\".\") + :clear-env - if true, remove all inherited parent env vars + :env - {env-var value} of environment variables to set (all strings) Returns an ILookup containing the java.lang.Process in :process and the streams :in :out :err. The map is also an IDeref that waits for process exit @@ -72,7 +76,7 @@ (let [[opts command] (if (map? (first opts+args)) [(first opts+args) (rest opts+args)] [{} opts+args]) - {:keys [in out err dir env] + {:keys [in out err dir env clear-env] :or {in :pipe, out :pipe, err :pipe, dir "."}} opts pb (ProcessBuilder. ^List command) to-redirect (fn to-redirect @@ -89,6 +93,8 @@ (if (= err :stdout) (.redirectErrorStream pb true) (.redirectError pb ^ProcessBuilder$Redirect (to-redirect err))) + (when clear-env + (.clear (.environment pb))) (when env (let [pb-env (.environment pb)] (run! (fn [[k v]] (.put pb-env k v)) env))) From 882d660114c95b9959ee6124a0f1a420d19d8d4f Mon Sep 17 00:00:00 2001 From: JarrodCTaylor Date: Tue, 24 Oct 2023 17:05:45 -0500 Subject: [PATCH 177/285] CLJ-2783 Update deprecated process of creating URLs in Java 20+ --- src/clj/clojure/java/io.clj | 16 +++++++++------- src/clj/clojure/repl/deps.clj | 6 +++--- src/jvm/clojure/lang/RT.java | 18 ++++++++++++------ test/clojure/test_clojure/java/io.clj | 3 ++- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/clj/clojure/java/io.clj b/src/clj/clojure/java/io.clj index f0715abfd4..1f6d121bc1 100644 --- a/src/clj/clojure/java/io.clj +++ b/src/clj/clojure/java/io.clj @@ -12,6 +12,7 @@ clojure.java.io (:require clojure.string) (:import + (clojure.lang RT) (java.io Reader InputStream InputStreamReader PushbackReader BufferedReader File OutputStream OutputStreamWriter BufferedWriter Writer @@ -19,7 +20,8 @@ StringReader ByteArrayInputStream BufferedInputStream BufferedOutputStream CharArrayReader Closeable) - (java.net URI URL MalformedURLException Socket URLDecoder URLEncoder))) + (java.lang IllegalArgumentException) + (java.net URI URL Socket URLDecoder URLEncoder))) (set! *warn-on-reflection* true) @@ -50,11 +52,11 @@ String (as-file [s] (File. s)) - (as-url [s] (URL. s)) + (as-url [s] (RT/toUrl s)) File (as-file [f] f) - (as-url [f] (.toURL (.toURI f))) + (as-url [f] (RT/toUrl f)) URL (as-url [u] u) @@ -255,13 +257,13 @@ (assoc default-streams-impl :make-input-stream (fn [^String x opts] (try - (make-input-stream (URL. x) opts) - (catch MalformedURLException e + (make-input-stream (RT/toUrl x) opts) + (catch IllegalArgumentException e (make-input-stream (File. x) opts)))) :make-output-stream (fn [^String x opts] (try - (make-output-stream (URL. x) opts) - (catch MalformedURLException err + (make-output-stream (RT/toUrl x) opts) + (catch IllegalArgumentException err (make-output-stream (File. x) opts)))))) (extend Socket diff --git a/src/clj/clojure/repl/deps.clj b/src/clj/clojure/repl/deps.clj index 1ed8365a1c..dfd3137fcd 100644 --- a/src/clj/clojure/repl/deps.clj +++ b/src/clj/clojure/repl/deps.clj @@ -14,7 +14,7 @@ [clojure.java.basis.impl :as basis-impl] [clojure.tools.deps.interop :as tool]) (:import - [clojure.lang DynamicClassLoader] + [clojure.lang DynamicClassLoader RT] [java.io File])) (set! *warn-on-reflection* true) @@ -22,7 +22,7 @@ (defn- add-loader-url "Add url string or URL to the highest level DynamicClassLoader url set." [url] - (let [u (if (string? url) (java.net.URL. url) url) + (let [u (if (string? url) (RT/toUrl ^String url) url) loader (loop [loader (.getContextClassLoader (Thread/currentThread))] (let [parent (.getParent loader)] (if (instance? DynamicClassLoader parent) @@ -48,7 +48,7 @@ {:keys [added] :as _res} (tool/invoke-tool {:tool-alias :deps, :fn 'clojure.tools.deps/resolve-added-libs, :args tool-args}) ;_ (clojure.pprint/pprint _res) paths (mapcat :paths (vals added)) - urls (->> paths (map jio/file) (map #(.toURL ^File %)))] + urls (->> paths (map jio/file) (map #(RT/toUrl ^File %)))] (run! add-loader-url urls) (basis-impl/update-basis! update :libs merge added) (let [ret (-> added keys sort vec)] diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index 86c89d69fb..0ff3e50a2b 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -12,7 +12,7 @@ package clojure.lang; -import java.net.MalformedURLException; +import java.net.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.Callable; import java.util.*; @@ -20,14 +20,12 @@ import java.util.regex.Pattern; import java.io.*; import java.lang.reflect.Array; +import java.lang.IllegalArgumentException; import java.math.BigDecimal; import java.math.BigInteger; import java.security.AccessController; import java.security.PrivilegedAction; -import java.net.URL; -import java.net.JarURLConnection; import java.nio.charset.Charset; -import java.net.URLConnection; public class RT{ @@ -293,8 +291,16 @@ private Object readResolve() throws ObjectStreamException { static AtomicInteger id = new AtomicInteger(1); -static public void addURL(Object url) throws MalformedURLException{ - URL u = (url instanceof String) ? (new URL((String) url)) : (URL) url; +static public URL toUrl(String url) throws URISyntaxException, MalformedURLException { + return new URI(url).toURL(); +} + +static public URL toUrl(File file) throws MalformedURLException { + return file.toURI().toURL(); +} + +static public void addURL(Object url) throws MalformedURLException, URISyntaxException, IllegalArgumentException { + URL u = (url instanceof String) ? toUrl((String) url) : (URL) url; ClassLoader ccl = Thread.currentThread().getContextClassLoader(); if(ccl instanceof DynamicClassLoader) ((DynamicClassLoader)ccl).addURL(u); diff --git a/test/clojure/test_clojure/java/io.clj b/test/clojure/test_clojure/java/io.clj index b83c63d311..fb179e96da 100644 --- a/test/clojure/test_clojure/java/io.clj +++ b/test/clojure/test_clojure/java/io.clj @@ -13,6 +13,7 @@ FileInputStream InputStreamReader InputStream FileOutputStream OutputStreamWriter OutputStream ByteArrayInputStream ByteArrayOutputStream) + (clojure.lang RT) (java.net URL URI Socket ServerSocket))) (defn temp-file @@ -48,7 +49,7 @@ (slurp read-from :encoding "UTF-8"))) f f (.getAbsolutePath f) (.getAbsolutePath f) - (.toURL f) (.toURL f) + (RT/toUrl f) (RT/toUrl f) (.toURI f) (.toURI f) (FileOutputStream. f) (FileInputStream. f) (OutputStreamWriter. (FileOutputStream. f) "UTF-8") (reader f :encoding "UTF-8") From aa2c637f9512d14bd78ee30d6d030bba6d095e7d Mon Sep 17 00:00:00 2001 From: JarrodCTaylor Date: Thu, 25 Jan 2024 12:57:48 -0600 Subject: [PATCH 178/285] CLJ-2828 Remove capture function --- src/clj/clojure/java/process.clj | 22 +++++----------------- src/clj/clojure/tools/deps/interop.clj | 2 +- test/clojure/test_clojure/java/process.clj | 2 +- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/clj/clojure/java/process.clj b/src/clj/clojure/java/process.clj index 5974f6325d..4355e5ec65 100644 --- a/src/clj/clojure/java/process.clj +++ b/src/clj/clojure/java/process.clj @@ -14,10 +14,9 @@ (if available) and the Java Process object. It is also deref-able to wait for process exit. - Helper functions are available to 'capture' the output of the process stdout - and to wait for an 'ok?' non-error exit. The 'exec' function handles the common - case of `start'ing a process, waiting for process exit, capture and return - stdout." + Use ‘slurp' to capture the output of a process stream, and 'ok?’ to wait for a + non-error exit. The 'exec' function handles the common case of `start'ing a + process, waiting for process exit, slurp, and return stdout." (:require [clojure.java.io :as jio] [clojure.string :as str]) @@ -121,17 +120,6 @@ [process-map] (zero? (.waitFor ^Process (:process process-map)))) -(defn capture - "Read from input-stream until EOF and return a String (or nil if 0 length). - Takes same opts as clojure.java.io/copy - :buffer-size and :encoding" - {:added "1.12"} - [input-stream & opts] - (let [writer (StringWriter.)] - (apply jio/copy input-stream writer opts) - (let [s (str/trim (.toString writer))] - (when-not (zero? (.length s)) - s)))) - ;; A thread factory for daemon threads (defonce ^:private io-thread-factory (let [counter (atom 0)] @@ -177,7 +165,7 @@ [{} opts+args]) opts (merge {:err :inherit} opts)] (let [state (apply start opts command) - captured (io-task #(capture (:out state)))] + captured (io-task #(slurp (:out state)))] (if (ok? state) @captured (throw (RuntimeException. (str "Process failed with exit=" (.exitValue ^Process (:process state))))))))) @@ -190,7 +178,7 @@ @(start {:out (to-file "out") :err (to-file "err")} "ls" "-l") ;; capture output to string - (-> (start "ls" "-l") :out capture) + (-> (start "ls" "-l") :out slurp) ;; with exec (exec "ls" "-l") diff --git a/src/clj/clojure/tools/deps/interop.clj b/src/clj/clojure/tools/deps/interop.clj index 3d0bdf1d7a..25d0f2548d 100644 --- a/src/clj/clojure/tools/deps/interop.clj +++ b/src/clj/clojure/tools/deps/interop.clj @@ -39,7 +39,7 @@ (doseq [a args] (.write w (pr-str a)) (.write w " ")))) - (let [envelope (edn/read-string (proc/capture out))] + (let [envelope (edn/read-string (slurp out))] (if preserve-envelope envelope (let [{:keys [tag val]} envelope diff --git a/test/clojure/test_clojure/java/process.clj b/test/clojure/test_clojure/java/process.clj index 170e801cd1..a36f211681 100644 --- a/test/clojure/test_clojure/java/process.clj +++ b/test/clojure/test_clojure/java/process.clj @@ -17,7 +17,7 @@ (is (not (str/blank? (p/exec "bash" "-c" "ls")))) ;; print to stderr, capture nil - (is (nil? (p/exec "bash" "-c" "ls >&2"))) + (is (str/blank? (p/exec "bash" "-c" "ls >&2"))) ;; redirect, then capture to string (is (not (str/blank? (p/exec {:err :stdout} "bash" "-c" "ls >&2"))))) From 5c6c21688154bd8985610712c958359d774c75d0 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 24 Aug 2023 10:13:14 -0500 Subject: [PATCH 179/285] CLJ-2791 Implement spliterator on IPersistentVector --- src/jvm/clojure/lang/APersistentVector.java | 62 +++++++++++++++++ src/jvm/clojure/lang/PersistentVector.java | 73 +++++++++++++++++++++ test/clojure/test_clojure/vectors.clj | 64 +++++++++++++++++- 3 files changed, 198 insertions(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/APersistentVector.java b/src/jvm/clojure/lang/APersistentVector.java index 07115684aa..20c40918eb 100644 --- a/src/jvm/clojure/lang/APersistentVector.java +++ b/src/jvm/clojure/lang/APersistentVector.java @@ -14,6 +14,7 @@ import java.io.Serializable; import java.util.*; +import java.util.function.Consumer; public abstract class APersistentVector extends AFn implements IPersistentVector, Iterable, List, @@ -276,6 +277,62 @@ public void remove(){ }; } +Spliterator rangedSpliterator(final int start, final int end) { + return new Spliterator() { + int i = start; + + @Override + public int characteristics() { + return Spliterator.IMMUTABLE | // persistent + Spliterator.ORDERED | // know order + Spliterator.SIZED | // know size + Spliterator.SUBSIZED; // know size after split + } + + @Override + public long estimateSize() { + return end-i; + } + + @Override + public long getExactSizeIfKnown() { + return end-i; + } + + @Override + public boolean tryAdvance(Consumer action) { + if(i < end) { + action.accept(nth(i++)); + return true; + } + return false; + } + + @Override + public Spliterator trySplit() { + int lo = i; + int mid = (lo + end) >>> 1; // avoid overflow + if(lo >= mid) { + return null; + } else { + i = mid; + return rangedSpliterator(lo, mid); + } + } + + @Override + public void forEachRemaining(Consumer action) { + for(int x=i; x>> 1; // avoid overflow + if(lo >= mid) { + return null; + } else { + i = mid; + return rangedSpliterator(lo, mid); + } + } + + @Override + public void forEachRemaining(Consumer action) { + int x=i; + while(x 0) diff --git a/test/clojure/test_clojure/vectors.clj b/test/clojure/test_clojure/vectors.clj index ea2b8e77d5..97cc0c5add 100644 --- a/test/clojure/test_clojure/vectors.clj +++ b/test/clojure/test_clojure/vectors.clj @@ -9,7 +9,11 @@ ; Author: Stuart Halloway, Daniel Solano Gómez (ns clojure.test-clojure.vectors - (:use clojure.test)) + (:use clojure.test) + (:import + [java.util Collection Spliterator] + [java.util.function Consumer] + [java.util.stream Collectors])) (deftest test-reversed-vec (let [r (range 6) @@ -428,3 +432,61 @@ (is (= [0 1 2] (new java.util.ArrayList [0 1 2]))) (is (not= [1 2] (take 1 (cycle [1 2])))) (is (= [1 2 3 nil 4 5 6 nil] (eduction cat [[1 2 3 nil] [4 5 6 nil]])))) + +(set! *warn-on-reflection* true) + +;; remember returns a consumer that adds to an-atom of coll +(defn remember + ^Consumer [an-atom] + (reify Consumer (accept [_ v] (swap! an-atom conj v)))) + +(deftest test-empty-vector-spliterator + (let [v [] + s (.spliterator ^Collection v) + seen (atom [])] + (is (= 0 (.estimateSize s) (.getExactSizeIfKnown s))) + (is (nil? (.trySplit s))) + (is (false? (.tryAdvance s (remember seen)))) + (is (= @seen [])))) + +;; tryAdvance then forEachRemaining walks vector spliterator +(deftest test-spliterator-tryadvance-then-forEach + (let [n 66 + source-vec (vec (range n))] + (for [v (into [(vec (range n))] (map #(subvec source-vec % (+ % 33)) (range 33)))] + (dotimes [up-to n] + (let [s (.spliterator ^Collection v) + seen (atom []) + consumer (remember seen)] + (loop [i 0] + (if (< i up-to) + (do (is (true? (.tryAdvance s consumer))) (recur (inc i))) + (.forEachRemaining s consumer))) + (is (= v @seen)) + (is (false? (.tryAdvance s consumer)))))))) + +;; recursively split vector spliterators, walk all of the splits +(deftest test-spliterator-trySplit + (dotimes [n 257] + (let [v (vec (range n)) + seen (atom #{}) + consumer (remember seen) + splits (loop [ss [(.spliterator ^Collection v)]] + (let [ss' (map #(.trySplit ^Spliterator %) ss)] + (if (every? nil? ss') + ss + (recur (into ss (remove nil? ss'))))))] + (loop [[spl & sr] splits] + (when spl + (.forEachRemaining ^Spliterator spl consumer) + (recur sr))) + (is (= v (sort @seen)))))) + +(deftest test-vector-parallel-stream + (dotimes [n 1024] + (let [v (vec (range n))] + (is (= n + (-> ^Collection v .stream (.collect (Collectors/counting))) + (-> ^Collection v .parallelStream (.collect (Collectors/counting))) + (-> v ^Collection (subvec 0 n) .stream (.collect (Collectors/counting))) + (-> v ^Collection (subvec 0 n) .parallelStream (.collect (Collectors/counting)))))))) \ No newline at end of file From a0573522e7c5e5d0fd281eefd3d7d6686935b5cb Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 6 Sep 2023 18:50:03 -0500 Subject: [PATCH 180/285] CLJ-2792 Make IDeref extend Supplier interfaces and provide default methods --- src/jvm/clojure/lang/IDeref.java | 28 +++++++++++++++++++++++++++- test/clojure/test_clojure/atoms.clj | 16 ++++++++++++++++ test/clojure/test_clojure/delays.clj | 20 ++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/IDeref.java b/src/jvm/clojure/lang/IDeref.java index 3a4746157b..41002f8ae1 100644 --- a/src/jvm/clojure/lang/IDeref.java +++ b/src/jvm/clojure/lang/IDeref.java @@ -12,6 +12,32 @@ package clojure.lang; -public interface IDeref{ +import java.util.function.BooleanSupplier; +import java.util.function.IntSupplier; +import java.util.function.LongSupplier; +import java.util.function.Supplier; + +public interface IDeref extends Supplier, BooleanSupplier, IntSupplier, LongSupplier { Object deref() ; + +@Override +default Object get() { + return deref(); +} + +@Override +default boolean getAsBoolean() { + return RT.booleanCast(deref()); +} + +@Override +default int getAsInt() { + return RT.intCast(deref()); +} + +@Override +default long getAsLong() { + return RT.longCast(deref()); +} + } diff --git a/test/clojure/test_clojure/atoms.clj b/test/clojure/test_clojure/atoms.clj index f9ecadcc56..2e6974ef03 100644 --- a/test/clojure/test_clojure/atoms.clj +++ b/test/clojure/test_clojure/atoms.clj @@ -42,3 +42,19 @@ (deftest reset-on-deref-reset-equality (let [a (atom :usual-value)] (is (= :usual-value (reset! a (first (reset-vals! a :almost-never-seen-value))))))) + +(deftest atoms-are-suppliers + (let [a (atom 10)] + (is (instance? java.util.function.Supplier a)) + (is (= 10 (.get ^java.util.function.Supplier a))) + (swap! a inc) + (is (= 11 (.get ^java.util.function.Supplier a))) + + (is (instance? java.util.function.IntSupplier a)) + (is (= 11 (.getAsInt a))) + + (is (instance? java.util.function.LongSupplier a)) + (is (= 11 (.getAsLong a))) + + (is (instance? java.util.function.BooleanSupplier a)) + (is (true? (.getAsBoolean a))))) \ No newline at end of file diff --git a/test/clojure/test_clojure/delays.clj b/test/clojure/test_clojure/delays.clj index 0a2a1c99ff..477ab99af6 100644 --- a/test/clojure/test_clojure/delays.clj +++ b/test/clojure/test_clojure/delays.clj @@ -66,3 +66,23 @@ (.await barrier) (is (instance? Exception (try-call))) (is (identical? (try-call) (try-call))))) + +(deftest delays-are-suppliers + (let [dt (delay true) + df (delay false) + dn (delay nil) + di (delay 100)] + + (is (instance? java.util.function.Supplier dt)) + (is (instance? java.util.function.BooleanSupplier dt)) + (is (true? (.get dt))) + (is (true? (.getAsBoolean dt))) + (is (false? (.getAsBoolean df))) + (is (false? (.getAsBoolean dn))) + + (is (instance? java.util.function.Supplier di)) + (is (instance? java.util.function.IntSupplier di)) + (is (instance? java.util.function.LongSupplier di)) + (is (= 100 (.get ^java.util.function.Supplier di))) + (is (= 100 (.getAsInt ^java.util.function.IntSupplier di))) + (is (= 100 (.getAsLong ^java.util.function.LongSupplier di))))) \ No newline at end of file From 96c6f816ade9da63243ef6f55ace96bf15c275a8 Mon Sep 17 00:00:00 2001 From: Fogus Date: Thu, 1 Feb 2024 06:15:55 -0600 Subject: [PATCH 181/285] CLJ-2290: Modified into docstring to mention 0 and 1-arities. --- src/clj/clojure/core.clj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index ebca84d40c..21e5c2c0a8 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -7008,8 +7008,9 @@ fails, attempts to require sym's namespace and retries." (f ret)))) (defn into - "Returns a new coll consisting of to-coll with all of the items of - from-coll conjoined. A transducer may be supplied." + "Returns a new coll consisting of to with all of the items of + from conjoined. A transducer may be supplied. + (into x) returns x. (into) returns []." {:added "1.0" :static true} ([] []) From dbaa1898adc82abaefb914277c791a2f8f97ef53 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 23 Oct 2023 14:01:56 -0500 Subject: [PATCH 182/285] CLJ-2225 Improve docstrings of assert and *assert* --- src/clj/clojure/core.clj | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 21e5c2c0a8..d560f67d57 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -4853,8 +4853,11 @@ (.getCause ^Throwable ex))) (defmacro assert - "Evaluates expr and throws an exception if it does not evaluate to - logical true." + "Evaluates expression x and throws an AssertionError with optional + message if x does not evaluate to logical true. + + Assertion checks are omitted from compiled code if '*assert*' is + false." {:added "1.0"} ([x] (when *assert* @@ -6587,6 +6590,11 @@ fails, attempts to require sym's namespace and retries." " {:added "1.0"}) +(add-doc-and-meta *assert* + "When set to logical false, 'assert' will omit assertion checks in + compiled code. Defaults to true." + {:added "1.0"}) + (defn future? "Returns true if x is a future" {:added "1.1" From 51d0c55ecc87bb79e7110b5f9162ef9d4adb734d Mon Sep 17 00:00:00 2001 From: Ambrose Bonnaire-Sergeant Date: Fri, 26 Jan 2024 13:10:24 -0600 Subject: [PATCH 183/285] CLJ-2552: Fix example code and improve recur description in reify docstring --- src/clj/clojure/core_deftype.clj | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/clj/clojure/core_deftype.clj b/src/clj/clojure/core_deftype.clj index c2babab291..17fce7012d 100644 --- a/src/clj/clojure/core_deftype.clj +++ b/src/clj/clojure/core_deftype.clj @@ -101,18 +101,19 @@ same arity in an interface you must specify complete hints to disambiguate - a missing hint implies Object. - recur works to method heads The method bodies of reify are lexical - closures, and can refer to the surrounding local scope: + Method heads are recursion points for recur, as in a fn. The method + bodies of reify are lexical closures, and can refer to the surrounding + local scope: (str (let [f \"foo\"] - (reify Object - (toString [this] f)))) + (reify Object + (toString [this] f)))) == \"foo\" (seq (let [f \"foo\"] - (reify clojure.lang.Seqable - (seq [this] (seq f))))) - == (\\f \\o \\o)) + (reify clojure.lang.Seqable + (seq [this] (seq f))))) + == (\\f \\o \\o) reify always implements clojure.lang.IObj and transfers meta data of the form to the created object. From 68a53fad91071f551065d5387c21b5997ebc8c06 Mon Sep 17 00:00:00 2001 From: Christophe Grand Date: Wed, 15 Nov 2023 12:49:10 -0600 Subject: [PATCH 184/285] CLJ-2813 Anonymous args accept non-integers, also allows discarded content --- src/jvm/clojure/lang/LispReader.java | 24 +++++++++--------------- test/clojure/test_clojure/reader.cljc | 21 ++++++++++++++++++++- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/jvm/clojure/lang/LispReader.java b/src/jvm/clojure/lang/LispReader.java index 104b05d1a2..995e21be15 100644 --- a/src/jvm/clojure/lang/LispReader.java +++ b/src/jvm/clojure/lang/LispReader.java @@ -71,6 +71,7 @@ public class LispReader{ "([-+]?)(?:(0)|([1-9][0-9]*)|0[xX]([0-9A-Fa-f]+)|0([0-7]+)|([1-9][0-9]?)[rR]([0-9A-Za-z]+)|0[0-9]+)(N)?"); static Pattern ratioPat = Pattern.compile("([-+]?[0-9]+)/([0-9]+)"); static Pattern floatPat = Pattern.compile("([-+]?[0-9]+(\\.[0-9]*)?([eE][-+]?[0-9]+)?)(M)?"); +static Pattern argPat = Pattern.compile("%(?:(&)|([1-9][0-9]*))?"); //static Pattern accessorPat = Pattern.compile("\\.[a-zA-Z_]\\w*"); //static Pattern instanceMemberPat = Pattern.compile("\\.([a-zA-Z_][\\w\\.]*)\\.([a-zA-Z_]\\w*)"); //static Pattern staticMemberPat = Pattern.compile("([a-zA-Z_][\\w\\.]*)\\.([a-zA-Z_]\\w*)"); @@ -920,23 +921,16 @@ static Symbol registerArg(int n){ static class ArgReader extends AFn{ public Object invoke(Object reader, Object pct, Object opts, Object pendingForms) { PushbackReader r = (PushbackReader) reader; + String token = readToken(r, '%'); if(ARG_ENV.deref() == null) - { - return interpretToken(readToken(r, '%'), null); - } - int ch = read1(r); - unread(r, ch); - //% alone is first arg - if(ch == -1 || isWhitespace(ch) || isTerminatingMacro(ch)) - { - return registerArg(1); - } - Object n = read(r, true, null, true, opts, ensurePending(pendingForms)); - if(n.equals(Compiler._AMP_)) - return registerArg(-1); - if(!(n instanceof Number)) + return interpretToken(token, null); + + Matcher m = argPat.matcher(token); + if (!m.matches()) throw new IllegalStateException("arg literal must be %, %& or %integer"); - return registerArg(((Number) n).intValue()); + if (m.group(1) != null) // %& + return registerArg(-1); + return registerArg(m.group(2) == null ? 1 : Integer.parseInt(m.group(2))); } } diff --git a/test/clojure/test_clojure/reader.cljc b/test/clojure/test_clojure/reader.cljc index 513b8dfe90..a0e1f1f13e 100644 --- a/test/clojure/test_clojure/reader.cljc +++ b/test/clojure/test_clojure/reader.cljc @@ -454,7 +454,26 @@ ;; Anonymous function literal (#()) -(deftest t-Anonymouns-function-literal) +(deftest t-Anonymous-function-literal + ;; #(vector %) => #(fn* [gen__#] (vector gen__#)) + ;; [\S]+ matches the anon arg, then \1 is backref matching first group + (is (= "(fn* [] (vector))" (pr-str (read-string "#(vector)")))) + (is (not (nil? (re-matches #"\(fn\* \[([\S]+)] \(vector \1\)\)" (pr-str (read-string "#(vector %)")))))) + (is (not (nil? (re-matches #"\(fn\* \[([\S]+)] \(vector \1 \1\)\)" (pr-str (read-string "#(vector % %)")))))) + (is (not (nil? (re-matches #"\(fn\* \[([\S]+)] \(vector \1 \1\)\)" (pr-str (read-string "#(vector % %1)")))))) + (is (not (nil? (re-matches #"\(fn\* \[([\S]+) ([\S]+)] \(vector \1 \2\)\)" (pr-str (read-string "#(vector %1 %2)")))))) + (is (not (nil? (re-matches #"\(fn\* \[([\S]+) ([\S]+) & ([\S]+)] \(vector \2 \3\)\)" (pr-str (read-string "#(vector %2 %&)")))))) + + ;; invalid formats + (is (thrown? RuntimeException (read-string "#(vector %%)"))) + (is (thrown? RuntimeException (read-string "#(vector %1/2)"))) + (is (thrown? RuntimeException (read-string "#(vector %1.5)"))) + (is (thrown? RuntimeException (read-string "#(vector %-0.2)"))) + (is (thrown? RuntimeException (read-string "#(vector %3M)"))) + + ;; check sneaking in discarded content + (is (thrown? RuntimeException (read-string "#(list %#_(first arg)1.00000001 %#_(secong arg)2r10 %#_(rest arg)-1.5)"))) + ) ;; Syntax-quote (`, note, the "backquote" character), Unquote (~) and ;; Unquote-splicing (~@) From 838783effed26b4779454faaa0e953912a6ab74f Mon Sep 17 00:00:00 2001 From: JarrodCTaylor Date: Fri, 20 Oct 2023 15:12:46 -0500 Subject: [PATCH 185/285] CLJ-1162 Improved error message from invalid deref --- src/clj/clojure/core.clj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index d560f67d57..6d8f24cbdd 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -2333,13 +2333,13 @@ value is available. See also - realized?." {:added "1.0" :static true} - ([ref] (if (instance? clojure.lang.IDeref ref) - (.deref ^clojure.lang.IDeref ref) - (deref-future ref))) + ([ref] (if (instance? java.util.concurrent.Future ref) + (deref-future ref) + (.deref ^clojure.lang.IDeref ref))) ([ref timeout-ms timeout-val] - (if (instance? clojure.lang.IBlockingDeref ref) - (.deref ^clojure.lang.IBlockingDeref ref timeout-ms timeout-val) - (deref-future ref timeout-ms timeout-val)))) + (if (instance? java.util.concurrent.Future ref) + (deref-future ref timeout-ms timeout-val) + (.deref ^clojure.lang.IBlockingDeref ref timeout-ms timeout-val)))) (defn atom "Creates and returns an Atom with an initial value of x and zero or From 00bf414696223354ea9d6c5f2e8e8142707f241b Mon Sep 17 00:00:00 2001 From: fogus Date: Thu, 8 Feb 2024 15:13:24 -0600 Subject: [PATCH 186/285] CLJ-2788: Added bindings around the io-task for invoke-task to set print bindings to non-truncating values and non-namespaced maps --- src/clj/clojure/tools/deps/interop.clj | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/clj/clojure/tools/deps/interop.clj b/src/clj/clojure/tools/deps/interop.clj index 25d0f2548d..0fd5869948 100644 --- a/src/clj/clojure/tools/deps/interop.clj +++ b/src/clj/clojure/tools/deps/interop.clj @@ -34,11 +34,14 @@ command-strs [command (str "-T" (or tool-alias tool-name)) "-"] _ (when (:debug opts) (apply println "Invoking: " command-strs)) {:keys [in out]} (apply proc/start command-strs)] - (proc/io-task - #(with-open [w (jio/writer in)] - (doseq [a args] - (.write w (pr-str a)) - (.write w " ")))) + (binding [*print-length* nil + *print-level* nil + *print-namespace-maps* false] + (proc/io-task + #(with-open [w (jio/writer in)] + (doseq [a args] + (.write w (pr-str a)) + (.write w " "))))) (let [envelope (edn/read-string (slurp out))] (if preserve-envelope envelope From e58aaef8b6790769b6950b32fbddb8cabb707747 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 8 Feb 2024 15:42:00 -0600 Subject: [PATCH 187/285] Revert "CLJ-2568 clojure.walk now retains metadata when walking lists and seqs" This reverts commit 8895fef132bd064032e737e55d54d9ba2c07a0c6. --- src/clj/clojure/walk.clj | 4 ++-- test/clojure/test_clojure/clojure_walk.clj | 11 ----------- test/clojure/test_clojure/reader.cljc | 5 ++--- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/clj/clojure/walk.clj b/src/clj/clojure/walk.clj index 0f027e7ad0..fe8fb631bd 100644 --- a/src/clj/clojure/walk.clj +++ b/src/clj/clojure/walk.clj @@ -41,10 +41,10 @@ the sorting function."} {:added "1.1"} [inner outer form] (cond - (list? form) (outer (with-meta (apply list (map inner form)) (meta form))) + (list? form) (outer (apply list (map inner form))) (instance? clojure.lang.IMapEntry form) (outer (clojure.lang.MapEntry/create (inner (key form)) (inner (val form)))) - (seq? form) (outer (with-meta (doall (map inner form)) (meta form))) + (seq? form) (outer (doall (map inner form))) (instance? clojure.lang.IRecord form) (outer (reduce (fn [r x] (conj r (inner x))) form form)) (coll? form) (outer (into (empty form) (map inner form))) diff --git a/test/clojure/test_clojure/clojure_walk.clj b/test/clojure/test_clojure/clojure_walk.clj index fa2f3e6492..6c6f866332 100644 --- a/test/clojure/test_clojure/clojure_walk.clj +++ b/test/clojure/test_clojure/clojure_walk.clj @@ -63,14 +63,3 @@ (let [coll [:html {:a ["b" 1]} ""] f (fn [e] (if (and (vector? e) (not (map-entry? e))) (apply list e) e))] (is (= (list :html {:a (list "b" 1)} "") (w/postwalk f coll))))) - -(defrecord RM [a]) -(deftest retain-meta - (let [m {:foo true}] - (are [o] (= m (meta (w/postwalk identity (with-meta o m)))) - '(1 2) - [1 2] - #{1 2} - {1 2} - (map inc (range 3)) - (->RM 1)))) \ No newline at end of file diff --git a/test/clojure/test_clojure/reader.cljc b/test/clojure/test_clojure/reader.cljc index a0e1f1f13e..e5fcf5d533 100644 --- a/test/clojure/test_clojure/reader.cljc +++ b/test/clojure/test_clojure/reader.cljc @@ -428,9 +428,8 @@ (doseq [form top-levels] (clojure.walk/postwalk #(when (list? %) - (when (contains? expected-metadata (first %)) - (is (= (expected-metadata (first %)) - (meta %)))) + (is (= (expected-metadata (first %)) + (meta %))) (is (->> (meta %) vals (filter number?) From 28c69862bdb9528468f5cbdb684a721cf5b92ad1 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Thu, 8 Feb 2024 21:53:41 +0000 Subject: [PATCH 188/285] [maven-release-plugin] prepare release clojure-1.12.0-alpha6 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2dd37faaad..79049ae7e2 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0-alpha6 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0-alpha6 From b56f95197e1dcfacf7c245fb68a10daae1952be2 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Thu, 8 Feb 2024 21:53:41 +0000 Subject: [PATCH 189/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 79049ae7e2..2dd37faaad 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-alpha6 + 1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0-alpha6 + HEAD From e3520c07e8b21dbf5a91fa14b7114b90dc1e89c6 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 8 Feb 2024 19:39:55 -0600 Subject: [PATCH 190/285] Revert "CLJ-2783 Update deprecated process of creating URLs in Java 20+" This reverts commit 882d660114c95b9959ee6124a0f1a420d19d8d4f. --- src/clj/clojure/java/io.clj | 16 +++++++--------- src/clj/clojure/repl/deps.clj | 6 +++--- src/jvm/clojure/lang/RT.java | 18 ++++++------------ test/clojure/test_clojure/java/io.clj | 3 +-- 4 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/clj/clojure/java/io.clj b/src/clj/clojure/java/io.clj index 1f6d121bc1..f0715abfd4 100644 --- a/src/clj/clojure/java/io.clj +++ b/src/clj/clojure/java/io.clj @@ -12,7 +12,6 @@ clojure.java.io (:require clojure.string) (:import - (clojure.lang RT) (java.io Reader InputStream InputStreamReader PushbackReader BufferedReader File OutputStream OutputStreamWriter BufferedWriter Writer @@ -20,8 +19,7 @@ StringReader ByteArrayInputStream BufferedInputStream BufferedOutputStream CharArrayReader Closeable) - (java.lang IllegalArgumentException) - (java.net URI URL Socket URLDecoder URLEncoder))) + (java.net URI URL MalformedURLException Socket URLDecoder URLEncoder))) (set! *warn-on-reflection* true) @@ -52,11 +50,11 @@ String (as-file [s] (File. s)) - (as-url [s] (RT/toUrl s)) + (as-url [s] (URL. s)) File (as-file [f] f) - (as-url [f] (RT/toUrl f)) + (as-url [f] (.toURL (.toURI f))) URL (as-url [u] u) @@ -257,13 +255,13 @@ (assoc default-streams-impl :make-input-stream (fn [^String x opts] (try - (make-input-stream (RT/toUrl x) opts) - (catch IllegalArgumentException e + (make-input-stream (URL. x) opts) + (catch MalformedURLException e (make-input-stream (File. x) opts)))) :make-output-stream (fn [^String x opts] (try - (make-output-stream (RT/toUrl x) opts) - (catch IllegalArgumentException err + (make-output-stream (URL. x) opts) + (catch MalformedURLException err (make-output-stream (File. x) opts)))))) (extend Socket diff --git a/src/clj/clojure/repl/deps.clj b/src/clj/clojure/repl/deps.clj index dfd3137fcd..1ed8365a1c 100644 --- a/src/clj/clojure/repl/deps.clj +++ b/src/clj/clojure/repl/deps.clj @@ -14,7 +14,7 @@ [clojure.java.basis.impl :as basis-impl] [clojure.tools.deps.interop :as tool]) (:import - [clojure.lang DynamicClassLoader RT] + [clojure.lang DynamicClassLoader] [java.io File])) (set! *warn-on-reflection* true) @@ -22,7 +22,7 @@ (defn- add-loader-url "Add url string or URL to the highest level DynamicClassLoader url set." [url] - (let [u (if (string? url) (RT/toUrl ^String url) url) + (let [u (if (string? url) (java.net.URL. url) url) loader (loop [loader (.getContextClassLoader (Thread/currentThread))] (let [parent (.getParent loader)] (if (instance? DynamicClassLoader parent) @@ -48,7 +48,7 @@ {:keys [added] :as _res} (tool/invoke-tool {:tool-alias :deps, :fn 'clojure.tools.deps/resolve-added-libs, :args tool-args}) ;_ (clojure.pprint/pprint _res) paths (mapcat :paths (vals added)) - urls (->> paths (map jio/file) (map #(RT/toUrl ^File %)))] + urls (->> paths (map jio/file) (map #(.toURL ^File %)))] (run! add-loader-url urls) (basis-impl/update-basis! update :libs merge added) (let [ret (-> added keys sort vec)] diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index 0ff3e50a2b..86c89d69fb 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -12,7 +12,7 @@ package clojure.lang; -import java.net.*; +import java.net.MalformedURLException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.Callable; import java.util.*; @@ -20,12 +20,14 @@ import java.util.regex.Pattern; import java.io.*; import java.lang.reflect.Array; -import java.lang.IllegalArgumentException; import java.math.BigDecimal; import java.math.BigInteger; import java.security.AccessController; import java.security.PrivilegedAction; +import java.net.URL; +import java.net.JarURLConnection; import java.nio.charset.Charset; +import java.net.URLConnection; public class RT{ @@ -291,16 +293,8 @@ private Object readResolve() throws ObjectStreamException { static AtomicInteger id = new AtomicInteger(1); -static public URL toUrl(String url) throws URISyntaxException, MalformedURLException { - return new URI(url).toURL(); -} - -static public URL toUrl(File file) throws MalformedURLException { - return file.toURI().toURL(); -} - -static public void addURL(Object url) throws MalformedURLException, URISyntaxException, IllegalArgumentException { - URL u = (url instanceof String) ? toUrl((String) url) : (URL) url; +static public void addURL(Object url) throws MalformedURLException{ + URL u = (url instanceof String) ? (new URL((String) url)) : (URL) url; ClassLoader ccl = Thread.currentThread().getContextClassLoader(); if(ccl instanceof DynamicClassLoader) ((DynamicClassLoader)ccl).addURL(u); diff --git a/test/clojure/test_clojure/java/io.clj b/test/clojure/test_clojure/java/io.clj index fb179e96da..b83c63d311 100644 --- a/test/clojure/test_clojure/java/io.clj +++ b/test/clojure/test_clojure/java/io.clj @@ -13,7 +13,6 @@ FileInputStream InputStreamReader InputStream FileOutputStream OutputStreamWriter OutputStream ByteArrayInputStream ByteArrayOutputStream) - (clojure.lang RT) (java.net URL URI Socket ServerSocket))) (defn temp-file @@ -49,7 +48,7 @@ (slurp read-from :encoding "UTF-8"))) f f (.getAbsolutePath f) (.getAbsolutePath f) - (RT/toUrl f) (RT/toUrl f) + (.toURL f) (.toURL f) (.toURI f) (.toURI f) (FileOutputStream. f) (FileInputStream. f) (OutputStreamWriter. (FileOutputStream. f) "UTF-8") (reader f :encoding "UTF-8") From 64382fe41573b0faf296129e6c4b626535c2eda6 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 21 Feb 2024 10:27:50 -0600 Subject: [PATCH 191/285] Revert "CLJ-1162 Improved error message from invalid deref" This reverts commit 838783effed26b4779454faaa0e953912a6ab74f. --- src/clj/clojure/core.clj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 6d8f24cbdd..d560f67d57 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -2333,13 +2333,13 @@ value is available. See also - realized?." {:added "1.0" :static true} - ([ref] (if (instance? java.util.concurrent.Future ref) - (deref-future ref) - (.deref ^clojure.lang.IDeref ref))) + ([ref] (if (instance? clojure.lang.IDeref ref) + (.deref ^clojure.lang.IDeref ref) + (deref-future ref))) ([ref timeout-ms timeout-val] - (if (instance? java.util.concurrent.Future ref) - (deref-future ref timeout-ms timeout-val) - (.deref ^clojure.lang.IBlockingDeref ref timeout-ms timeout-val)))) + (if (instance? clojure.lang.IBlockingDeref ref) + (.deref ^clojure.lang.IBlockingDeref ref timeout-ms timeout-val) + (deref-future ref timeout-ms timeout-val)))) (defn atom "Creates and returns an Atom with an initial value of x and zero or From 089f27f9fc881674e565f1ffcbe2f8a616726c3b Mon Sep 17 00:00:00 2001 From: JarrodCTaylor Date: Tue, 13 Feb 2024 14:04:08 -0600 Subject: [PATCH 192/285] CLJ-2783 Update deprecated process of creating URLs in Java 20+ --- src/clj/clojure/java/io.clj | 9 +++++---- src/clj/clojure/repl/deps.clj | 6 +++--- src/jvm/clojure/lang/RT.java | 21 ++++++++++++++++++++- test/clojure/test_clojure/java/io.clj | 6 +++++- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/clj/clojure/java/io.clj b/src/clj/clojure/java/io.clj index f0715abfd4..5b96664e01 100644 --- a/src/clj/clojure/java/io.clj +++ b/src/clj/clojure/java/io.clj @@ -19,6 +19,7 @@ StringReader ByteArrayInputStream BufferedInputStream BufferedOutputStream CharArrayReader Closeable) + (clojure.lang RT) (java.net URI URL MalformedURLException Socket URLDecoder URLEncoder))) (set! *warn-on-reflection* true) @@ -50,11 +51,11 @@ String (as-file [s] (File. s)) - (as-url [s] (URL. s)) + (as-url [s] (RT/toUrl s)) File (as-file [f] f) - (as-url [f] (.toURL (.toURI f))) + (as-url [f] (RT/toUrl f)) URL (as-url [u] u) @@ -255,12 +256,12 @@ (assoc default-streams-impl :make-input-stream (fn [^String x opts] (try - (make-input-stream (URL. x) opts) + (make-input-stream (RT/toUrl x) opts) (catch MalformedURLException e (make-input-stream (File. x) opts)))) :make-output-stream (fn [^String x opts] (try - (make-output-stream (URL. x) opts) + (make-output-stream (RT/toUrl x) opts) (catch MalformedURLException err (make-output-stream (File. x) opts)))))) diff --git a/src/clj/clojure/repl/deps.clj b/src/clj/clojure/repl/deps.clj index 1ed8365a1c..dfd3137fcd 100644 --- a/src/clj/clojure/repl/deps.clj +++ b/src/clj/clojure/repl/deps.clj @@ -14,7 +14,7 @@ [clojure.java.basis.impl :as basis-impl] [clojure.tools.deps.interop :as tool]) (:import - [clojure.lang DynamicClassLoader] + [clojure.lang DynamicClassLoader RT] [java.io File])) (set! *warn-on-reflection* true) @@ -22,7 +22,7 @@ (defn- add-loader-url "Add url string or URL to the highest level DynamicClassLoader url set." [url] - (let [u (if (string? url) (java.net.URL. url) url) + (let [u (if (string? url) (RT/toUrl ^String url) url) loader (loop [loader (.getContextClassLoader (Thread/currentThread))] (let [parent (.getParent loader)] (if (instance? DynamicClassLoader parent) @@ -48,7 +48,7 @@ {:keys [added] :as _res} (tool/invoke-tool {:tool-alias :deps, :fn 'clojure.tools.deps/resolve-added-libs, :args tool-args}) ;_ (clojure.pprint/pprint _res) paths (mapcat :paths (vals added)) - urls (->> paths (map jio/file) (map #(.toURL ^File %)))] + urls (->> paths (map jio/file) (map #(RT/toUrl ^File %)))] (run! add-loader-url urls) (basis-impl/update-basis! update :libs merge added) (let [ret (-> added keys sort vec)] diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index 86c89d69fb..d56023a063 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -13,6 +13,8 @@ package clojure.lang; import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URI; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.Callable; import java.util.*; @@ -20,6 +22,7 @@ import java.util.regex.Pattern; import java.io.*; import java.lang.reflect.Array; +import java.lang.IllegalArgumentException; import java.math.BigDecimal; import java.math.BigInteger; import java.security.AccessController; @@ -293,8 +296,24 @@ private Object readResolve() throws ObjectStreamException { static AtomicInteger id = new AtomicInteger(1); +static public URL toUrl(String url) throws MalformedURLException { + try { + return new URI(url).toURL(); + } catch (URISyntaxException | IllegalArgumentException e) { + // Maintain backward compatibility with error + // thrown from now deprecated java.net.URL + MalformedURLException ex = new MalformedURLException(); + ex.initCause(e); + throw ex; + } +} + +static public URL toUrl(File file) throws MalformedURLException { + return file.toURI().toURL(); +} + static public void addURL(Object url) throws MalformedURLException{ - URL u = (url instanceof String) ? (new URL((String) url)) : (URL) url; + URL u = (url instanceof String) ? toUrl((String) url) : (URL) url; ClassLoader ccl = Thread.currentThread().getContextClassLoader(); if(ccl instanceof DynamicClassLoader) ((DynamicClassLoader)ccl).addURL(u); diff --git a/test/clojure/test_clojure/java/io.clj b/test/clojure/test_clojure/java/io.clj index b83c63d311..78864220d6 100644 --- a/test/clojure/test_clojure/java/io.clj +++ b/test/clojure/test_clojure/java/io.clj @@ -13,6 +13,7 @@ FileInputStream InputStreamReader InputStream FileOutputStream OutputStreamWriter OutputStream ByteArrayInputStream ByteArrayOutputStream) + (clojure.lang RT) (java.net URL URI Socket ServerSocket))) (defn temp-file @@ -48,7 +49,7 @@ (slurp read-from :encoding "UTF-8"))) f f (.getAbsolutePath f) (.getAbsolutePath f) - (.toURL f) (.toURL f) + (RT/toUrl f) (RT/toUrl f) (.toURI f) (.toURI f) (FileOutputStream. f) (FileInputStream. f) (OutputStreamWriter. (FileOutputStream. f) "UTF-8") (reader f :encoding "UTF-8") @@ -60,6 +61,9 @@ (finally (.delete f))))) +(deftest clj-2783-slurp-maintains-backward-compatibility-errors + (is (thrown? java.io.FileNotFoundException (slurp "whitespace = #'\\s+'")))) + (deftest test-streams-nil (is (thrown-with-msg? IllegalArgumentException #"Cannot open.*nil" (reader nil))) (is (thrown-with-msg? IllegalArgumentException #"Cannot open.*nil" (writer nil))) From 4dbdcb1fe8128620162839a60192d899eb3c83f7 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 13 Feb 2024 15:38:02 -0600 Subject: [PATCH 193/285] CLJ-2568 clojure.walk now retains metadata when walking lists and seqs --- src/clj/clojure/walk.clj | 4 ++-- test/clojure/test_clojure/clojure_walk.clj | 11 +++++++++++ test/clojure/test_clojure/printer.clj | 5 +++-- test/clojure/test_clojure/reader.cljc | 5 +++-- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/clj/clojure/walk.clj b/src/clj/clojure/walk.clj index fe8fb631bd..0f027e7ad0 100644 --- a/src/clj/clojure/walk.clj +++ b/src/clj/clojure/walk.clj @@ -41,10 +41,10 @@ the sorting function."} {:added "1.1"} [inner outer form] (cond - (list? form) (outer (apply list (map inner form))) + (list? form) (outer (with-meta (apply list (map inner form)) (meta form))) (instance? clojure.lang.IMapEntry form) (outer (clojure.lang.MapEntry/create (inner (key form)) (inner (val form)))) - (seq? form) (outer (doall (map inner form))) + (seq? form) (outer (with-meta (doall (map inner form)) (meta form))) (instance? clojure.lang.IRecord form) (outer (reduce (fn [r x] (conj r (inner x))) form form)) (coll? form) (outer (into (empty form) (map inner form))) diff --git a/test/clojure/test_clojure/clojure_walk.clj b/test/clojure/test_clojure/clojure_walk.clj index 6c6f866332..fa2f3e6492 100644 --- a/test/clojure/test_clojure/clojure_walk.clj +++ b/test/clojure/test_clojure/clojure_walk.clj @@ -63,3 +63,14 @@ (let [coll [:html {:a ["b" 1]} ""] f (fn [e] (if (and (vector? e) (not (map-entry? e))) (apply list e) e))] (is (= (list :html {:a (list "b" 1)} "") (w/postwalk f coll))))) + +(defrecord RM [a]) +(deftest retain-meta + (let [m {:foo true}] + (are [o] (= m (meta (w/postwalk identity (with-meta o m)))) + '(1 2) + [1 2] + #{1 2} + {1 2} + (map inc (range 3)) + (->RM 1)))) \ No newline at end of file diff --git a/test/clojure/test_clojure/printer.clj b/test/clojure/test_clojure/printer.clj index ffb3007138..0216f4f48f 100644 --- a/test/clojure/test_clojure/printer.clj +++ b/test/clojure/test_clojure/printer.clj @@ -123,8 +123,9 @@ (deftest print-throwable (binding [*data-readers* {'error identity}] - (are [e] (= (-> e Throwable->map) - (-> e pr-str read-string)) + (are [e] (let [e' e] ;; use same templated exception object in both cases + (= (-> e' Throwable->map) + (-> e' pr-str read-string))) (Exception. "heyo") (Throwable. "I can a throwable" (Exception. "chain 1" diff --git a/test/clojure/test_clojure/reader.cljc b/test/clojure/test_clojure/reader.cljc index e5fcf5d533..a0e1f1f13e 100644 --- a/test/clojure/test_clojure/reader.cljc +++ b/test/clojure/test_clojure/reader.cljc @@ -428,8 +428,9 @@ (doseq [form top-levels] (clojure.walk/postwalk #(when (list? %) - (is (= (expected-metadata (first %)) - (meta %))) + (when (contains? expected-metadata (first %)) + (is (= (expected-metadata (first %)) + (meta %)))) (is (->> (meta %) vals (filter number?) From 6355ed6fa62a38604291fe1f83c27eaa7ee6e45b Mon Sep 17 00:00:00 2001 From: clojure-build Date: Wed, 21 Feb 2024 21:47:39 +0000 Subject: [PATCH 194/285] [maven-release-plugin] prepare release clojure-1.12.0-alpha8 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2dd37faaad..4a7d6790fa 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0-alpha8 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0-alpha8 From f06ef8ad0b3d3ca5cbea64f55e416de1065a65e0 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Wed, 21 Feb 2024 21:47:39 +0000 Subject: [PATCH 195/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4a7d6790fa..2dd37faaad 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-alpha8 + 1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0-alpha8 + HEAD From 06d450895e2d4028afaa4face17f8e597c772a24 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 7 Mar 2024 11:47:14 -0600 Subject: [PATCH 196/285] CLJ-2839 Infinite seq class hashCode() is infinite loop --- src/clj/clojure/core.clj | 3 ++- src/jvm/clojure/lang/Cycle.java | 9 +++++++++ src/jvm/clojure/lang/Iterate.java | 8 ++++++++ src/jvm/clojure/lang/Repeat.java | 14 ++++++++++++++ test/clojure/test_clojure/sequences.clj | 10 ++++++++++ test/clojure/test_clojure/serialization.clj | 9 ++++++++- 6 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index d560f67d57..dc1f02e49b 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -3034,7 +3034,8 @@ [n x] (take n (repeat x))) (defn iterate - "Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects" + "Returns a lazy (infinite!) sequence of x, (f x), (f (f x)) etc. + f must be free of side-effects" {:added "1.0" :static true} [f x] (clojure.lang.Iterate/create f x) ) diff --git a/src/jvm/clojure/lang/Cycle.java b/src/jvm/clojure/lang/Cycle.java index a605e8ca20..293463090c 100644 --- a/src/jvm/clojure/lang/Cycle.java +++ b/src/jvm/clojure/lang/Cycle.java @@ -95,4 +95,13 @@ public Object reduce(IFn f, Object start){ s = all; } } + +public int hashCode(){ + throw new UnsupportedOperationException(); +} + +public int hasheq(){ + throw new UnsupportedOperationException(); +} + } diff --git a/src/jvm/clojure/lang/Iterate.java b/src/jvm/clojure/lang/Iterate.java index 0bbe733d94..9cffa92080 100644 --- a/src/jvm/clojure/lang/Iterate.java +++ b/src/jvm/clojure/lang/Iterate.java @@ -86,4 +86,12 @@ public Object reduce(IFn rf, Object start){ v = f.invoke(v); } } + +public int hashCode(){ + throw new UnsupportedOperationException(); +} + +public int hasheq(){ + throw new UnsupportedOperationException(); +} } diff --git a/src/jvm/clojure/lang/Repeat.java b/src/jvm/clojure/lang/Repeat.java index 1190b1e5d7..7e11808385 100644 --- a/src/jvm/clojure/lang/Repeat.java +++ b/src/jvm/clojure/lang/Repeat.java @@ -112,4 +112,18 @@ public Sequential drop(int n) { } } +public int hashCode(){ + if(count <= 0) + throw new UnsupportedOperationException(); + else + return super.hashCode(); +} + +public int hasheq(){ + if(count <= 0) + throw new UnsupportedOperationException(); + else + return super.hasheq(); +} + } diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj index 0ce1122bf5..624ba7c772 100644 --- a/test/clojure/test_clojure/sequences.clj +++ b/test/clojure/test_clojure/sequences.clj @@ -1587,6 +1587,16 @@ (range 1 2) 1 101 (range 1 3) 3 103)) +(deftest infinite-seq-hash + (are [e] (thrown? Exception (.hashCode ^Object e)) + (iterate identity nil) + (cycle [1]) + (repeat 1)) + (are [e] (thrown? Exception (.hasheq ^clojure.lang.IHashEq e)) + (iterate identity nil) + (cycle [1]) + (repeat 1))) + (defspec iteration-seq-equals-reduce 1000 (prop/for-all [initk gen/int seed gen/int] diff --git a/test/clojure/test_clojure/serialization.clj b/test/clojure/test_clojure/serialization.clj index 51a0d6a263..c9befc49cd 100644 --- a/test/clojure/test_clojure/serialization.clj +++ b/test/clojure/test_clojure/serialization.clj @@ -183,4 +183,11 @@ ;; stateful seqs (enumeration-seq (java.util.Collections/enumeration (range 50))) - (iterator-seq (.iterator (range 50))))) \ No newline at end of file + (iterator-seq (.iterator (range 50))))) + +;; necessary for CVE-2024-22871 +(deftest CLJ-2839 + (are [e] (thrown? Exception (.hashCode ^Object (-> e serialize deserialize))) + (repeat 1) + (iterate identity nil) + (cycle [1]))) \ No newline at end of file From 9704da2db9628a08db3627107a3389c2b1b2d27c Mon Sep 17 00:00:00 2001 From: clojure-build Date: Fri, 8 Mar 2024 14:56:53 +0000 Subject: [PATCH 197/285] [maven-release-plugin] prepare release clojure-1.12.0-alpha9 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2dd37faaad..18a7d81a7e 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0-alpha9 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0-alpha9 From 92d86872d242d5176b0e616de91c339f79ff39cc Mon Sep 17 00:00:00 2001 From: clojure-build Date: Fri, 8 Mar 2024 14:56:53 +0000 Subject: [PATCH 198/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 18a7d81a7e..2dd37faaad 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-alpha9 + 1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0-alpha9 + HEAD From 3e2bfe64fd111323944ad98e9150898d893d74d1 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 24 Apr 2024 13:01:17 -0500 Subject: [PATCH 199/285] CLJ-2843 If reflection does not match overload, widen boxed numerics and retry --- src/jvm/clojure/lang/Reflector.java | 51 ++++++++++++++++++--------- test/clojure/test_clojure/reflect.clj | 11 +++++- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/jvm/clojure/lang/Reflector.java b/src/jvm/clojure/lang/Reflector.java index d5811cc59d..f413d01ec5 100644 --- a/src/jvm/clojure/lang/Reflector.java +++ b/src/jvm/clojure/lang/Reflector.java @@ -118,10 +118,38 @@ private static String noMethodReport(String methodName, Object target, Object[] return "No matching method " + methodName + " found taking " + args.length + " args" + (target==null?"":" for " + target.getClass()); } + +private static Method matchMethod(List methods, Object[] args) { + Method foundm = null; + for(Iterator i = methods.iterator(); i.hasNext();) { + Method m = (Method) i.next(); + Class[] params = m.getParameterTypes(); + if(isCongruent(params, args) && (foundm == null || Compiler.subsumes(params, foundm.getParameterTypes()))) + foundm = m; + } + return foundm; +} + +private static Object[] widenBoxedArgs(Object[] args) { + Object[] widenedArgs = new Object[args.length]; + for(int i=0; i= 19, does reflect + (Thread/sleep ms)) + + +(deftest check-CLJ-2843 + (sleep 1) + (sleep (Integer/valueOf 1))) From f9cbc6548180acfe1460df373a39d0a583ca2b94 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 26 Apr 2024 09:02:34 -0500 Subject: [PATCH 200/285] Changelog updates for Clojure 1.11.2 and 1.11.3 --- changes.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/changes.md b/changes.md index f18b330f4a..9cbc7a4504 100644 --- a/changes.md +++ b/changes.md @@ -1,5 +1,15 @@ +# Changes to Clojure in Version 1.11.3 + +* [CLJ-2843](https://clojure.atlassian.net/browse/CLJ-2843) - Reflective calls to Java methods that take primitive long or double now work when passed a narrower boxed number at runtime (Integer, Short, Byte, Float). Previously, these methods were not matched during reflection and an error was thrown. + +# Changes to Clojure in Version 1.11.2 + +Fixes [CVE-2024-22871](https://nvd.nist.gov/vuln/detail/CVE-2024-22871) detailed in [GHSA-vr64-r9qj-h27f](https://github.com/advisories/GHSA-vr64-r9qj-h27f): + +* [CLJ-2839](https://clojure.atlassian.net/browse/CLJ-2839) - `iterate`, `cycle`, `repeat` - infinite seqs have infinite `hashCode()` + # Changes to Clojure in Version 1.11.1 * [CLJ-2701](https://clojure.atlassian.net/browse/CLJ-2701) From 1d50190539e2c4f89fd2954144b49cd03f7f46cd Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 26 Apr 2024 11:06:01 -0500 Subject: [PATCH 201/285] Revert "CLJ-2807: Add support for a symbol comprising the name of the array component type (primitive, full-qualified class, or import aliases accepted) followed by an asterisk for each dimension of the array (1 or more)." This reverts commit b2a914355589acad3aed6d724fbd6a995fd2610b. --- src/jvm/clojure/lang/Compiler.java | 87 ++-------------------- test/clojure/test_clojure/java_interop.clj | 20 ----- test/clojure/test_clojure/numbers.clj | 17 ----- 3 files changed, 5 insertions(+), 119 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 4baf9cb72c..4bb066c92d 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -395,12 +395,7 @@ static Symbol resolveSymbol(Symbol sym){ } Object o = currentNS().getMapping(sym); if(o == null) - { - Class ac = HostExpr.maybeArrayClass(sym); - if(ac != null) - return HostExpr.arrayTypeToSymbol(ac); return Symbol.intern(currentNS().name.name, sym.name); - } else if(o instanceof Class) return Symbol.intern(null, ((Class) o).getName()); else if(o instanceof Var) @@ -1028,12 +1023,8 @@ public static Class maybeClass(Object form, boolean stringOk) { { if(Util.equals(sym,COMPILE_STUB_SYM.get())) return (Class) COMPILE_STUB_CLASS.get(); - else if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[') - { - c = maybeArrayClass(sym); - if (c == null) - c = RT.classForNameNonLoading(sym.name); - } + if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[') + c = RT.classForNameNonLoading(sym.name); else { Object o = currentNS().getMapping(sym); @@ -1044,12 +1035,7 @@ else if(LOCAL_ENV.deref() != null && ((java.util.Map)LOCAL_ENV.deref()).contains else { try{ - if(c == null) - { - c = maybeArrayClass(sym); - if(c == null) - c = RT.classForNameNonLoading(sym.name); - } + c = RT.classForNameNonLoading(sym.name); } catch(Exception e){ // aargh @@ -1111,60 +1097,6 @@ else if(sym.name.equals("booleans")) return c; } - static String getArrayComponentClassDescriptor(Class c) { - if (c.isPrimitive()) - return Type.getType(c).getDescriptor(); - - return "L" + c.getName() + ";"; - } - - // componentArrayType (maybe qualified or prim) ending in 1+ *'s, e.g. java.lang.String** - // capture group 1 = componentArrayType, group 2 = dimension *'s - final static Pattern ARRAY_TYPE_PATTERN = Pattern.compile("([^*]+)(\\*+)"); - - public static Class maybeArrayClass(Symbol sym) { - if(!sym.name.endsWith("*")) return null; - - Matcher matcher = ARRAY_TYPE_PATTERN.matcher(sym.name); - - if(!matcher.matches()) return null; - - Symbol rootSymbol = Symbol.intern(matcher.group(1)); - String stars = matcher.group(2); - Class componentClass = maybeClass(rootSymbol, false); - - if(componentClass == null) - componentClass = primClass(rootSymbol); - - if(componentClass == null) return null; - - String componentDescriptor = getArrayComponentClassDescriptor(componentClass); - StringBuilder arrayDescriptor = new StringBuilder(); - arrayDescriptor.append(stars.replace('*', '[')); - arrayDescriptor.append(componentDescriptor); - return maybeClass(arrayDescriptor.toString(), true); - } - - public static Symbol arrayTypeToSymbol(Class c) { - if(!c.isArray()) return null; - - int dim = 1; - - Class componentClass = c.getComponentType(); - - while(componentClass.isArray()) { - dim++; - componentClass = componentClass.getComponentType(); - } - - String componentClassName = componentClass.getName(); - StringBuilder repr = new StringBuilder(componentClassName.length() + dim); - repr.append(componentClassName); - for(int i=0; i 0 || sym.name.charAt(0) == '[') { - Class ac = HostExpr.maybeArrayClass(sym); - if(ac != null) - return ac; - else - return RT.classForName(sym.name); + return RT.classForName(sym.name); } else if(sym.equals(NS)) return RT.NS_VAR; @@ -7804,12 +7732,7 @@ else if(sym.equals(IN_NS)) Object o = n.getMapping(sym); if(o == null) { - o = HostExpr.maybeArrayClass(sym); - if(o != null) - { - return o; - } - else if(RT.booleanCast(RT.ALLOW_UNRESOLVED_VARS.deref())) + if(RT.booleanCast(RT.ALLOW_UNRESOLVED_VARS.deref())) { return sym; } diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj index dae092f641..da7075d138 100644 --- a/test/clojure/test_clojure/java_interop.clj +++ b/test/clojure/test_clojure/java_interop.clj @@ -639,23 +639,3 @@ (deftest test-boxing-prevention-when-compiling-statements (is (= 1 (.get (doto (AtomicInteger. 0) inc-atomic-int)))) (is (= 1 (.get (doto (AtomicLong. 0) inc-atomic-long))))) - -(deftest array-type-symbols - (is (= long* (class (make-array Long/TYPE 0)))) - (is (= int* (class (make-array Integer/TYPE 0)))) - (is (= double* (class (make-array Double/TYPE 0)))) - (is (= short* (class (make-array Short/TYPE 0)))) - (is (= boolean* (class (make-array Boolean/TYPE 0)))) - (is (= byte* (class (make-array Byte/TYPE 0)))) - (is (= float* (class (make-array Float/TYPE 0)))) - (is (= String* (class (make-array String 0)))) - (is (= java.lang.String* (class (make-array String 0)))) - (is (= java.util.UUID* (class (make-array java.util.UUID 0)))) - (is (= `byte* 'byte*)) - (is (= `byte*** 'byte***)) - (is (= `java.util.UUID* 'java.util.UUID*)) - (is (= `String* 'java.lang.String*)) - (is (= `java.lang.String* 'java.lang.String*)) - (is (= `[NotAClassThatWasImported*] '[clojure.test-clojure.java-interop/NotAClassThatWasImported*])) - (is (= [long**] `[~long**])) - (is (= [42] (let [long** 42] `[~long**])))) diff --git a/test/clojure/test_clojure/numbers.clj b/test/clojure/test_clojure/numbers.clj index ec0fa04e34..be4f7a0a60 100644 --- a/test/clojure/test_clojure/numbers.clj +++ b/test/clojure/test_clojure/numbers.clj @@ -593,23 +593,6 @@ Math/pow overflows to Infinity." "[I" (int-array 1) (ints (int-array 1 1)) "[J" (long-array 1) (longs (long-array 1 1)))) -(deftest test-array-type-symbols - (are [str-repr klass] (= (Class/forName str-repr) klass) - "[Z" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'boolean*) - "[B" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'byte*) - "[C" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'char*) - "[S" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'short*) - "[F" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'float*) - "[D" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'double*) - "[I" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'int*) - "[J" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'long*) - "[[J" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'long**) - "[Ljava.lang.Object;" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'Object*) - "[Ljava.lang.String;" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'String*) - "[[Ljava.lang.String;" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'String**)) - (is (nil? (clojure.lang.Compiler$HostExpr/maybeArrayClass 'Object))) - (is (nil? (clojure.lang.Compiler$HostExpr/maybeArrayClass 'ThisIsNotAClassThatCouldBeFound138))) - (is (nil? (clojure.lang.Compiler$HostExpr/maybeArrayClass 'String-*IJ*)))) (deftest test-ratios (is (== (denominator 1/2) 2)) From 1fa5b038a434da34f787e3aec56f9cb48ed4dd99 Mon Sep 17 00:00:00 2001 From: fogus Date: Fri, 12 Apr 2024 12:54:43 -0400 Subject: [PATCH 202/285] CLJ-2807: Adding array class symbols into the symbol space via the locked out sym/N pattern. --- src/clj/clojure/core_print.clj | 4 +- src/jvm/clojure/lang/Compiler.java | 46 +++++++++++++- src/jvm/clojure/lang/LispReader.java | 7 +++ src/jvm/clojure/lang/Util.java | 22 +++++++ test/clojure/test_clojure/array_symbols.clj | 67 +++++++++++++++++++++ 5 files changed, 142 insertions(+), 4 deletions(-) create mode 100644 test/clojure/test_clojure/array_symbols.clj diff --git a/src/clj/clojure/core_print.clj b/src/clj/clojure/core_print.clj index 18c5101c1d..45b72d2971 100644 --- a/src/clj/clojure/core_print.clj +++ b/src/clj/clojure/core_print.clj @@ -380,7 +380,9 @@ Short/TYPE "Short/TYPE"}) (defmethod print-method Class [^Class c, ^Writer w] - (.write w (.getName c))) + (if (.isArray c) + (print-method (clojure.lang.Util/arrayTypeToSymbol c) w) + (.write w (.getName c)))) (defmethod print-dup Class [^Class c, ^Writer w] (cond diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 4bb066c92d..a5a4b1efd2 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -390,7 +390,12 @@ static Symbol resolveSymbol(Symbol sym){ { Namespace ns = namespaceFor(sym); if(ns == null || (ns.name.name == null ? sym.ns == null : ns.name.name.equals(sym.ns))) + { + Class ac = HostExpr.maybeArrayClass(sym); + if(ac != null) + return Util.arrayTypeToSymbol(ac); return sym; + } return Symbol.intern(ns.name.name, sym.name); } Object o = currentNS().getMapping(sym); @@ -1103,10 +1108,12 @@ static Class tagToClass(Object tag) { if(tag instanceof Symbol) { Symbol sym = (Symbol) tag; - if(sym.ns == null) //if ns-qualified can't be classname + if(sym.ns == null) { c = maybeSpecialTag(sym); } + if(c == null) + c = HostExpr.maybeArrayClass(sym); } if(c == null) c = maybeClass(tag, true); @@ -1114,6 +1121,34 @@ static Class tagToClass(Object tag) { return c; throw new IllegalArgumentException("Unable to resolve classname: " + tag); } + + static Class maybeArrayClass(Symbol sym) { + if(sym.ns == null || !Util.isPosDigit(sym.name)) + return null; + + int dim = sym.name.charAt(0) - '0'; + Symbol componentClassName = Symbol.intern(null, sym.ns); + Class componentClass = primClass(componentClassName); + + if(componentClass == null) + componentClass = maybeClass(componentClassName, false); + + if(componentClass == null) + throw Util.sneakyThrow(new ClassNotFoundException("Unable to resolve component classname: " + + componentClassName)); + + StringBuilder arrayDescriptor = new StringBuilder(); + + for(int i=0; i loadFrom) throws } } +static boolean isPosDigit(String s) { + if(s.length() != 1) + return false; + char ch = s.charAt(0); + return ch <= '9' && ch >= '1'; +} + +public static Symbol arrayTypeToSymbol(Class c) { + int dim = 0; + Class componentClass = c; + + while(componentClass.isArray()) { + if(++dim > 9) + break; + + componentClass = componentClass.getComponentType(); + } + if (dim <= 9 && dim >= 1) + return Symbol.intern(componentClass.getName(), Integer.toString(dim)); + else + return Symbol.intern(null, c.getName()); +} } diff --git a/test/clojure/test_clojure/array_symbols.clj b/test/clojure/test_clojure/array_symbols.clj new file mode 100644 index 0000000000..c9f94da309 --- /dev/null +++ b/test/clojure/test_clojure/array_symbols.clj @@ -0,0 +1,67 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. + +(ns clojure.test-clojure.array-symbols + (:use clojure.test) + (:require [clojure.test-helper :as util])) + +(set! *warn-on-reflection* true) + +(deftest test-array-symbols + (is (= 'java.lang.String/1 (read-string "java.lang.String/1"))) + (is (= 'String/1 (read-string "String/1"))) + (is (= 'int/2 (read-string "int/2"))) + (testing "array symbol resolution" + (are [str-repr klass] (= (Class/forName str-repr) klass) + "[Z" (resolve 'boolean/1) + "[B" (resolve 'byte/1) + "[C" (resolve 'char/1) + "[S" (resolve 'short/1) + "[F" (resolve 'float/1) + "[D" (resolve 'double/1) + "[I" (resolve 'int/1) + "[J" (resolve 'long/1) + "[[J" (resolve 'long/2) + "[Ljava.lang.Object;" (resolve 'Object/1) + "[Ljava.lang.String;" (resolve 'String/1) + "[[Ljava.lang.String;" (resolve 'String/2)) + (is (thrown? ClassNotFoundException (resolve 'ThisIsNotAClassThatCouldBeFound138/2))) + (is (thrown? ClassNotFoundException (resolve 'foo.bar.ThisIsNotAClassThatCouldBeFound138/2)))) + (testing "array hints" + (util/should-not-reflect + (let [^long/1 a (long-array [1 2 3 4 99 100])] + (java.util.Arrays/binarySearch a 99)))) + (testing "syntax quote" + (is (= `byte/1 'byte/1)) + (is (= `byte/9 'byte/9)) + (is (= `java.util.UUID/1 'java.util.UUID/1)) + (is (= `String/1 'java.lang.String/1))) + (testing "resolution" + (is (= (eval 'long/1) (class (make-array Long/TYPE 0)))) + (is (= (resolve 'long/1) (class (make-array Long/TYPE 0)))) + (is (= (resolve 'String/1) (class (make-array String 0)))) + (is (= (resolve 'java.lang.String/1) (class (make-array String 0)))) + (is (= (resolve 'java.util.UUID/1) (class (make-array java.util.UUID 0)))) + (is (= (resolve 'String/2) + (class (into-array (class (make-array String 0)) [(into-array String ["a" "b"])]))))) + (testing "value position" + (is (= (class (make-array String 0)) String/1)) + (is (= [(class (make-array String 0))] [String/1]))) + (testing "printing" + (is (= "long/1" (print-str long/1))) + (is (= "byte/1" (print-str (class (make-array Byte/TYPE 0))))) + (is (= "java.lang.String/2" (print-str String/2))) + (is (= "[[java.lang.String/2]]" (print-str [[String/2]]))) + (is (= "java.util.UUID/4" (print-str java.util.UUID/4))) + (is (= "[[[[[[[[[[Ljava.lang.Object;" (print-str (Class/forName "[[[[[[[[[[Ljava.lang.Object;")))) + (is (= "java.lang.Object/9" (print-str (Class/forName "[[[[[[[[[Ljava.lang.Object;"))))) + (testing "error conditions" + (is (thrown? Exception (read-string "String/1:"))) + (is (thrown? Exception (read-string "String/0"))) + (is (thrown? Exception (read-string "String/42"))) + (is (thrown? Exception (eval '(deftype Foo/2 [a])))))) From bc69ef477614b69021888c273f1cda100284dffb Mon Sep 17 00:00:00 2001 From: fogus Date: Tue, 13 Feb 2024 13:49:13 -0500 Subject: [PATCH 203/285] CLJ-2835: Passing the string 'new' to the methodDescription method when the method is a Constructor instance. --- src/jvm/clojure/lang/Compiler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index a5a4b1efd2..777baa2628 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1405,7 +1405,8 @@ static boolean isConstructor(Executable method) { private static void checkMethodArity(Executable method, int argCount) { if(method.getParameterCount() != argCount) throw new IllegalArgumentException("Invocation of " - + MethodValueExpr.methodDescription(method.getDeclaringClass(), method.getName()) + + MethodValueExpr.methodDescription(method.getDeclaringClass(), + (method instanceof Constructor) ? "new" : method.getName()) + " expected " + method.getParameterCount() + " arguments, but received " + argCount); } From c4973a4eb1f105f217dde9d45b751b2467dc532f Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 4 Apr 2024 14:26:43 -0500 Subject: [PATCH 204/285] CLJ-2841 - make IDeref extend DoubleSupplier, as with the other Supplier interfaces --- src/jvm/clojure/lang/IDeref.java | 8 +++++++- test/clojure/test_clojure/atoms.clj | 5 ++++- test/clojure/test_clojure/delays.clj | 3 ++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/jvm/clojure/lang/IDeref.java b/src/jvm/clojure/lang/IDeref.java index 41002f8ae1..0eeaaf329d 100644 --- a/src/jvm/clojure/lang/IDeref.java +++ b/src/jvm/clojure/lang/IDeref.java @@ -13,11 +13,12 @@ package clojure.lang; import java.util.function.BooleanSupplier; +import java.util.function.DoubleSupplier; import java.util.function.IntSupplier; import java.util.function.LongSupplier; import java.util.function.Supplier; -public interface IDeref extends Supplier, BooleanSupplier, IntSupplier, LongSupplier { +public interface IDeref extends Supplier, BooleanSupplier, IntSupplier, LongSupplier, DoubleSupplier { Object deref() ; @Override @@ -40,4 +41,9 @@ default long getAsLong() { return RT.longCast(deref()); } +@Override +default double getAsDouble() { + return RT.doubleCast(deref()); +} + } diff --git a/test/clojure/test_clojure/atoms.clj b/test/clojure/test_clojure/atoms.clj index 2e6974ef03..875f26d60f 100644 --- a/test/clojure/test_clojure/atoms.clj +++ b/test/clojure/test_clojure/atoms.clj @@ -57,4 +57,7 @@ (is (= 11 (.getAsLong a))) (is (instance? java.util.function.BooleanSupplier a)) - (is (true? (.getAsBoolean a))))) \ No newline at end of file + (is (true? (.getAsBoolean a))) + + (is (instance? java.util.function.DoubleSupplier a)) + (is (= 11.0 (.getAsDouble a))))) \ No newline at end of file diff --git a/test/clojure/test_clojure/delays.clj b/test/clojure/test_clojure/delays.clj index 477ab99af6..322feb6e49 100644 --- a/test/clojure/test_clojure/delays.clj +++ b/test/clojure/test_clojure/delays.clj @@ -85,4 +85,5 @@ (is (instance? java.util.function.LongSupplier di)) (is (= 100 (.get ^java.util.function.Supplier di))) (is (= 100 (.getAsInt ^java.util.function.IntSupplier di))) - (is (= 100 (.getAsLong ^java.util.function.LongSupplier di))))) \ No newline at end of file + (is (= 100 (.getAsLong ^java.util.function.LongSupplier di))) + (is (= 100.0 (.getAsDouble ^java.util.function.DoubleSupplier di))))) \ No newline at end of file From fd26a461efbf360ead0028c2f122860bfea69123 Mon Sep 17 00:00:00 2001 From: fogus Date: Fri, 26 Apr 2024 11:58:00 -0500 Subject: [PATCH 205/285] CLJ-2844: Modified qualified method impl to support new instance method syntax, defer resolution, and fallback to existing method inference when param-tags not used and Class + methodName cannot resolve. --- src/jvm/clojure/lang/Compiler.java | 328 ++++++++++---------- src/jvm/clojure/lang/Reflector.java | 15 +- test/clojure/test_clojure/method_thunks.clj | 13 +- test/clojure/test_clojure/param_tags.clj | 30 +- 4 files changed, 186 insertions(+), 200 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 777baa2628..116088c817 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1012,7 +1012,7 @@ else if(instance != null && instance.hasJavaClass() && instance.getJavaClass() ! if(c != null) return new StaticMethodExpr(source, line, column, tag, c, munge(sym.name), args, tailPosition); else - return new InstanceMethodExpr(source, line, column, tag, instance, munge(sym.name), args, tailPosition); + return new InstanceMethodExpr(source, line, column, tag, instance, null, munge(sym.name), args, tailPosition); } } } @@ -1152,104 +1152,53 @@ static Class maybeArrayClass(Symbol sym) { } // In invocation position -// direct invocation of resolved constructor, static, or instance method -// OR legacy static method invocation with inference -// this is the ONLY valid case where method is unresolved by end of constructor -// In value position, will emit as a method thunk (error if not resolved) -static class MethodValueExpr implements Expr { +// param-tags - direct invocation of resolved constructor, static, or instance method +// else method invocation with inference + reflection +// In value position, will emit as a multi-arity method thunk with +// params matching the arity set of the named method +static class QualifiedMethodExpr implements Expr { private final Class c; private final List hintedSig; - private final Executable method; private final Symbol methodSymbol; private final String methodName; + private final MethodKind kind; - public MethodValueExpr(Class methodClass, Symbol sym){ + private enum MethodKind { + CTOR, INSTANCE, STATIC + } + + public QualifiedMethodExpr(Class methodClass, Symbol sym){ c = methodClass; methodSymbol = sym; - methodName = sym.name; - - List methods = methodsWithName(c, methodName); - if(methods.isEmpty()) - throw noMethodWithNameException(c, methodName); - hintedSig = tagsToClasses(paramTagsOf(sym)); - if(hintedSig != null) { - method = resolveHintedMethod(c, methodName, hintedSig, methods); - } else { - Executable maybeMethod = null; - if(methods.size() == 1) { - // Only 1 method - no inference needed - maybeMethod = methods.get(0); - } - else if(methods.size() > 1) { - // Only statics supported at this point (needs inference) - - if(methodNamesConstructor(c, methodName)) - throw overloadNeedsParamTagsException(c, methodName); - - // Filter out instance methods (no inference allowed) - List staticMethods = methods.stream() - .filter(m -> Modifier.isStatic(m.getModifiers())) - .collect(Collectors.toList()); - if(staticMethods.size() == 1) - maybeMethod = staticMethods.get(0); - else if(staticMethods.isEmpty()) - throw overloadNeedsParamTagsException(c, methodName); - // else not resolved, static method w/inference - } - method = maybeMethod; + if(sym.name.startsWith(".")) { + kind = MethodKind.INSTANCE; + methodName = sym.name.substring(1); } - } - - private static Executable resolveHintedMethod(Class c, String methodName, List hintedSig, List methods) { - final int arity = hintedSig.size(); - List filteredMethods = methods.stream() - .filter(m -> m.getParameterCount() == arity) - .filter(m -> !m.isSynthetic()) // remove bridge/lambda methods - .filter(m -> signatureMatches(hintedSig, m)) - .collect(Collectors.toList()); - - if(filteredMethods.size() == 1) - return filteredMethods.get(0); - else - throw paramTagsDontResolveException(c, methodName, hintedSig, filteredMethods.size()); - } - - private static boolean methodNamesConstructor(Class c, String methodName) { - return c != null && methodName.equals("new"); - } - - private static List methodsWithName(Class c, String name) { - final Executable[] methods; - final String methodName; - if (methodNamesConstructor(c, name)) { - methods = c.getConstructors(); - methodName = c.getName(); + else if(sym.name.equals("new")) { + kind = MethodKind.CTOR; + methodName = sym.name; } else { - methods = c.getMethods(); - methodName = name; + kind = MethodKind.STATIC; + methodName = sym.name; } - - return Arrays.stream(methods) - .filter(m -> m.getName().equals(methodName)) - .collect(Collectors.toList()); } - public boolean isResolved() { - return method != null; - } + // Expr impl - invocation, convert to fn expr @Override public Object eval() { - return toFnExpr(this).eval(); + return buildThunk(C.EVAL, this).eval(); } @Override public void emit(C context, ObjExpr objx, GeneratorAdapter gen) { - toFnExpr(this).emit(context, objx, gen); + buildThunk(context, this).emit(context, objx, gen); } + // Expr impl - method value, always an AFn + @Override public boolean hasJavaClass() { return true; @@ -1260,76 +1209,85 @@ public Class getJavaClass() { return AFn.class; } - private static FnExpr toFnExpr(MethodValueExpr mexpr) { - // If not resolved by this point we were not given param-tags - // and named method was overloaded. - if(!mexpr.isResolved()) { - throw overloadNeedsParamTagsException(mexpr.c, mexpr.methodName); - } - - // return hint symbol - Symbol retTag = null; - Class retClass = mexpr.method instanceof Constructor ? mexpr.c - : ((java.lang.reflect.Method)mexpr.method).getReturnType(); - if (isHintablePrimitive(retClass) || !retClass.isPrimitive()) { - retTag = primTag(retClass); - retTag = (retTag != null) ? retTag : Symbol.intern(null, retClass.getName()); + // TBD: caching/reuse of thunks + private static FnExpr buildThunk(C context, QualifiedMethodExpr qmexpr) { + // When qualified symbol has param-tags: + // (fn invoke__Class_meth ([this? args*] (methodSymbol this? args*))) + // When no param-tags: + // (fn invoke__Class_meth ([this?] (methodSymbol this?)) + // ([this? arg1] (methodSymbol this? arg1)) ...) + IPersistentCollection form = PersistentVector.EMPTY; + Symbol instanceParam = qmexpr.kind == MethodKind.INSTANCE ? THIS : null; + String thunkName = "invoke__" + qmexpr.c.getSimpleName() + "_" + qmexpr.methodSymbol.name; + Set arities = (qmexpr.hintedSig != null) ? PersistentHashSet.create(qmexpr.hintedSig.size()) + : aritySet(qmexpr.c, qmexpr.methodName, qmexpr.kind); + + for(Object a : arities) { + int arity = (int) a; + IPersistentVector params = buildParams(instanceParam, arity); + ISeq body = RT.listStar(qmexpr.methodSymbol, params.seq()); + form = RT.conj(form, RT.list(params, body)); } - return buildThunk(mexpr.c, mexpr.method, mexpr.methodSymbol, - isInstanceMethod(mexpr.method) ? THIS : null, retTag); + ISeq thunkForm = RT.listStar(Symbol.intern("fn"), Symbol.intern(thunkName), RT.seq(form)); + return (FnExpr) analyzeSeq(context, thunkForm, thunkName); } - private static boolean isHintablePrimitive(Class c) { - return Long.TYPE.equals(c) || Double.TYPE.equals(c); + private static IPersistentVector buildParams(Symbol instanceParam, int arity) { + IPersistentVector params = PersistentVector.EMPTY; + if(instanceParam != null) params = params.cons(instanceParam); + for(int i = 0; i(); + List methods = methodsWithName(c, methodName, kind); + + for(Executable exec : methods) + res.add(exec.getParameterCount()); + + return res; } - // All buildThunk methods currently return a new FnExpr on every call - // TBD: caching/reuse of thunks - private static FnExpr buildThunk(Class c, Executable method, Symbol methodSymbol, Symbol instanceParam, Symbol retHint) { - // (fn invoke__Class_meth (^retHint? [this? primHintedArgs*] (methodSymbol this? primHintedArgs*))) - IPersistentVector params = PersistentVector.EMPTY; - if(instanceParam != null) params = params.cons(instanceParam); - // hinted params - Class[] paramTypes = method.getParameterTypes(); - for(int i = 0; i methodsWithName(Class c, String methodName, MethodKind kind) { + if (kind == MethodKind.CTOR) { + return Arrays.asList(c.getConstructors()); } - // hint return - params = (retHint == null) ? params - : ((PersistentVector)params).withMeta(RT.map(RT.TAG_KEY, retHint)); - ISeq body = RT.listStar(methodSymbol, params.seq()); - String thunkName = "invoke__" + c.getSimpleName() + "_" + methodSymbol.name; - ISeq form = RT.list(Symbol.intern("fn"), Symbol.intern(thunkName), RT.list(params, body)); - return (FnExpr) analyzeSeq(C.EVAL, form, thunkName); + final Executable[] methods = c.getMethods(); + return Arrays.stream(methods) + .filter(m -> m.getName().equals(methodName)) + .filter(m -> { + switch(kind) { + case STATIC: return isStaticMethod(m); + case INSTANCE: return isInstanceMethod(m); + default: return false; + } + }) + .collect(Collectors.toList()); } - private static String methodDescription(Class c, String methodName) { - boolean isCtor = methodNamesConstructor(c, methodName); - String type = isCtor ? "constructor" : "method"; - return type + (isCtor ? "" : " " + methodName) + " in class " + c.getName(); - } + static Executable resolveHintedMethod(Class c, String methodName, MethodKind kind, List hintedSig) { + List methods = methodsWithName(c, methodName, kind); + if (methods.isEmpty()) + throw noMethodWithNameException(c, methodName); - static IPersistentVector toParamTags(List hintedSig) { - return PersistentVector.create(hintedSig.stream() - .map(tag -> tag == null ? PARAM_TAG_ANY : tag) - .collect(Collectors.toList())); + final int arity = hintedSig.size(); + List filteredMethods = methods.stream() + .filter(m -> m.getParameterCount() == arity) + .filter(m -> !m.isSynthetic()) // remove bridge/lambda methods + .filter(m -> signatureMatches(hintedSig, m)) + .collect(Collectors.toList()); + + if(filteredMethods.size() == 1) + return filteredMethods.get(0); + else + throw paramTagsDontResolveException(c, methodName, hintedSig, filteredMethods.size()); } static IllegalArgumentException noMethodWithNameException(Class c, String methodName) { @@ -1337,17 +1295,14 @@ static IllegalArgumentException noMethodWithNameException(Class c, String method + methodDescription(c, methodName)); } - static IllegalArgumentException overloadNeedsParamTagsException(Class c, String methodName) { - return new IllegalArgumentException("Multiple matches for " - + methodDescription(c, methodName) - + ", use param-tags to specify"); - } - static IllegalArgumentException paramTagsDontResolveException(Class c, String methodName, List hintedSig, int found) { + IPersistentVector paramTags = PersistentVector.create(hintedSig.stream() + .map(tag -> tag == null ? PARAM_TAG_ANY : tag) + .collect(Collectors.toList())); return new IllegalArgumentException("Expected to find 1 matching signature for " + methodDescription(c, methodName) + " but found " + found - + " with param-tags " + toParamTags(hintedSig)); + + " with param-tags " + paramTags); } } @@ -1403,11 +1358,17 @@ static boolean isConstructor(Executable method) { } private static void checkMethodArity(Executable method, int argCount) { - if(method.getParameterCount() != argCount) - throw new IllegalArgumentException("Invocation of " - + MethodValueExpr.methodDescription(method.getDeclaringClass(), - (method instanceof Constructor) ? "new" : method.getName()) - + " expected " + method.getParameterCount() + " arguments, but received " + argCount); + if(method.getParameterCount() != argCount) + throw new IllegalArgumentException("Invocation of " + + methodDescription(method.getDeclaringClass(), + (method instanceof Constructor) ? "new" : method.getName()) + + " expected " + method.getParameterCount() + " arguments, but received " + argCount); +} + +private static String methodDescription(Class c, String methodName) { + boolean isCtor = c != null && methodName.equals("new"); + String type = isCtor ? "constructor" : "method"; + return type + (isCtor ? "" : " " + methodName) + " in class " + c.getName(); } static abstract class FieldExpr extends HostExpr{ @@ -1748,15 +1709,19 @@ static class InstanceMethodExpr extends MethodExpr{ public final Symbol tag; public final boolean tailPosition; public final java.lang.reflect.Method method; + public final Class qualifyingClass; Class jc; final static Method invokeInstanceMethodMethod = Method.getMethod("Object invokeInstanceMethod(Object,String,Object[])"); + final static Method invokeInstanceMethodOfClassMethod = + Method.getMethod("Object invokeInstanceMethodOfClass(Object,String,String,Object[])"); public InstanceMethodExpr(String source, int line, int column, Symbol tag, Expr target, - String methodName, java.lang.reflect.Method preferredMethod, IPersistentVector args, boolean tailPosition) + Class qualifyingClass, String methodName, java.lang.reflect.Method resolvedMethod, + IPersistentVector args, boolean tailPosition) { - checkMethodArity(preferredMethod, RT.count(args)); + checkMethodArity(resolvedMethod, RT.count(args)); this.source = source; this.line = line; @@ -1766,11 +1731,12 @@ public InstanceMethodExpr(String source, int line, int column, Symbol tag, Expr this.target = target; this.tag = tag; this.tailPosition = tailPosition; - this.method = preferredMethod; + this.method = resolvedMethod; + this.qualifyingClass = qualifyingClass; } public InstanceMethodExpr(String source, int line, int column, Symbol tag, Expr target, - String methodName, IPersistentVector args, boolean tailPosition) + Class qualifyingClass, String methodName, IPersistentVector args, boolean tailPosition) { this.source = source; this.line = line; @@ -1780,6 +1746,7 @@ public InstanceMethodExpr(String source, int line, int column, Symbol tag, Expr this.target = target; this.tag = tag; this.tailPosition = tailPosition; + this.qualifyingClass = qualifyingClass; if(target.hasJavaClass() && target.getJavaClass() != null) { List methods = Reflector.getMethods(target.getJavaClass(), args.count(), methodName, false); @@ -1849,7 +1816,10 @@ public Object eval() { ms.add(method); return Reflector.invokeMatchingMethod(methodName, ms, targetval, argvals); } - return Reflector.invokeInstanceMethod(targetval, methodName, argvals); + if(qualifyingClass != null) + return Reflector.invokeInstanceMethodOfClass(targetval, qualifyingClass, methodName, argvals); + else + return Reflector.invokeInstanceMethod(targetval, methodName, argvals); } catch(Throwable e) { @@ -1921,6 +1891,8 @@ else if(retClass != void.class) else { target.emit(C.EXPRESSION, objx, gen); + if(qualifyingClass != null) + gen.push(qualifyingClass.getName()); gen.push(methodName); emitArgsAsArray(args, objx, gen); gen.visitLineNumber(line, gen.mark()); @@ -1929,7 +1901,10 @@ else if(retClass != void.class) ObjMethod method = (ObjMethod) METHOD.deref(); method.emitClearLocals(gen); } - gen.invokeStatic(REFLECTOR_TYPE, invokeInstanceMethodMethod); + if(qualifyingClass != null) + gen.invokeStatic(REFLECTOR_TYPE, invokeInstanceMethodOfClassMethod); + else + gen.invokeStatic(REFLECTOR_TYPE, invokeInstanceMethodMethod); if(context == C.STATEMENT) gen.pop(); } @@ -4232,8 +4207,8 @@ static public Expr parse(C context, ISeq form) { args = args.cons(analyze(context, s.first())); } - if(fexpr instanceof MethodValueExpr) - return toHostExpr((MethodValueExpr)fexpr, (String) SOURCE.deref(), lineDeref(), columnDeref(), tagOf(form), tailPosition, args); + if(fexpr instanceof QualifiedMethodExpr) + return toHostExpr((QualifiedMethodExpr)fexpr, (String) SOURCE.deref(), lineDeref(), columnDeref(), tagOf(form), tailPosition, args); // if(args.count() > MAX_POSITIONAL_ARITY) // throw new IllegalArgumentException( @@ -4242,22 +4217,34 @@ static public Expr parse(C context, ISeq form) { return new InvokeExpr((String) SOURCE.deref(), lineDeref(), columnDeref(), tagOf(form), fexpr, args, tailPosition); } - private static Expr toHostExpr(MethodValueExpr mexpr, String source, int line, int column, Symbol tag, boolean tailPosition, IPersistentVector args) { - if(!mexpr.isResolved()) { - // default to static method with inference - return new StaticMethodExpr(source, line, column, tag, mexpr.c, munge(mexpr.methodName), args, tailPosition); + private static Expr toHostExpr(QualifiedMethodExpr qmexpr, String source, int line, int column, Symbol tag, boolean tailPosition, IPersistentVector args) { + if(qmexpr.hintedSig != null) { + Executable method = QualifiedMethodExpr.resolveHintedMethod(qmexpr.c, qmexpr.methodName, qmexpr.kind, qmexpr.hintedSig); + switch(qmexpr.kind) { + case CTOR: + return new NewExpr(qmexpr.c, (Constructor) method, args, line, column); + case INSTANCE: + return new InstanceMethodExpr(source, line, column, tag, (Expr) RT.first(args), + qmexpr.c, munge(qmexpr.methodName), (java.lang.reflect.Method) method, + PersistentVector.create(RT.next(args)), + tailPosition); + default: + return new StaticMethodExpr(source, line, column, tag, qmexpr.c, + munge(qmexpr.methodName), (java.lang.reflect.Method) method, args, tailPosition); + } + } + else { + switch(qmexpr.kind) { + case CTOR: + return new NewExpr(qmexpr.c, args, line, column); + case INSTANCE: + return new InstanceMethodExpr(source, line, column, tag, (Expr) RT.first(args), qmexpr.c, + munge(qmexpr.methodName), PersistentVector.create(RT.next(args)), tailPosition); + default: + return new StaticMethodExpr(source, line, column, tag, qmexpr.c, + munge(qmexpr.methodName), args, tailPosition); + } } - - if(isConstructor(mexpr.method)) - return new NewExpr(mexpr.c, (Constructor) mexpr.method, args, line, column); - - if(isInstanceMethod(mexpr.method)) - return new InstanceMethodExpr(source, line, column, tag, (Expr) RT.first(args), - munge(mexpr.methodName), (java.lang.reflect.Method) mexpr.method, PersistentVector.create(RT.next(args)), - tailPosition); - - return new StaticMethodExpr(source, line, column, tag, mexpr.c, - munge(mexpr.methodName), (java.lang.reflect.Method) mexpr.method, args, tailPosition); } } @@ -7397,7 +7384,8 @@ public static Object macroexpand1(Object x) { Symbol sym = (Symbol) op; String sname = sym.name; //(.substring s 2 5) => (. s substring 2 5) - if(sym.name.charAt(0) == '.') + // ns == null ensures that Class/.instanceMethod isn't expanded to . form + if(sym.name.charAt(0) == '.' && sym.ns == null) { if(RT.length(form) < 2) throw new IllegalArgumentException( @@ -7670,7 +7658,7 @@ private static Expr analyzeSymbol(Symbol sym) { if(Reflector.getField(c, sym.name, true) != null) return new StaticFieldExpr(lineDeref(), columnDeref(), c, sym.name, tag); else - return new MethodValueExpr(c, sym); + return new QualifiedMethodExpr(c, sym); } } diff --git a/src/jvm/clojure/lang/Reflector.java b/src/jvm/clojure/lang/Reflector.java index f413d01ec5..31b08831ad 100644 --- a/src/jvm/clojure/lang/Reflector.java +++ b/src/jvm/clojure/lang/Reflector.java @@ -94,14 +94,21 @@ private static Method toAccessibleSuperMethod(Method m, Object target) { } public static Object invokeInstanceMethod(Object target, String methodName, Object[] args) { - Class c = target.getClass(); + return invokeInstanceMethodOfClass(target, target.getClass(), methodName, args); +} + +public static Object invokeInstanceMethodOfClass(Object target, Class c, String methodName, Object[] args) { List methods = getMethods(c, args.length, methodName, false).stream() - .map(method -> toAccessibleSuperMethod(method, target)) - .filter(method -> (method != null)) - .collect(Collectors.toList()); + .map(method -> toAccessibleSuperMethod(method, target)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); return invokeMatchingMethod(methodName, methods, target, args); } +public static Object invokeInstanceMethodOfClass(Object target, String className, String methodName, Object[] args) { + return invokeInstanceMethodOfClass(target, RT.classForName(className), methodName, args); +} + private static Throwable getCauseOrElse(Exception e) { if (e.getCause() != null) return e.getCause(); diff --git a/test/clojure/test_clojure/method_thunks.clj b/test/clojure/test_clojure/method_thunks.clj index 06ac5a3f6e..55463e12fa 100644 --- a/test/clojure/test_clojure/method_thunks.clj +++ b/test/clojure/test_clojure/method_thunks.clj @@ -21,8 +21,7 @@ (is (= '([1] [2] [3]) (map ^[_] Tuple/create [1 2 3]))) (is (= '([1 4] [2 5] [3 6]) - (map ^[_ _] Tuple/create [1 2 3] [4 5 6]))) - (is (thrown? Exception (eval 'clojure.lang.Tuple/create)))) + (map ^[_ _] Tuple/create [1 2 3] [4 5 6])))) (deftest method-signature-selection (is (= [1.23 3.14] @@ -36,18 +35,16 @@ (is (= '("a" "12") (map ^[Object] String/valueOf ["a" 12]))) (is (= ["A" "B" "C"] - (map ^[java.util.Locale] String/toUpperCase ["a" "b" "c"] (repeat java.util.Locale/ENGLISH)))) + (map ^[java.util.Locale] String/.toUpperCase ["a" "b" "c"] (repeat java.util.Locale/ENGLISH)))) (is (thrown? ClassCastException (doall (map ^[long] String/valueOf [12 "a"]))))) (def mt ^[_] Tuple/create) (def mts {:fromString ^[_] UUID/fromString}) +(def gbs ^[] String/.getBytes) (deftest method-thunks-in-structs (is (= #uuid "00000000-0000-0001-0000-000000000002" ((:fromString mts) "00000000-0000-0001-0000-000000000002"))) - (is (= [1] (mt 1)))) - -(deftest primitive-hinting - (is (instance? clojure.lang.IFn$DO ^[double] String/valueOf)) - (is (instance? clojure.lang.IFn$LL ^[long] Math/abs))) + (is (= [1] (mt 1))) + (is (= 97 (first (seq (gbs "a")))))) diff --git a/test/clojure/test_clojure/param_tags.clj b/test/clojure/test_clojure/param_tags.clj index c4c57d60e1..3970070f25 100644 --- a/test/clojure/test_clojure/param_tags.clj +++ b/test/clojure/test_clojure/param_tags.clj @@ -23,13 +23,13 @@ (deftest no-hints-with-param-tags (should-not-reflect (defn touc-no-reflect [s] - (^[] String/toUpperCase s))) + (^[] String/.toUpperCase s))) (should-not-reflect (defn touc-no-reflectq [s] - (^[] java.lang.String/toUpperCase s))) + (^[] java.lang.String/.toUpperCase s))) (should-not-reflect (defn touc-no-reflect-arg-tags [s] - (^[java.util.Locale] String/toUpperCase s java.util.Locale/ENGLISH)))) + (^[java.util.Locale] String/.toUpperCase s java.util.Locale/ENGLISH)))) (deftest param-tags-in-invocation-positions (testing "qualified static method invocation" @@ -41,11 +41,11 @@ (is (= (^[long long] java.util.UUID/new 1 2) #uuid "00000000-0000-0001-0000-000000000002")) (is (= "a" (^[String] String/new "a")))) (testing "qualified instance method invocation" - (is (= \A (String/charAt "A" 0))) - (is (= "A" (^[java.util.Locale] String/toUpperCase "a" java.util.Locale/ENGLISH))) - (is (= "A" (^[Locale] String/toUpperCase "a" java.util.Locale/ENGLISH))) - (is (= 65 (aget (^[String] String/getBytes "A" "US-ASCII") 0))) - (is (= "42" (^[] Long/toString 42)))) + (is (= \A (String/.charAt "A" 0))) + (is (= "A" (^[java.util.Locale] String/.toUpperCase "a" java.util.Locale/ENGLISH))) + (is (= "A" (^[Locale] String/.toUpperCase "a" java.util.Locale/ENGLISH))) + (is (= 65 (aget (^[String] String/.getBytes "A" "US-ASCII") 0))) + (is (= "42" (^[] Long/.toString 42)))) (testing "string repr array type resolutions" (let [lary (long-array [1 2 3 4 99 100]) oary (into-array [1 2 3 4 99 100]) @@ -133,7 +133,7 @@ Call the method providing the appropriate arg-tags and return a map containing the actual and expected response." [{:keys [name declaring-class parameter-types]}] - (let [method (str name) + (let [method (str "." name) args (str/join " " (map #(-> % reflected-parameter-types :arg-type) parameter-types)) arg-tags (str/join " " (map #(-> % reflected-parameter-types :arg-tag) parameter-types)) expected-response (str/join "-" parameter-types) @@ -162,11 +162,11 @@ (deftest bridge-methods (testing "Allows correct intended usage." (let [concrete (ConcreteClass.)] - (is (= 42 (^[Integer] ConcreteClass/stampWidgets concrete (int 99)))))) + (is (= 42 (^[Integer] ConcreteClass/.stampWidgets concrete (int 99)))))) (testing "Will not call bridge method." (is (thrown? Compiler$CompilerException (eval '(let [concrete (clojure.test.ConcreteClass.)] - (^[Object] ConcreteClass/stampWidgets concrete (int 99)))))))) + (^[Object] ConcreteClass/.stampWidgets concrete (int 99)))))))) (deftest incorrect-arity-invocation-error-messages @@ -175,10 +175,4 @@ (let [e (try (eval '(^[long] Math/abs -1 -2 -3)) (catch Compiler$CompilerException e (str "-> " (.getMessage (.getCause e)))))] - (is (not (nil? (re-find #"expected 1.*received 3" e))) "Error message was expected to indicate 1 argument was expected but 2 were provided"))) - - (testing "Invocation without param-tags having incorrect number of args" - (let [e (try - (eval '(java.util.UUID/fromString "a" 1)) - (catch Compiler$CompilerException e (str "-> " (.getMessage (.getCause e)))))] - (is (not (nil? (re-find #"expected 1.*received 2" e))) "Error message was expected to indicate 1 argument was expected but 2 were provided")))) \ No newline at end of file + (is (not (nil? (re-find #"expected 1.*received 3" e))) "Error message was expected to indicate 1 argument was expected but 2 were provided")))) From 41c946ac8716d5ebaaf37809adad2d15ce7707a3 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Sun, 28 Apr 2024 14:46:22 +0000 Subject: [PATCH 206/285] [maven-release-plugin] prepare release clojure-1.12.0-alpha10 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2dd37faaad..cb650c65bd 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0-alpha10 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0-alpha10 From e36f4e92ce01edb8d2c84766d2357bfb38c4ec3d Mon Sep 17 00:00:00 2001 From: clojure-build Date: Sun, 28 Apr 2024 14:46:22 +0000 Subject: [PATCH 207/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index cb650c65bd..2dd37faaad 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-alpha10 + 1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0-alpha10 + HEAD From f1207aeebf9aca5f03799593d4cea59527b00ee9 Mon Sep 17 00:00:00 2001 From: fogus Date: Tue, 30 Apr 2024 12:25:42 -0400 Subject: [PATCH 208/285] CLJ-2847: Moved no name result check into methodsWithName method so that value and invocation paths will get the same error when a name results in no matches. Also expanded check to constructors so that classes with no public ctors will also have same error message. Finally, cleaned up paramTagsDontResolveException error message. --- src/jvm/clojure/lang/Compiler.java | 32 ++++++++++++--------- test/clojure/test_clojure/method_thunks.clj | 6 +++- test/clojure/test_clojure/param_tags.clj | 6 +++- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 116088c817..0f45990600 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1254,13 +1254,18 @@ private static Set aritySet(Class c, String methodName, MethodKind kind) { return res; } + // Returns a list of methods or ctors matching the name and kind given. + // Otherwise, will throw if the information provided results in no matches private static List methodsWithName(Class c, String methodName, MethodKind kind) { if (kind == MethodKind.CTOR) { - return Arrays.asList(c.getConstructors()); + List ctors = Arrays.asList(c.getConstructors()); + if(ctors.isEmpty()) + throw noMethodWithNameException(c, methodName, kind); + return ctors; } final Executable[] methods = c.getMethods(); - return Arrays.stream(methods) + List res = Arrays.stream(methods) .filter(m -> m.getName().equals(methodName)) .filter(m -> { switch(kind) { @@ -1270,13 +1275,14 @@ private static List methodsWithName(Class c, String methodName, Meth } }) .collect(Collectors.toList()); + + if(res.isEmpty()) + throw noMethodWithNameException(c, methodName, kind); + return res; } static Executable resolveHintedMethod(Class c, String methodName, MethodKind kind, List hintedSig) { List methods = methodsWithName(c, methodName, kind); - if (methods.isEmpty()) - throw noMethodWithNameException(c, methodName); - final int arity = hintedSig.size(); List filteredMethods = methods.stream() .filter(m -> m.getParameterCount() == arity) @@ -1287,22 +1293,22 @@ static Executable resolveHintedMethod(Class c, String methodName, MethodKind kin if(filteredMethods.size() == 1) return filteredMethods.get(0); else - throw paramTagsDontResolveException(c, methodName, hintedSig, filteredMethods.size()); + throw paramTagsDontResolveException(c, methodName, hintedSig); } - static IllegalArgumentException noMethodWithNameException(Class c, String methodName) { - return new IllegalArgumentException("Could not find " + static IllegalArgumentException noMethodWithNameException(Class c, String methodName, MethodKind kind) { + return new IllegalArgumentException("Error - no matches found for " + + (kind != MethodKind.CTOR ? kind.toString().toLowerCase() + " " : "") + methodDescription(c, methodName)); } - static IllegalArgumentException paramTagsDontResolveException(Class c, String methodName, List hintedSig, int found) { + static IllegalArgumentException paramTagsDontResolveException(Class c, String methodName, List hintedSig) { IPersistentVector paramTags = PersistentVector.create(hintedSig.stream() .map(tag -> tag == null ? PARAM_TAG_ANY : tag) .collect(Collectors.toList())); - return new IllegalArgumentException("Expected to find 1 matching signature for " - + methodDescription(c, methodName) - + " but found " + found - + " with param-tags " + paramTags); + return new IllegalArgumentException("Error - param-tags " + paramTags + + " insufficient to resolve " + + methodDescription(c, methodName)); } } diff --git a/test/clojure/test_clojure/method_thunks.clj b/test/clojure/test_clojure/method_thunks.clj index 55463e12fa..c70d833962 100644 --- a/test/clojure/test_clojure/method_thunks.clj +++ b/test/clojure/test_clojure/method_thunks.clj @@ -37,7 +37,11 @@ (is (= ["A" "B" "C"] (map ^[java.util.Locale] String/.toUpperCase ["a" "b" "c"] (repeat java.util.Locale/ENGLISH)))) (is (thrown? ClassCastException - (doall (map ^[long] String/valueOf [12 "a"]))))) + (doall (map ^[long] String/valueOf [12 "a"])))) + (testing "bad method names" + (is (thrown-with-msg? Exception #"static method" (eval 'java.lang.String/foo))) + (is (thrown-with-msg? Exception #"instance method" (eval 'java.lang.String/.foo))) + (is (thrown-with-msg? Exception #"constructor" (eval 'Math/new))))) (def mt ^[_] Tuple/create) (def mts {:fromString ^[_] UUID/fromString}) diff --git a/test/clojure/test_clojure/param_tags.clj b/test/clojure/test_clojure/param_tags.clj index 3970070f25..4a2d64d1fc 100644 --- a/test/clojure/test_clojure/param_tags.clj +++ b/test/clojure/test_clojure/param_tags.clj @@ -53,7 +53,11 @@ (is (= 4 (^[longs long] Arrays/binarySearch lary (long 99)))) (is (= 4 (^[objects _] Arrays/binarySearch oary 99))) (is (= 4 (^["[Ljava.lang.Object;" _] Arrays/binarySearch oary 99))) - (is (= 1 (^["[Ljava.lang.Object;" _] Arrays/binarySearch sary "b")))))) + (is (= 1 (^["[Ljava.lang.Object;" _] Arrays/binarySearch sary "b"))))) + (testing "bad method names" + (is (thrown? Exception (eval '(^[] java.lang.String/foo "a")))) + (is (thrown? Exception (eval '(^[] java.lang.String/.foo "a")))) + (is (thrown? Exception (eval '(^[] Math/new "a")))))) ;; Mapping of symbols returned from reflect call to :parameter-type used as arguments to .getDeclaredMethod, From ebc312f1ccc5041411b5fdfbb25799529e227ab9 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 30 Apr 2024 12:03:46 -0500 Subject: [PATCH 209/285] CLJ-2848 Qualified instance methods should use the qualifying class when no param-tags --- src/jvm/clojure/lang/Compiler.java | 10 ++++++---- test/clojure/test_clojure/param_tags.clj | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 0f45990600..3e123e3495 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1753,9 +1753,11 @@ public InstanceMethodExpr(String source, int line, int column, Symbol tag, Expr this.tag = tag; this.tailPosition = tailPosition; this.qualifyingClass = qualifyingClass; - if(target.hasJavaClass() && target.getJavaClass() != null) + Class contextClass = qualifyingClass != null ? qualifyingClass : + (target.hasJavaClass() ? target.getJavaClass() : null); + if(contextClass != null) { - List methods = Reflector.getMethods(target.getJavaClass(), args.count(), methodName, false); + List methods = Reflector.getMethods(contextClass, args.count(), methodName, false); if(methods.isEmpty()) { method = null; @@ -1763,7 +1765,7 @@ public InstanceMethodExpr(String source, int line, int column, Symbol tag, Expr { RT.errPrintWriter() .format("Reflection warning, %s:%d:%d - call to method %s on %s can't be resolved (no such method).\n", - SOURCE_PATH.deref(), line, column, methodName, target.getJavaClass().getName()); + SOURCE_PATH.deref(), line, column, methodName, contextClass.getName()); } } else @@ -1793,7 +1795,7 @@ public InstanceMethodExpr(String source, int line, int column, Symbol tag, Expr { RT.errPrintWriter() .format("Reflection warning, %s:%d:%d - call to method %s on %s can't be resolved (argument types: %s).\n", - SOURCE_PATH.deref(), line, column, methodName, target.getJavaClass().getName(), getTypeStringForArgs(args)); + SOURCE_PATH.deref(), line, column, methodName, contextClass.getName(), getTypeStringForArgs(args)); } } } diff --git a/test/clojure/test_clojure/param_tags.clj b/test/clojure/test_clojure/param_tags.clj index 4a2d64d1fc..fee2d1c53e 100644 --- a/test/clojure/test_clojure/param_tags.clj +++ b/test/clojure/test_clojure/param_tags.clj @@ -29,7 +29,21 @@ (^[] java.lang.String/.toUpperCase s))) (should-not-reflect (defn touc-no-reflect-arg-tags [s] - (^[java.util.Locale] String/.toUpperCase s java.util.Locale/ENGLISH)))) + (^[java.util.Locale] String/.toUpperCase s java.util.Locale/ENGLISH))) + (should-not-reflect + (defn no-overloads-no-reflect [v] + (java.time.OffsetDateTime/.getYear v)))) + +(deftest no-param-tags-use-qualifier + ;; both Date and OffsetDateTime have .getYear - want to show here the qualifier is used + (let [f (fn [^java.util.Date d] (java.time.OffsetDateTime/.getYear d)) + date (java.util.Date. 1714495523100)] + ;; works when passed OffsetDateTime + (is (= 2024 (f (-> date .toInstant (.atOffset java.time.ZoneOffset/UTC))))) + + ;; fails when passed Date, expects OffsetDateTime + (is (thrown? ClassCastException + (f date))))) (deftest param-tags-in-invocation-positions (testing "qualified static method invocation" From cee3c1a2a0049025e6559c362d736b8384e51850 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 30 Apr 2024 15:21:33 -0500 Subject: [PATCH 210/285] update to latest github workflow action versions --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b50a9813d1..42b11d66b9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,9 +15,9 @@ jobs: profile: ["test-direct", "test-no-direct"] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: ${{ matrix.java-version }} distribution: ${{ matrix.distribution }} From 6178a59b432670c71f8346083398dbb4f3572877 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Tue, 30 Apr 2024 21:21:29 +0000 Subject: [PATCH 211/285] [maven-release-plugin] prepare release clojure-1.12.0-alpha11 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2dd37faaad..9cc488f7fc 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0-alpha11 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0-alpha11 From 9f4dc520a9ee95fb527152f65900aa2c97cb676e Mon Sep 17 00:00:00 2001 From: clojure-build Date: Tue, 30 Apr 2024 21:21:29 +0000 Subject: [PATCH 212/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9cc488f7fc..2dd37faaad 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-alpha11 + 1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0-alpha11 + HEAD From 8f461351860433220a1709a8a43e1424560f4905 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 6 May 2024 12:13:57 -0500 Subject: [PATCH 213/285] CLJ-2717 nthrest does not return a rest output on n=0 or past end of seq --- src/clj/clojure/core.clj | 18 ++++++----- test/clojure/test_clojure/sequences.clj | 43 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index dc1f02e49b..584899d396 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -3188,14 +3188,16 @@ {:added "1.3" :static true} [coll n] - (if (instance? clojure.lang.IDrop coll) - (if (pos? n) - (or (.drop ^clojure.lang.IDrop coll (if (int? n) n (Math/ceil n))) ()) - coll) - (loop [n n xs coll] - (if-let [xs (and (pos? n) (seq xs))] - (recur (dec n) (rest xs)) - xs)))) + (if (pos? n) + (or + (if (instance? clojure.lang.IDrop coll) + (.drop ^clojure.lang.IDrop coll (if (int? n) n (Math/ceil n))) + (loop [n n xs coll] + (if-let [xs (and (pos? n) (seq xs))] + (recur (dec n) (rest xs)) + (seq xs)))) + ()) + coll)) (defn partition "Returns a lazy sequence of lists of n items each, at offsets step diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj index 624ba7c772..f8f3f5910d 100644 --- a/test/clojure/test_clojure/sequences.clj +++ b/test/clojure/test_clojure/sequences.clj @@ -413,6 +413,49 @@ (next (to-array [(into-array []) nil])) '(nil) (next (to-array [(into-array []) 2 nil])) '(2 nil) )) +(deftest test-nthnext+rest-on-0 + (are [coll] + (and (= (seq coll) (nthnext coll 0)) + (= coll (nthrest coll 0))) + nil + "" + () + '(0) + [] + [0] + #{} + {} + {:a 1} + (range 5))) + +(deftest test-nthnext+rest-on-pos + (are [coll n nthnext-expected nthrest-expected] + (and (= nthnext-expected (nthnext coll n)) + (= nthrest-expected (nthrest coll n))) + + ;coll n nthnext nthrest + nil 1 nil () + "abc" 1 '(\b \c) '(\b \c) + "abc" 3 nil () + "abc" 4 nil () + () 1 nil () + '(1) 1 nil () + '(1) 2 nil () + '(()) 1 nil () + #{} 1 nil () + {:a 1} 1 nil () + [] 1 nil () + [0] 1 nil () + [0] 2 nil () + [[] 2 nil] 1 '(2 nil) '(2 nil) + [[] 2 nil] 2 '(nil) '(nil) + [[] 2 nil] 3 nil () + (sorted-set 1 2 3) 2 '(3) '(3) + (sorted-map :a 1 :b 2) 1 '([:b 2]) '([:b 2]) + (into-array []) 1 nil () + (into-array [1]) 1 nil () + (range 5) 3 '(3 4) '(3 4) + (range 5) 5 nil ())) (deftest test-last (are [x y] (= x y) From 3cff3c1ce23e6abf8aeafa823e09575331a293a5 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 14 May 2024 09:16:48 -0500 Subject: [PATCH 214/285] CLJ-2852 Update deps and build plugin versions --- pom.xml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pom.xml b/pom.xml index 2dd37faaad..df07f56549 100644 --- a/pom.xml +++ b/pom.xml @@ -41,17 +41,17 @@ org.clojure spec.alpha - 0.3.218 + 0.5.238 org.clojure core.specs.alpha - 0.2.62 + 0.4.74 org.clojure test.generative - 1.0.0 + 1.1.0 test @@ -75,7 +75,7 @@ javax.xml.ws jaxws-api - 2.3.0 + 2.3.1 test @@ -103,7 +103,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.1 + 3.13.0 1.8 1.8 @@ -112,7 +112,7 @@ maven-antrun-plugin - 1.6 + 3.1.0 clojure-compile @@ -145,7 +145,7 @@ org.codehaus.mojo build-helper-maven-plugin - 1.5 + 3.5.0 add-clojure-source-dirs @@ -163,7 +163,7 @@ maven-assembly-plugin - 2.2 + 3.7.1 clojure-slim-jar @@ -181,11 +181,11 @@ maven-jar-plugin - 2.3.1 + 3.4.1 maven-source-plugin - 2.1.2 + 3.3.1 attach-sources @@ -207,7 +207,7 @@ instead, push SCM changes in Hudson configuration --> org.apache.maven.plugins maven-release-plugin - 2.5.3 + 3.0.1 false true @@ -217,7 +217,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.6 + 3.2.5 true @@ -227,7 +227,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.8 + 1.6.13 true @@ -261,7 +261,7 @@ maven-assembly-plugin - 2.2 + 3.7.1 clojure-distribution @@ -289,7 +289,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.5 + 3.2.4 sign-artifacts @@ -309,7 +309,7 @@ org.clojure test.check - 0.9.0 + 1.1.1 org.clojure @@ -323,7 +323,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.1.0 + 3.5.3 package From ce1927e74b0c71c93375f1db2758d790a826f32c Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 16 May 2024 10:31:41 -0500 Subject: [PATCH 215/285] Revert "clj-2803 update #inst printer to use thread safe java.time.format.DateTimeFormatter" This reverts commit 213c50e7a34a27901b6db835b87f840a8b2a36ee. --- src/clj/clojure/instant.clj | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/clj/clojure/instant.clj b/src/clj/clojure/instant.clj index 3efc8b6026..2c052c03fa 100644 --- a/src/clj/clojure/instant.clj +++ b/src/clj/clojure/instant.clj @@ -159,18 +159,22 @@ with invalid arguments." ;;; ------------------------------------------------------------------------ ;;; print integration -(def ^:private ^java.time.format.DateTimeFormatter UTC_DATE_FORMATTER - ;; RFC3339 says to use -00:00 when the timezone is unknown (+00:00 implies a known GMT) - (.withZone (java.time.format.DateTimeFormatter/ofPattern "yyyy-MM-dd'T'HH:mm:ss.SSS-00:00") - (java.time.ZoneId/of "GMT"))) + +(def ^:private ^ThreadLocal thread-local-utc-date-format + ;; SimpleDateFormat is not thread-safe, so we use a ThreadLocal proxy for access. + ;; http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4228335 + (proxy [ThreadLocal] [] + (initialValue [] + (doto (java.text.SimpleDateFormat. "yyyy-MM-dd'T'HH:mm:ss.SSS-00:00") + ;; RFC3339 says to use -00:00 when the timezone is unknown (+00:00 implies a known GMT) + (.setTimeZone (java.util.TimeZone/getTimeZone "GMT")))))) (defn- print-date "Print a java.util.Date as RFC3339 timestamp, always in UTC." [^java.util.Date d, ^java.io.Writer w] - (let [instant (.toInstant d) - formatted-date (.format UTC_DATE_FORMATTER instant)] + (let [^java.text.DateFormat utc-format (.get thread-local-utc-date-format)] (.write w "#inst \"") - (.write w formatted-date) + (.write w (.format utc-format d)) (.write w "\""))) (defmethod print-method java.util.Date @@ -202,19 +206,23 @@ with invalid arguments." (print-calendar c w)) -(def ^:private ^java.time.format.DateTimeFormatter UTC_TIMESTAMP_FORMATTER - (.withZone (java.time.format.DateTimeFormatter/ofPattern "yyyy-MM-dd'T'HH:mm:ss.nnnnnnnnn") - (java.time.ZoneId/of "UTC"))) +(def ^:private ^ThreadLocal thread-local-utc-timestamp-format + ;; SimpleDateFormat is not thread-safe, so we use a ThreadLocal proxy for access. + ;; http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4228335 + (proxy [ThreadLocal] [] + (initialValue [] + (doto (java.text.SimpleDateFormat. "yyyy-MM-dd'T'HH:mm:ss") + (.setTimeZone (java.util.TimeZone/getTimeZone "GMT")))))) (defn- print-timestamp "Print a java.sql.Timestamp as RFC3339 timestamp, always in UTC." [^java.sql.Timestamp ts, ^java.io.Writer w] - (let [instant (.toInstant ts) - formatted-date (.format UTC_TIMESTAMP_FORMATTER instant)] + (let [^java.text.DateFormat utc-format (.get thread-local-utc-timestamp-format)] (.write w "#inst \"") - (.write w formatted-date) + (.write w (.format utc-format ts)) + ;; add on nanos and offset ;; RFC3339 says to use -00:00 when the timezone is unknown (+00:00 implies a known GMT) - (.write w "-00:00") + (.write w (format ".%09d-00:00" (.getNanos ts))) (.write w "\""))) (defmethod print-method java.sql.Timestamp @@ -284,4 +292,3 @@ fractional seconds with nanosecond precision. The timezone offset will be used to convert into UTC." [^CharSequence cs] (parse-timestamp (validated construct-timestamp) cs)) - From 58d5c3db0ce0e82ed53c244c0778e057a56ef088 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 16 May 2024 10:25:31 -0500 Subject: [PATCH 216/285] CLJ-2799 Conversion of IFn to Java functional interfaces --- codegen/gen_fn_adapter_tests.clj | 169 ++++ codegen/gen_fn_invokers.clj | 180 ++++ src/jvm/clojure/lang/Compiler.java | 160 +++- src/jvm/clojure/lang/FnInvokers.java | 812 ++++++++++++++++++ src/jvm/clojure/lang/Reflector.java | 29 +- .../generated_all_fi_adapters_in_let.clj | 344 ++++++++ .../generated_functional_adapters_in_def.clj | 231 +++++ ...l_adapters_in_def_requiring_reflection.clj | 231 +++++ test/clojure/test_clojure/java_interop.clj | 221 ++++- test/java/clojure/test/AdapterExerciser.java | 563 ++++++++++++ test/java/clojure/test/FIConstructor.java | 17 + test/java/clojure/test/FIStatic.java | 26 + test/java/clojure/test/FunctionalTester.java | 31 + 13 files changed, 3009 insertions(+), 5 deletions(-) create mode 100644 codegen/gen_fn_adapter_tests.clj create mode 100644 codegen/gen_fn_invokers.clj create mode 100644 src/jvm/clojure/lang/FnInvokers.java create mode 100644 test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj create mode 100644 test/clojure/test_clojure/generated_functional_adapters_in_def.clj create mode 100644 test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj create mode 100644 test/java/clojure/test/AdapterExerciser.java create mode 100644 test/java/clojure/test/FIConstructor.java create mode 100644 test/java/clojure/test/FIStatic.java create mode 100644 test/java/clojure/test/FunctionalTester.java diff --git a/codegen/gen_fn_adapter_tests.clj b/codegen/gen_fn_adapter_tests.clj new file mode 100644 index 0000000000..c8039cedbd --- /dev/null +++ b/codegen/gen_fn_adapter_tests.clj @@ -0,0 +1,169 @@ +;; This code was used to generate: +;; generated_all_fi_adapters_in_let.clj +;; generated_functional_adapters_in_def_requiring_reflection.clj +;; generated_functional_adapters_in_def.clj +;; AdapterExerciser.java +;; This code is not intended to be reused but might be +;; useful in the future as a template for other code gen. + +(ns gen-fn-adapter-tests + (:require + [clojure.string :as str]) + (:import + [java.io StringWriter Writer])) + +(defn let-test-header [imported-methods] + (format " +(ns clojure.test-clojure.generated-all-fi-adapters-in-let + (:use clojure.test) + (:require [clojure.string :as str]) + (:import (clojure.test %s))) + + (deftest test-all-fi-adapters-in-let + (let [^AdapterExerciser exerciser (AdapterExerciser.)" imported-methods)) + +(defn def-test-header [filename] + (format " +(ns clojure.test-clojure.%s + (:use clojure.test) + (:require [clojure.string :as str]) + (:import (clojure.test AdapterExerciser))) + + (deftest functional-adapters-in-def + (def exerciser (AdapterExerciser.))" filename)) + +(def adapter-exerciser-header " +package clojure.test; + +public class AdapterExerciser {") + +(defn sigs [args return-types] + (let [fun-sig-reducer (fn [res ret] + (mapcat seq [res (map (fn [params] + (str params ret)) args)]))] + (reduce fun-sig-reducer [] return-types))) + +(defn gen-sigs [] + (let [small-rets ["L" "I" "S" "B" "D" "F" "Z" "O"] + single-arity (sigs ["L" "D" "O"] small-rets) + two-arity (sigs ["LL" "LO" "OL" "DD" "LD" "DL" "OO" "OD" "DO"] small-rets) + big-rets ["Z" "O"] + three-arity (sigs ["OOO"] big-rets) + four-arity (sigs ["OOOO"] big-rets) + five-arity (sigs ["OOOOO"] big-rets) + six-arity (sigs ["OOOOOO"] big-rets) + seven-arity (sigs ["OOOOOOO"] big-rets) + eight-arity (sigs ["OOOOOOOO"] big-rets) + nine-arity (sigs ["OOOOOOOOO"] big-rets) + ten-arity (sigs ["OOOOOOOOOO"] big-rets)] + (mapcat seq [single-arity two-arity three-arity four-arity five-arity six-arity seven-arity eight-arity nine-arity ten-arity]))) + +(def alphabet (map char (range 97 122))) +(def type-hints {:D "^double " + :O "^AdapterExerciser " + :L "^long " + :I "^int " + :F "^float " + :Z "^boolean " + :S "^short " + :B "^byte "}) +(def types {:D "double" + :O "AdapterExerciser" + :L "long" + :I "int" + :F "float" + :Z "boolean" + :S "short" + :B "byte"}) +(def method-args {:D "(double 1)" + :O "exerciser" + :L "(long 1)" + :I "1" + :F "(float 1)" + :Z "false" + :S "(short 1)" + :B "(byte 1)"}) + +(defn format-parts [sig] + (let [return-type-initial (str (last sig)) + return-type (get types (keyword return-type-initial)) + input-types (map str (butlast sig)) + arg-type-hints (map #(get type-hints (keyword %)) input-types) + java-types (map #(get types (keyword %)) input-types) + fn-vars (str/join " " (map #(str %1 %2) arg-type-hints (take (count input-types) alphabet))) + fn-args (str/join " " (map #(get method-args (keyword %)) input-types)) + java-vars (str/join ", " (map #(str %1 " " %2) java-types (take (count input-types) alphabet))) + fn-body (get method-args (keyword return-type-initial)) + expected-val (get method-args (keyword return-type-initial))] + {:return-type return-type :fn-args fn-args :return-type-initial return-type-initial :fn-vars fn-vars :fn-body fn-body :input-types input-types :java-vars java-vars :expected-val expected-val})) + +(defn gen-imported-methods [sigs] + (let [sb (StringBuilder. " ")] + (doseq [sig sigs] + (.append sb (format "AdapterExerciser$%s" sig)) + (.append sb "\n")) + (.toString sb))) + +(defn gen-test-all-fi-adapters-in-let [] + (let [adapter-signatures (gen-sigs) + imported-methods (gen-imported-methods adapter-signatures) + sb (StringBuilder. ^String (let-test-header imported-methods))] + ;; Assemble let + (doseq [sig adapter-signatures] + (let [{:keys [fn-vars fn-body]} (format-parts sig)] + (.append sb "\n") + (.append sb (format " ^AdapterExerciser$%s %sadapter (fn [%s] %s)" sig sig fn-vars fn-body)))) + (.append sb "]") + ;; Assemble test cases + (doseq [sig adapter-signatures] + (let [{:keys [return-type-initial fn-args expected-val]} (format-parts sig)] + (.append sb "\n") + (.append sb (format " (is (= (.takes%sRet%s %sadapter %s) %s))" (str/join "" (butlast sig)) return-type-initial sig fn-args expected-val)))) + (.append sb "))") + (spit "generated_all_fi_adapters_in_let.clj" (.toString sb)))) + +(defn gen-test-functional-adapters-in-def [] + (let [sb (StringBuilder. ^String (def-test-header "generated-functional-adapters-in-def")) + adapter-signatures (gen-sigs)] + (doseq [[idx sig] (map-indexed (fn [idx itm] [idx itm]) adapter-signatures)] + (let [{:keys [fn-vars fn-body]} (format-parts sig)] + (.append sb "\n") + (.append sb (format " (def %sadapter (fn [%s] %s))" sig fn-vars fn-body)) + (.append sb "\n") + (.append sb (format " (is (= (.method%s ^AdapterExerciser exerciser %sadapter) %s))" sig sig idx)))) + (.append sb ")") + (spit "generated_functional_adapters_in_def.clj" (.toString sb)))) + +(defn gen-test-functional-adapters-in-def-requiring-reflection [] + (let [sb (StringBuilder. ^String (def-test-header "generated-functional-adapters-in-def-requiring-reflection")) + adapter-signatures (gen-sigs)] + (doseq [[idx sig] (map-indexed (fn [idx itm] [idx itm]) adapter-signatures)] + (let [{:keys [fn-vars fn-body]} (format-parts sig)] + (.append sb "\n") + (.append sb (format " (def %sadapter (fn [%s] %s))" sig fn-vars fn-body)) + (.append sb "\n") + (.append sb (format " (is (= (.method%s exerciser %sadapter) %s))" sig sig idx)))) + (.append sb ")") + (spit "generated_functional_adapters_in_def_requiring_reflection.clj" (.toString sb)))) + +(defn gen-adapter-exerciser-class [] + (let [sb (StringBuilder. ^String adapter-exerciser-header) + adapter-signatures (gen-sigs)] + (doseq [sig adapter-signatures] + (let [{:keys [return-type return-type-initial input-types java-vars]} (format-parts sig)] + (.append sb "\n") + (.append sb " @FunctionalInterface\n") + (.append sb (format " public interface %s {\n" sig)) + (.append sb (format " public %s takes%sRet%s(%s);\n" return-type (str/join "" input-types) return-type-initial java-vars)) + (.append sb " }"))) + (doseq [[idx sig] (map-indexed (fn [idx itm] [idx itm]) adapter-signatures)] + (.append sb "\n") + (.append sb (format " public int method%s(%s a) { return %s; }" sig sig idx))) + (.append sb "}") + (spit "AdapterExerciser.java" (.toString sb)))) + +(comment + (gen-test-all-fi-adapters-in-let) + (gen-test-functional-adapters-in-def) + (gen-test-functional-adapters-in-def-requiring-reflection) + (gen-adapter-exerciser-class)) \ No newline at end of file diff --git a/codegen/gen_fn_invokers.clj b/codegen/gen_fn_invokers.clj new file mode 100644 index 0000000000..2bb9baf6e6 --- /dev/null +++ b/codegen/gen_fn_invokers.clj @@ -0,0 +1,180 @@ +;; This code was used to generate the clojure.lang.FnInvokers class in +;; Clojure 1.12. This code is not intended to be reused but might be +;; useful in the future as a template for other code gen. + +(ns gen-fn-invokers + (:require + [clojure.string :as str])) + +(def header + "/** + * Copyright (c) Rich Hickey. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (https://opensource.org/license/epl-1-0) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +package clojure.lang; + +public class FnInvokers { + + // Encode invoker param/return class to code for method name + static char encodeInvokerType(Class c) { + if(Long.TYPE.equals(c)) { + return 'L'; + } else if(Double.TYPE.equals(c)) { + return 'D'; + } else if(Integer.TYPE.equals(c)) { + return 'I'; + } else if(Short.TYPE.equals(c)) { + return 'S'; + } else if(Byte.TYPE.equals(c)) { + return 'B'; + } else if(Float.TYPE.equals(c)) { + return 'F'; + } else if(Boolean.TYPE.equals(c)) { + return 'Z'; + } else { + return 'O'; + } + } + +") + +(def footer + "}") + +(def invokeO-format + " public static Object invoke%sO(IFn f0%s) { + return f0.invoke(%s); + }") + +(def invokeO-with-l-or-d-arg-format + " public static Object invoke%sO(IFn f0%s) { + if(f0 instanceof IFn.%sO) { + return ((IFn.%sO)f0).invokePrim(%s); + } else { + return f0.invoke(%s); + } + }") + +(def invokeZ-format + " public static boolean invoke%sZ(IFn f0%s) { + return RT.booleanCast(f0.invoke(%s)); + }") + +(def invokeD-format + " public static double invoke%sD(IFn f0%s) { + if(f0 instanceof IFn.%sD) { + return ((IFn.%sD)f0).invokePrim(%s); + } else { + return RT.doubleCast(f0.invoke(%s)); + } + }") + +(def invokeF-format + " public static float invoke%sF(IFn f0%s) { + if(f0 instanceof IFn.%sD) { + return RT.floatCast(((IFn.%sD)f0).invokePrim(%s)); + } else { + return RT.floatCast(f0.invoke(%s)); + } + }") + +(def invokeL-format + " public static long invoke%sL(IFn f0%s) { + if(f0 instanceof IFn.%sL) { + return ((IFn.%sL)f0).invokePrim(%s); + } else { + return RT.longCast(f0.invoke(%s)); + } + }") + +(def invokeI-format + " public static int invoke%sI(IFn f0%s) { + if(f0 instanceof IFn.%sL) { + return RT.intCast(((IFn.%sL)f0).invokePrim(%s)); + } else { + return RT.intCast(f0.invoke(%s)); + } + }") + +(def invokeS-format + " public static short invoke%sS(IFn f0%s) { + if(f0 instanceof IFn.%sL) { + return RT.shortCast(((IFn.%sL)f0).invokePrim(%s)); + } else { + return RT.shortCast(f0.invoke(%s)); + } + }") + +(def invokeB-format + " public static byte invoke%sB(IFn f0%s) { + if(f0 instanceof IFn.%sL) { + return RT.byteCast(((IFn.%sL)f0).invokePrim(%s)); + } else { + return RT.byteCast(f0.invoke(%s)); + } + }") + +(def alphabet (map char (range 97 122))) + +(def arg-types {:D ", double " + :L ", long " + :O ", Object "}) + +(defn gen-invoke [sig] + (let [formatter (str (last sig)) + args (map str (butlast sig)) + arg-types (map #(get arg-types (keyword %)) args) + fn-vars (str/join "" (map #(str %1 %2) arg-types (take (count args) alphabet))) + fn-vars-sans-type (str/join ", " (take (count args) alphabet)) + arg-str (str/join args)] + (case formatter + "O" (if (some #{"D" "L"} args) + (format invokeO-with-l-or-d-arg-format arg-str fn-vars arg-str arg-str fn-vars-sans-type fn-vars-sans-type) + (format invokeO-format arg-str fn-vars fn-vars-sans-type)) + "L" (format invokeL-format arg-str fn-vars arg-str arg-str fn-vars-sans-type fn-vars-sans-type) + "I" (format invokeI-format arg-str fn-vars arg-str arg-str fn-vars-sans-type fn-vars-sans-type) + "S" (format invokeS-format arg-str fn-vars arg-str arg-str fn-vars-sans-type fn-vars-sans-type) + "B" (format invokeB-format arg-str fn-vars arg-str arg-str fn-vars-sans-type fn-vars-sans-type) + "D" (format invokeD-format arg-str fn-vars arg-str arg-str fn-vars-sans-type fn-vars-sans-type) + "F" (format invokeF-format arg-str fn-vars arg-str arg-str fn-vars-sans-type fn-vars-sans-type) + "Z" (format invokeZ-format arg-str fn-vars fn-vars-sans-type)))) + +(defn sigs [args return-types] + (let [fun-sig-reducer (fn [res ret] + (mapcat seq [res (map (fn [params] + (str params ret)) args)]))] + (reduce fun-sig-reducer [] return-types))) + +(defn gen-sigs [] + (let [small-rets ["L" "I" "S" "B" "D" "F" "Z" "O"] + single-arity (sigs ["L" "D" "O"] small-rets) + two-arity (sigs ["LL" "LO" "OL" "DD" "LD" "DL" "OO" "OD" "DO"] small-rets) + big-rets ["Z" "O"] + three-arity (sigs ["OOO"] big-rets) + four-arity (sigs ["OOOO"] big-rets) + five-arity (sigs ["OOOOO"] big-rets) + six-arity (sigs ["OOOOOO"] big-rets) + seven-arity (sigs ["OOOOOOO"] big-rets) + eight-arity (sigs ["OOOOOOOO"] big-rets) + nine-arity (sigs ["OOOOOOOOO"] big-rets) + ten-arity (sigs ["OOOOOOOOOO"] big-rets)] + (mapcat seq [single-arity two-arity three-arity four-arity five-arity six-arity seven-arity eight-arity nine-arity ten-arity]))) + +(defn gen-invokers [] + (let [sb (StringBuilder. ^String header) + invoker-signatures (gen-sigs)] + (doseq [sig invoker-signatures] + (.append sb (gen-invoke sig)) + (.append sb "\n\n")) + (.append sb footer) + (spit "src/jvm/clojure/lang/FnInvokers.java" (.toString sb)))) + +(comment + (gen-invokers) + ) \ No newline at end of file diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 3e123e3495..64b4171a55 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -20,10 +20,12 @@ import clojure.asm.commons.Method; import java.io.*; +import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.lang.reflect.Executable; import java.util.*; +import java.util.concurrent.Callable; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.util.stream.Collectors; @@ -1611,6 +1613,157 @@ static Class maybePrimitiveType(Expr e){ return null; } +static class FISupport { + private static final IPersistentSet AFN_FIS = RT.set(Callable.class, Runnable.class, Comparator.class); + private static final IPersistentSet OBJECT_METHODS = RT.set("equals", "toString", "hashCode"); + + // Return FI method if: + // 1) Target is a functional interface and not already implemented by AFn + // 2) Target method matches one of our fn invoker methods (0 < arity <= 10) + static java.lang.reflect.Method maybeFIMethod(Class target) { + if (target != null && target.isAnnotationPresent(FunctionalInterface.class) + && !AFN_FIS.contains(target)) { + + java.lang.reflect.Method[] methods = target.getMethods(); + for (java.lang.reflect.Method method : methods) { + // We do not support arity=0 (e.g. Supplier) b/c not functional - use IDeref instead + if (method.getParameterCount() > 0 && method.getParameterCount() <= 10 + && Modifier.isAbstract(method.getModifiers()) + && !OBJECT_METHODS.contains(method.getName())) + return method; + } + } + return null; + } + + // Invokers support only long, double, Object params; widen numerics + private static Class toInvokerParamType(Class c) { + if (c.equals(Byte.TYPE) || c.equals(Short.TYPE) || c.equals(Integer.TYPE) || c.equals(Long.TYPE)) { + return Long.TYPE; + } else if (c.equals(Float.TYPE) || c.equals(Double.TYPE)) { + return Double.TYPE; + } + return Object.class; + } + + /** + * If targetClass is FI and has an adaptable functional method + * Find fn invoker method matching adaptable method of FI + * Emit bytecode for (expr is emitted): + * if(expr instanceof IFn) + * invokeDynamic(targetMethod, fnInvokerImplMethod) + * Else emit nothing + */ + static boolean maybeEmitFIAdapter(ObjExpr objx, GeneratorAdapter gen, Expr expr, Class targetClass) { + // Optimization: + // if(expr instanceof QualifiedMethodExpr) + // emitInvokeDynamic(targetMethod, QME method) // DON'T emit expr + + java.lang.reflect.Method targetMethod = maybeFIMethod(targetClass); + if (targetMethod == null) + return false; + + // compute fn invoker method + int paramCount = targetMethod.getParameterCount(); + Class[] invokerParams = new Class[paramCount + 1]; + invokerParams[0] = IFn.class; // close over Ifn as first arg + StringBuilder invokeMethodBuilder = new StringBuilder("invoke"); + for (int i = 0; i < paramCount; i++) { + // FnInvokers only has prims for first 2 args + invokerParams[i + 1] = paramCount <= 2 ? toInvokerParamType(targetMethod.getParameterTypes()[i]) : Object.class; + invokeMethodBuilder.append(FnInvokers.encodeInvokerType(invokerParams[i + 1])); + } + char invokerReturnCode = FnInvokers.encodeInvokerType(targetMethod.getReturnType()); + invokeMethodBuilder.append(invokerReturnCode); + String invokerMethodName = invokeMethodBuilder.toString(); + + // Emit adapter to fn invoker method + Type samType = Type.getType(targetClass); + Type ifnType = Type.getType(IFn.class); + try { + java.lang.reflect.Method fnInvokerMethod = FnInvokers.class.getMethod(invokerMethodName, invokerParams); + + // if(exp instanceof IFn) { emitInvokeDynamic(targetMethod, fnInvokerMethod) } + expr.emit(C.EXPRESSION, objx, gen); + gen.dup(); + gen.instanceOf(ifnType); + + // if not instanceof IFn, go to end + Label endLabel = gen.newLabel(); + gen.ifZCmp(Opcodes.IFEQ, endLabel); + + // else adapt fn invoker method as impl for target method + emitInvokeDynamicAdapter(gen, targetClass, targetMethod, FnInvokers.class, fnInvokerMethod); + + // end - checkcast that we have the target FI type + gen.mark(endLabel); + gen.checkCast(samType); + return true; + } catch (NoSuchMethodException e) { + throw Util.sneakyThrow(e); // should never happen + } + + } + + // LambdaMetafactory.metafactory() method handle for lambda bootstrap + private static final Handle LMF_HANDLE = + new Handle(Opcodes.H_INVOKESTATIC, + "java/lang/invoke/LambdaMetafactory", + "metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", + false); + + /** + * Emit an invokedynamic to adapt an implMethod to act as a targetMethod. + * + * implMethod may be a static method, a constructor, or an instance method. If it is an + * instance method, the first argument is the invocation instance. + * + * The implMethod may close over objects on the stack - these are passed as the initial arguments + * to implMethod. The trailing arguments must match the targetMethod arguments. + * + * See: https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/LambdaMetafactory.html + * @param gen ASM code generator, expects any closed-overs to be on the stack already + * @param targetClass The target class + * @param targetMethod The target method + * @param implClass The impl class + * @param implMethod The impl method that will be adapted, takes closed-overs + args of targetMethod + */ + static void emitInvokeDynamicAdapter(GeneratorAdapter gen, + Class targetClass, java.lang.reflect.Method targetMethod, + Class implClass, Executable implMethod) { + + // Impl method - takes closed overs (on stack now) + args (when called) + Class[] implParams = implMethod.getParameterTypes(); + Class retClass = isConstructor(implMethod) ? implClass + : ((java.lang.reflect.Method) implMethod).getReturnType(); + + int opCode = isConstructor(implMethod) ? Opcodes.H_INVOKESPECIAL : + (isStaticMethod(implMethod) ? Opcodes.H_INVOKESTATIC : + Opcodes.H_INVOKEVIRTUAL); + + Handle implHandle = new Handle(opCode, + Type.getInternalName(implClass), + implMethod.getName(), + MethodType.methodType(retClass, implParams).toMethodDescriptorString(), + false); + + // Adapter interface lambda-style: (closedOver*) -> targetType + int implArgCount = implParams.length; + if (isInstanceMethod(implMethod)) // instance is first "arg" + implArgCount++; + List lambdaParams = Arrays.asList(Arrays.copyOfRange(implParams, 0, implArgCount - targetMethod.getParameterCount())); + MethodType lambdaSig = MethodType.methodType(targetClass, lambdaParams); + + Type targetType = Type.getType(targetMethod); + gen.visitInvokeDynamicInsn( + targetMethod.getName(), + lambdaSig.toMethodDescriptorString(), // adapter signature, closedOvers -> target + LMF_HANDLE, // bootstrap method handle: LambdaMetaFactory.metafactory() + new Object[]{targetType, implHandle, targetType}); // arg types of bootstrap method + } +} + static Class maybeJavaClass(Collection exprs){ Class match = null; try @@ -1690,7 +1843,7 @@ else if(primc == double.class && parameterTypes[i] == float.class) pe.emitUnboxed(C.EXPRESSION, objx, gen); gen.visitInsn(D2F); } - else + else if(!FISupport.maybeEmitFIAdapter(objx, gen, e, parameterTypes[i])) { e.emit(C.EXPRESSION, objx, gen); HostExpr.emitUnboxArg(objx, gen, parameterTypes[i]); @@ -6853,7 +7006,10 @@ public void doEmit(C context, ObjExpr objx, GeneratorAdapter gen, boolean emitUn } else { - bi.init.emit(C.EXPRESSION, objx, gen); + Class bindingClass = HostExpr.maybeClass(bi.binding.tag, true); + if(!FISupport.maybeEmitFIAdapter(objx, gen, bi.init, bindingClass)) + bi.init.emit(C.EXPRESSION, objx, gen); + if (!bi.binding.used && bi.binding.canBeCleared) gen.pop(); else diff --git a/src/jvm/clojure/lang/FnInvokers.java b/src/jvm/clojure/lang/FnInvokers.java new file mode 100644 index 0000000000..a95afaa2f0 --- /dev/null +++ b/src/jvm/clojure/lang/FnInvokers.java @@ -0,0 +1,812 @@ +/** + * Copyright (c) Rich Hickey. All rights reserved. + * The use and distribution terms for this software are covered by the + * Eclipse Public License 1.0 (https://opensource.org/license/epl-1-0) + * which can be found in the file epl-v10.html at the root of this distribution. + * By using this software in any fashion, you are agreeing to be bound by + * the terms of this license. + * You must not remove this notice, or any other, from this software. + **/ + +package clojure.lang; + +public class FnInvokers { + + // Encode invoker param/return class to code for method name + static char encodeInvokerType(Class c) { + if(Long.TYPE.equals(c)) { + return 'L'; + } else if(Double.TYPE.equals(c)) { + return 'D'; + } else if(Integer.TYPE.equals(c)) { + return 'I'; + } else if(Short.TYPE.equals(c)) { + return 'S'; + } else if(Byte.TYPE.equals(c)) { + return 'B'; + } else if(Float.TYPE.equals(c)) { + return 'F'; + } else if(Boolean.TYPE.equals(c)) { + return 'Z'; + } else { + return 'O'; + } + } + + public static long invokeLL(IFn f0, long a) { + if(f0 instanceof IFn.LL) { + return ((IFn.LL)f0).invokePrim(a); + } else { + return RT.longCast(f0.invoke(a)); + } + } + + public static long invokeDL(IFn f0, double a) { + if(f0 instanceof IFn.DL) { + return ((IFn.DL)f0).invokePrim(a); + } else { + return RT.longCast(f0.invoke(a)); + } + } + + public static long invokeOL(IFn f0, Object a) { + if(f0 instanceof IFn.OL) { + return ((IFn.OL)f0).invokePrim(a); + } else { + return RT.longCast(f0.invoke(a)); + } + } + + public static int invokeLI(IFn f0, long a) { + if(f0 instanceof IFn.LL) { + return RT.intCast(((IFn.LL)f0).invokePrim(a)); + } else { + return RT.intCast(f0.invoke(a)); + } + } + + public static int invokeDI(IFn f0, double a) { + if(f0 instanceof IFn.DL) { + return RT.intCast(((IFn.DL)f0).invokePrim(a)); + } else { + return RT.intCast(f0.invoke(a)); + } + } + + public static int invokeOI(IFn f0, Object a) { + if(f0 instanceof IFn.OL) { + return RT.intCast(((IFn.OL)f0).invokePrim(a)); + } else { + return RT.intCast(f0.invoke(a)); + } + } + + public static short invokeLS(IFn f0, long a) { + if(f0 instanceof IFn.LL) { + return RT.shortCast(((IFn.LL)f0).invokePrim(a)); + } else { + return RT.shortCast(f0.invoke(a)); + } + } + + public static short invokeDS(IFn f0, double a) { + if(f0 instanceof IFn.DL) { + return RT.shortCast(((IFn.DL)f0).invokePrim(a)); + } else { + return RT.shortCast(f0.invoke(a)); + } + } + + public static short invokeOS(IFn f0, Object a) { + if(f0 instanceof IFn.OL) { + return RT.shortCast(((IFn.OL)f0).invokePrim(a)); + } else { + return RT.shortCast(f0.invoke(a)); + } + } + + public static byte invokeLB(IFn f0, long a) { + if(f0 instanceof IFn.LL) { + return RT.byteCast(((IFn.LL)f0).invokePrim(a)); + } else { + return RT.byteCast(f0.invoke(a)); + } + } + + public static byte invokeDB(IFn f0, double a) { + if(f0 instanceof IFn.DL) { + return RT.byteCast(((IFn.DL)f0).invokePrim(a)); + } else { + return RT.byteCast(f0.invoke(a)); + } + } + + public static byte invokeOB(IFn f0, Object a) { + if(f0 instanceof IFn.OL) { + return RT.byteCast(((IFn.OL)f0).invokePrim(a)); + } else { + return RT.byteCast(f0.invoke(a)); + } + } + + public static double invokeLD(IFn f0, long a) { + if(f0 instanceof IFn.LD) { + return ((IFn.LD)f0).invokePrim(a); + } else { + return RT.doubleCast(f0.invoke(a)); + } + } + + public static double invokeDD(IFn f0, double a) { + if(f0 instanceof IFn.DD) { + return ((IFn.DD)f0).invokePrim(a); + } else { + return RT.doubleCast(f0.invoke(a)); + } + } + + public static double invokeOD(IFn f0, Object a) { + if(f0 instanceof IFn.OD) { + return ((IFn.OD)f0).invokePrim(a); + } else { + return RT.doubleCast(f0.invoke(a)); + } + } + + public static float invokeLF(IFn f0, long a) { + if(f0 instanceof IFn.LD) { + return RT.floatCast(((IFn.LD)f0).invokePrim(a)); + } else { + return RT.floatCast(f0.invoke(a)); + } + } + + public static float invokeDF(IFn f0, double a) { + if(f0 instanceof IFn.DD) { + return RT.floatCast(((IFn.DD)f0).invokePrim(a)); + } else { + return RT.floatCast(f0.invoke(a)); + } + } + + public static float invokeOF(IFn f0, Object a) { + if(f0 instanceof IFn.OD) { + return RT.floatCast(((IFn.OD)f0).invokePrim(a)); + } else { + return RT.floatCast(f0.invoke(a)); + } + } + + public static boolean invokeLZ(IFn f0, long a) { + return RT.booleanCast(f0.invoke(a)); + } + + public static boolean invokeDZ(IFn f0, double a) { + return RT.booleanCast(f0.invoke(a)); + } + + public static boolean invokeOZ(IFn f0, Object a) { + return RT.booleanCast(f0.invoke(a)); + } + + public static Object invokeLO(IFn f0, long a) { + if(f0 instanceof IFn.LO) { + return ((IFn.LO)f0).invokePrim(a); + } else { + return f0.invoke(a); + } + } + + public static Object invokeDO(IFn f0, double a) { + if(f0 instanceof IFn.DO) { + return ((IFn.DO)f0).invokePrim(a); + } else { + return f0.invoke(a); + } + } + + public static Object invokeOO(IFn f0, Object a) { + return f0.invoke(a); + } + + public static long invokeLLL(IFn f0, long a, long b) { + if(f0 instanceof IFn.LLL) { + return ((IFn.LLL)f0).invokePrim(a, b); + } else { + return RT.longCast(f0.invoke(a, b)); + } + } + + public static long invokeLOL(IFn f0, long a, Object b) { + if(f0 instanceof IFn.LOL) { + return ((IFn.LOL)f0).invokePrim(a, b); + } else { + return RT.longCast(f0.invoke(a, b)); + } + } + + public static long invokeOLL(IFn f0, Object a, long b) { + if(f0 instanceof IFn.OLL) { + return ((IFn.OLL)f0).invokePrim(a, b); + } else { + return RT.longCast(f0.invoke(a, b)); + } + } + + public static long invokeDDL(IFn f0, double a, double b) { + if(f0 instanceof IFn.DDL) { + return ((IFn.DDL)f0).invokePrim(a, b); + } else { + return RT.longCast(f0.invoke(a, b)); + } + } + + public static long invokeLDL(IFn f0, long a, double b) { + if(f0 instanceof IFn.LDL) { + return ((IFn.LDL)f0).invokePrim(a, b); + } else { + return RT.longCast(f0.invoke(a, b)); + } + } + + public static long invokeDLL(IFn f0, double a, long b) { + if(f0 instanceof IFn.DLL) { + return ((IFn.DLL)f0).invokePrim(a, b); + } else { + return RT.longCast(f0.invoke(a, b)); + } + } + + public static long invokeOOL(IFn f0, Object a, Object b) { + if(f0 instanceof IFn.OOL) { + return ((IFn.OOL)f0).invokePrim(a, b); + } else { + return RT.longCast(f0.invoke(a, b)); + } + } + + public static long invokeODL(IFn f0, Object a, double b) { + if(f0 instanceof IFn.ODL) { + return ((IFn.ODL)f0).invokePrim(a, b); + } else { + return RT.longCast(f0.invoke(a, b)); + } + } + + public static long invokeDOL(IFn f0, double a, Object b) { + if(f0 instanceof IFn.DOL) { + return ((IFn.DOL)f0).invokePrim(a, b); + } else { + return RT.longCast(f0.invoke(a, b)); + } + } + + public static int invokeLLI(IFn f0, long a, long b) { + if(f0 instanceof IFn.LLL) { + return RT.intCast(((IFn.LLL)f0).invokePrim(a, b)); + } else { + return RT.intCast(f0.invoke(a, b)); + } + } + + public static int invokeLOI(IFn f0, long a, Object b) { + if(f0 instanceof IFn.LOL) { + return RT.intCast(((IFn.LOL)f0).invokePrim(a, b)); + } else { + return RT.intCast(f0.invoke(a, b)); + } + } + + public static int invokeOLI(IFn f0, Object a, long b) { + if(f0 instanceof IFn.OLL) { + return RT.intCast(((IFn.OLL)f0).invokePrim(a, b)); + } else { + return RT.intCast(f0.invoke(a, b)); + } + } + + public static int invokeDDI(IFn f0, double a, double b) { + if(f0 instanceof IFn.DDL) { + return RT.intCast(((IFn.DDL)f0).invokePrim(a, b)); + } else { + return RT.intCast(f0.invoke(a, b)); + } + } + + public static int invokeLDI(IFn f0, long a, double b) { + if(f0 instanceof IFn.LDL) { + return RT.intCast(((IFn.LDL)f0).invokePrim(a, b)); + } else { + return RT.intCast(f0.invoke(a, b)); + } + } + + public static int invokeDLI(IFn f0, double a, long b) { + if(f0 instanceof IFn.DLL) { + return RT.intCast(((IFn.DLL)f0).invokePrim(a, b)); + } else { + return RT.intCast(f0.invoke(a, b)); + } + } + + public static int invokeOOI(IFn f0, Object a, Object b) { + if(f0 instanceof IFn.OOL) { + return RT.intCast(((IFn.OOL)f0).invokePrim(a, b)); + } else { + return RT.intCast(f0.invoke(a, b)); + } + } + + public static int invokeODI(IFn f0, Object a, double b) { + if(f0 instanceof IFn.ODL) { + return RT.intCast(((IFn.ODL)f0).invokePrim(a, b)); + } else { + return RT.intCast(f0.invoke(a, b)); + } + } + + public static int invokeDOI(IFn f0, double a, Object b) { + if(f0 instanceof IFn.DOL) { + return RT.intCast(((IFn.DOL)f0).invokePrim(a, b)); + } else { + return RT.intCast(f0.invoke(a, b)); + } + } + + public static short invokeLLS(IFn f0, long a, long b) { + if(f0 instanceof IFn.LLL) { + return RT.shortCast(((IFn.LLL)f0).invokePrim(a, b)); + } else { + return RT.shortCast(f0.invoke(a, b)); + } + } + + public static short invokeLOS(IFn f0, long a, Object b) { + if(f0 instanceof IFn.LOL) { + return RT.shortCast(((IFn.LOL)f0).invokePrim(a, b)); + } else { + return RT.shortCast(f0.invoke(a, b)); + } + } + + public static short invokeOLS(IFn f0, Object a, long b) { + if(f0 instanceof IFn.OLL) { + return RT.shortCast(((IFn.OLL)f0).invokePrim(a, b)); + } else { + return RT.shortCast(f0.invoke(a, b)); + } + } + + public static short invokeDDS(IFn f0, double a, double b) { + if(f0 instanceof IFn.DDL) { + return RT.shortCast(((IFn.DDL)f0).invokePrim(a, b)); + } else { + return RT.shortCast(f0.invoke(a, b)); + } + } + + public static short invokeLDS(IFn f0, long a, double b) { + if(f0 instanceof IFn.LDL) { + return RT.shortCast(((IFn.LDL)f0).invokePrim(a, b)); + } else { + return RT.shortCast(f0.invoke(a, b)); + } + } + + public static short invokeDLS(IFn f0, double a, long b) { + if(f0 instanceof IFn.DLL) { + return RT.shortCast(((IFn.DLL)f0).invokePrim(a, b)); + } else { + return RT.shortCast(f0.invoke(a, b)); + } + } + + public static short invokeOOS(IFn f0, Object a, Object b) { + if(f0 instanceof IFn.OOL) { + return RT.shortCast(((IFn.OOL)f0).invokePrim(a, b)); + } else { + return RT.shortCast(f0.invoke(a, b)); + } + } + + public static short invokeODS(IFn f0, Object a, double b) { + if(f0 instanceof IFn.ODL) { + return RT.shortCast(((IFn.ODL)f0).invokePrim(a, b)); + } else { + return RT.shortCast(f0.invoke(a, b)); + } + } + + public static short invokeDOS(IFn f0, double a, Object b) { + if(f0 instanceof IFn.DOL) { + return RT.shortCast(((IFn.DOL)f0).invokePrim(a, b)); + } else { + return RT.shortCast(f0.invoke(a, b)); + } + } + + public static byte invokeLLB(IFn f0, long a, long b) { + if(f0 instanceof IFn.LLL) { + return RT.byteCast(((IFn.LLL)f0).invokePrim(a, b)); + } else { + return RT.byteCast(f0.invoke(a, b)); + } + } + + public static byte invokeLOB(IFn f0, long a, Object b) { + if(f0 instanceof IFn.LOL) { + return RT.byteCast(((IFn.LOL)f0).invokePrim(a, b)); + } else { + return RT.byteCast(f0.invoke(a, b)); + } + } + + public static byte invokeOLB(IFn f0, Object a, long b) { + if(f0 instanceof IFn.OLL) { + return RT.byteCast(((IFn.OLL)f0).invokePrim(a, b)); + } else { + return RT.byteCast(f0.invoke(a, b)); + } + } + + public static byte invokeDDB(IFn f0, double a, double b) { + if(f0 instanceof IFn.DDL) { + return RT.byteCast(((IFn.DDL)f0).invokePrim(a, b)); + } else { + return RT.byteCast(f0.invoke(a, b)); + } + } + + public static byte invokeLDB(IFn f0, long a, double b) { + if(f0 instanceof IFn.LDL) { + return RT.byteCast(((IFn.LDL)f0).invokePrim(a, b)); + } else { + return RT.byteCast(f0.invoke(a, b)); + } + } + + public static byte invokeDLB(IFn f0, double a, long b) { + if(f0 instanceof IFn.DLL) { + return RT.byteCast(((IFn.DLL)f0).invokePrim(a, b)); + } else { + return RT.byteCast(f0.invoke(a, b)); + } + } + + public static byte invokeOOB(IFn f0, Object a, Object b) { + if(f0 instanceof IFn.OOL) { + return RT.byteCast(((IFn.OOL)f0).invokePrim(a, b)); + } else { + return RT.byteCast(f0.invoke(a, b)); + } + } + + public static byte invokeODB(IFn f0, Object a, double b) { + if(f0 instanceof IFn.ODL) { + return RT.byteCast(((IFn.ODL)f0).invokePrim(a, b)); + } else { + return RT.byteCast(f0.invoke(a, b)); + } + } + + public static byte invokeDOB(IFn f0, double a, Object b) { + if(f0 instanceof IFn.DOL) { + return RT.byteCast(((IFn.DOL)f0).invokePrim(a, b)); + } else { + return RT.byteCast(f0.invoke(a, b)); + } + } + + public static double invokeLLD(IFn f0, long a, long b) { + if(f0 instanceof IFn.LLD) { + return ((IFn.LLD)f0).invokePrim(a, b); + } else { + return RT.doubleCast(f0.invoke(a, b)); + } + } + + public static double invokeLOD(IFn f0, long a, Object b) { + if(f0 instanceof IFn.LOD) { + return ((IFn.LOD)f0).invokePrim(a, b); + } else { + return RT.doubleCast(f0.invoke(a, b)); + } + } + + public static double invokeOLD(IFn f0, Object a, long b) { + if(f0 instanceof IFn.OLD) { + return ((IFn.OLD)f0).invokePrim(a, b); + } else { + return RT.doubleCast(f0.invoke(a, b)); + } + } + + public static double invokeDDD(IFn f0, double a, double b) { + if(f0 instanceof IFn.DDD) { + return ((IFn.DDD)f0).invokePrim(a, b); + } else { + return RT.doubleCast(f0.invoke(a, b)); + } + } + + public static double invokeLDD(IFn f0, long a, double b) { + if(f0 instanceof IFn.LDD) { + return ((IFn.LDD)f0).invokePrim(a, b); + } else { + return RT.doubleCast(f0.invoke(a, b)); + } + } + + public static double invokeDLD(IFn f0, double a, long b) { + if(f0 instanceof IFn.DLD) { + return ((IFn.DLD)f0).invokePrim(a, b); + } else { + return RT.doubleCast(f0.invoke(a, b)); + } + } + + public static double invokeOOD(IFn f0, Object a, Object b) { + if(f0 instanceof IFn.OOD) { + return ((IFn.OOD)f0).invokePrim(a, b); + } else { + return RT.doubleCast(f0.invoke(a, b)); + } + } + + public static double invokeODD(IFn f0, Object a, double b) { + if(f0 instanceof IFn.ODD) { + return ((IFn.ODD)f0).invokePrim(a, b); + } else { + return RT.doubleCast(f0.invoke(a, b)); + } + } + + public static double invokeDOD(IFn f0, double a, Object b) { + if(f0 instanceof IFn.DOD) { + return ((IFn.DOD)f0).invokePrim(a, b); + } else { + return RT.doubleCast(f0.invoke(a, b)); + } + } + + public static float invokeLLF(IFn f0, long a, long b) { + if(f0 instanceof IFn.LLD) { + return RT.floatCast(((IFn.LLD)f0).invokePrim(a, b)); + } else { + return RT.floatCast(f0.invoke(a, b)); + } + } + + public static float invokeLOF(IFn f0, long a, Object b) { + if(f0 instanceof IFn.LOD) { + return RT.floatCast(((IFn.LOD)f0).invokePrim(a, b)); + } else { + return RT.floatCast(f0.invoke(a, b)); + } + } + + public static float invokeOLF(IFn f0, Object a, long b) { + if(f0 instanceof IFn.OLD) { + return RT.floatCast(((IFn.OLD)f0).invokePrim(a, b)); + } else { + return RT.floatCast(f0.invoke(a, b)); + } + } + + public static float invokeDDF(IFn f0, double a, double b) { + if(f0 instanceof IFn.DDD) { + return RT.floatCast(((IFn.DDD)f0).invokePrim(a, b)); + } else { + return RT.floatCast(f0.invoke(a, b)); + } + } + + public static float invokeLDF(IFn f0, long a, double b) { + if(f0 instanceof IFn.LDD) { + return RT.floatCast(((IFn.LDD)f0).invokePrim(a, b)); + } else { + return RT.floatCast(f0.invoke(a, b)); + } + } + + public static float invokeDLF(IFn f0, double a, long b) { + if(f0 instanceof IFn.DLD) { + return RT.floatCast(((IFn.DLD)f0).invokePrim(a, b)); + } else { + return RT.floatCast(f0.invoke(a, b)); + } + } + + public static float invokeOOF(IFn f0, Object a, Object b) { + if(f0 instanceof IFn.OOD) { + return RT.floatCast(((IFn.OOD)f0).invokePrim(a, b)); + } else { + return RT.floatCast(f0.invoke(a, b)); + } + } + + public static float invokeODF(IFn f0, Object a, double b) { + if(f0 instanceof IFn.ODD) { + return RT.floatCast(((IFn.ODD)f0).invokePrim(a, b)); + } else { + return RT.floatCast(f0.invoke(a, b)); + } + } + + public static float invokeDOF(IFn f0, double a, Object b) { + if(f0 instanceof IFn.DOD) { + return RT.floatCast(((IFn.DOD)f0).invokePrim(a, b)); + } else { + return RT.floatCast(f0.invoke(a, b)); + } + } + + public static boolean invokeLLZ(IFn f0, long a, long b) { + return RT.booleanCast(f0.invoke(a, b)); + } + + public static boolean invokeLOZ(IFn f0, long a, Object b) { + return RT.booleanCast(f0.invoke(a, b)); + } + + public static boolean invokeOLZ(IFn f0, Object a, long b) { + return RT.booleanCast(f0.invoke(a, b)); + } + + public static boolean invokeDDZ(IFn f0, double a, double b) { + return RT.booleanCast(f0.invoke(a, b)); + } + + public static boolean invokeLDZ(IFn f0, long a, double b) { + return RT.booleanCast(f0.invoke(a, b)); + } + + public static boolean invokeDLZ(IFn f0, double a, long b) { + return RT.booleanCast(f0.invoke(a, b)); + } + + public static boolean invokeOOZ(IFn f0, Object a, Object b) { + return RT.booleanCast(f0.invoke(a, b)); + } + + public static boolean invokeODZ(IFn f0, Object a, double b) { + return RT.booleanCast(f0.invoke(a, b)); + } + + public static boolean invokeDOZ(IFn f0, double a, Object b) { + return RT.booleanCast(f0.invoke(a, b)); + } + + public static Object invokeLLO(IFn f0, long a, long b) { + if(f0 instanceof IFn.LLO) { + return ((IFn.LLO)f0).invokePrim(a, b); + } else { + return f0.invoke(a, b); + } + } + + public static Object invokeLOO(IFn f0, long a, Object b) { + if(f0 instanceof IFn.LOO) { + return ((IFn.LOO)f0).invokePrim(a, b); + } else { + return f0.invoke(a, b); + } + } + + public static Object invokeOLO(IFn f0, Object a, long b) { + if(f0 instanceof IFn.OLO) { + return ((IFn.OLO)f0).invokePrim(a, b); + } else { + return f0.invoke(a, b); + } + } + + public static Object invokeDDO(IFn f0, double a, double b) { + if(f0 instanceof IFn.DDO) { + return ((IFn.DDO)f0).invokePrim(a, b); + } else { + return f0.invoke(a, b); + } + } + + public static Object invokeLDO(IFn f0, long a, double b) { + if(f0 instanceof IFn.LDO) { + return ((IFn.LDO)f0).invokePrim(a, b); + } else { + return f0.invoke(a, b); + } + } + + public static Object invokeDLO(IFn f0, double a, long b) { + if(f0 instanceof IFn.DLO) { + return ((IFn.DLO)f0).invokePrim(a, b); + } else { + return f0.invoke(a, b); + } + } + + public static Object invokeOOO(IFn f0, Object a, Object b) { + return f0.invoke(a, b); + } + + public static Object invokeODO(IFn f0, Object a, double b) { + if(f0 instanceof IFn.ODO) { + return ((IFn.ODO)f0).invokePrim(a, b); + } else { + return f0.invoke(a, b); + } + } + + public static Object invokeDOO(IFn f0, double a, Object b) { + if(f0 instanceof IFn.DOO) { + return ((IFn.DOO)f0).invokePrim(a, b); + } else { + return f0.invoke(a, b); + } + } + + public static boolean invokeOOOZ(IFn f0, Object a, Object b, Object c) { + return RT.booleanCast(f0.invoke(a, b, c)); + } + + public static Object invokeOOOO(IFn f0, Object a, Object b, Object c) { + return f0.invoke(a, b, c); + } + + public static boolean invokeOOOOZ(IFn f0, Object a, Object b, Object c, Object d) { + return RT.booleanCast(f0.invoke(a, b, c, d)); + } + + public static Object invokeOOOOO(IFn f0, Object a, Object b, Object c, Object d) { + return f0.invoke(a, b, c, d); + } + + public static boolean invokeOOOOOZ(IFn f0, Object a, Object b, Object c, Object d, Object e) { + return RT.booleanCast(f0.invoke(a, b, c, d, e)); + } + + public static Object invokeOOOOOO(IFn f0, Object a, Object b, Object c, Object d, Object e) { + return f0.invoke(a, b, c, d, e); + } + + public static boolean invokeOOOOOOZ(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f) { + return RT.booleanCast(f0.invoke(a, b, c, d, e, f)); + } + + public static Object invokeOOOOOOO(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f) { + return f0.invoke(a, b, c, d, e, f); + } + + public static boolean invokeOOOOOOOZ(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g) { + return RT.booleanCast(f0.invoke(a, b, c, d, e, f, g)); + } + + public static Object invokeOOOOOOOO(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g) { + return f0.invoke(a, b, c, d, e, f, g); + } + + public static boolean invokeOOOOOOOOZ(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h) { + return RT.booleanCast(f0.invoke(a, b, c, d, e, f, g, h)); + } + + public static Object invokeOOOOOOOOO(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h) { + return f0.invoke(a, b, c, d, e, f, g, h); + } + + public static boolean invokeOOOOOOOOOZ(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h, Object i) { + return RT.booleanCast(f0.invoke(a, b, c, d, e, f, g, h, i)); + } + + public static Object invokeOOOOOOOOOO(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h, Object i) { + return f0.invoke(a, b, c, d, e, f, g, h, i); + } + + public static boolean invokeOOOOOOOOOOZ(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h, Object i, Object j) { + return RT.booleanCast(f0.invoke(a, b, c, d, e, f, g, h, i, j)); + } + + public static Object invokeOOOOOOOOOOO(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h, Object i, Object j) { + return f0.invoke(a, b, c, d, e, f, g, h, i, j); + } + +} \ No newline at end of file diff --git a/src/jvm/clojure/lang/Reflector.java b/src/jvm/clojure/lang/Reflector.java index 31b08831ad..7267074db5 100644 --- a/src/jvm/clojure/lang/Reflector.java +++ b/src/jvm/clojure/lang/Reflector.java @@ -19,6 +19,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; import java.util.*; import java.util.stream.Collectors; @@ -570,9 +571,32 @@ static public List getMethods(Class c, int arity, String name, boolean g return methods; } +// Return type coercions match coercions in FnInvokers for compiled invokers +private static Object coerceAdapterReturn(Object ret, Class targetType) { + if(targetType.isPrimitive()) { + switch (targetType.getName()) { + case "boolean": return RT.booleanCast(ret); + case "long": return RT.longCast(ret); + case "double": return RT.doubleCast(ret); + case "int": return RT.intCast(ret); + case "short": return RT.shortCast(ret); + case "byte": return RT.byteCast(ret); + case "float": return RT.floatCast(ret); + } + } + return ret; +} static Object boxArg(Class paramType, Object arg){ - if(!paramType.isPrimitive()) + if(arg instanceof IFn && Compiler.FISupport.maybeFIMethod(paramType) != null) + // Adapt IFn obj to targetType using dynamic proxy + return Proxy.newProxyInstance((ClassLoader) Compiler.LOADER.get(), + new Class[]{paramType}, + (proxy, method, methodArgs) -> { + Object ret = ((IFn) arg).applyTo(RT.seq(methodArgs)); + return coerceAdapterReturn(ret, method.getReturnType()); + }); + else if(!paramType.isPrimitive()) return paramType.cast(arg); else if(paramType == boolean.class) return Boolean.class.cast(arg); @@ -616,6 +640,8 @@ static public boolean paramArgTypeMatch(Class paramType, Class argType){ return !paramType.isPrimitive(); if(paramType == argType || paramType.isAssignableFrom(argType)) return true; + if(Compiler.FISupport.maybeFIMethod(paramType) != null && IFn.class.isAssignableFrom(argType)) + return true; if(paramType == int.class) return argType == Integer.class || argType == long.class @@ -675,4 +701,5 @@ public static Object prepRet(Class c, Object x){ // return Double.valueOf(((Float) x).doubleValue()); return x; } + } diff --git a/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj b/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj new file mode 100644 index 0000000000..e74ac2ce57 --- /dev/null +++ b/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj @@ -0,0 +1,344 @@ +(ns clojure.test-clojure.generated-all-fi-adapters-in-let + (:use clojure.test) + (:require [clojure.string :as str]) + (:import (clojure.test AdapterExerciser + AdapterExerciser$LL + AdapterExerciser$DL + AdapterExerciser$OL + AdapterExerciser$LI + AdapterExerciser$DI + AdapterExerciser$OI + AdapterExerciser$LS + AdapterExerciser$DS + AdapterExerciser$OS + AdapterExerciser$LB + AdapterExerciser$DB + AdapterExerciser$OB + AdapterExerciser$LD + AdapterExerciser$DD + AdapterExerciser$OD + AdapterExerciser$LF + AdapterExerciser$DF + AdapterExerciser$OF + AdapterExerciser$LZ + AdapterExerciser$DZ + AdapterExerciser$OZ + AdapterExerciser$LO + AdapterExerciser$DO + AdapterExerciser$OO + AdapterExerciser$LLL + AdapterExerciser$LOL + AdapterExerciser$OLL + AdapterExerciser$DDL + AdapterExerciser$LDL + AdapterExerciser$DLL + AdapterExerciser$OOL + AdapterExerciser$ODL + AdapterExerciser$DOL + AdapterExerciser$LLI + AdapterExerciser$LOI + AdapterExerciser$OLI + AdapterExerciser$DDI + AdapterExerciser$LDI + AdapterExerciser$DLI + AdapterExerciser$OOI + AdapterExerciser$ODI + AdapterExerciser$DOI + AdapterExerciser$LLS + AdapterExerciser$LOS + AdapterExerciser$OLS + AdapterExerciser$DDS + AdapterExerciser$LDS + AdapterExerciser$DLS + AdapterExerciser$OOS + AdapterExerciser$ODS + AdapterExerciser$DOS + AdapterExerciser$LLB + AdapterExerciser$LOB + AdapterExerciser$OLB + AdapterExerciser$DDB + AdapterExerciser$LDB + AdapterExerciser$DLB + AdapterExerciser$OOB + AdapterExerciser$ODB + AdapterExerciser$DOB + AdapterExerciser$LLD + AdapterExerciser$LOD + AdapterExerciser$OLD + AdapterExerciser$DDD + AdapterExerciser$LDD + AdapterExerciser$DLD + AdapterExerciser$OOD + AdapterExerciser$ODD + AdapterExerciser$DOD + AdapterExerciser$LLF + AdapterExerciser$LOF + AdapterExerciser$OLF + AdapterExerciser$DDF + AdapterExerciser$LDF + AdapterExerciser$DLF + AdapterExerciser$OOF + AdapterExerciser$ODF + AdapterExerciser$DOF + AdapterExerciser$LLZ + AdapterExerciser$LOZ + AdapterExerciser$OLZ + AdapterExerciser$DDZ + AdapterExerciser$LDZ + AdapterExerciser$DLZ + AdapterExerciser$OOZ + AdapterExerciser$ODZ + AdapterExerciser$DOZ + AdapterExerciser$LLO + AdapterExerciser$LOO + AdapterExerciser$OLO + AdapterExerciser$DDO + AdapterExerciser$LDO + AdapterExerciser$DLO + AdapterExerciser$OOO + AdapterExerciser$ODO + AdapterExerciser$DOO + AdapterExerciser$OOOZ + AdapterExerciser$OOOO + AdapterExerciser$OOOOZ + AdapterExerciser$OOOOO + AdapterExerciser$OOOOOZ + AdapterExerciser$OOOOOO + AdapterExerciser$OOOOOOZ + AdapterExerciser$OOOOOOO + AdapterExerciser$OOOOOOOZ + AdapterExerciser$OOOOOOOO + AdapterExerciser$OOOOOOOOZ + AdapterExerciser$OOOOOOOOO + AdapterExerciser$OOOOOOOOOZ + AdapterExerciser$OOOOOOOOOO + AdapterExerciser$OOOOOOOOOOZ + AdapterExerciser$OOOOOOOOOOO + ))) + +(deftest test-all-fi-adapters-in-let + (let [^AdapterExerciser exerciser (AdapterExerciser.) + ^AdapterExerciser$LL LLadapter (fn [^long a] (long 1)) + ^AdapterExerciser$DL DLadapter (fn [^double a] (long 1)) + ^AdapterExerciser$OL OLadapter (fn [^AdapterExerciser a] (long 1)) + ^AdapterExerciser$LI LIadapter (fn [^long a] 1) + ^AdapterExerciser$DI DIadapter (fn [^double a] 1) + ^AdapterExerciser$OI OIadapter (fn [^AdapterExerciser a] 1) + ^AdapterExerciser$LS LSadapter (fn [^long a] (short 1)) + ^AdapterExerciser$DS DSadapter (fn [^double a] (short 1)) + ^AdapterExerciser$OS OSadapter (fn [^AdapterExerciser a] (short 1)) + ^AdapterExerciser$LB LBadapter (fn [^long a] (byte 1)) + ^AdapterExerciser$DB DBadapter (fn [^double a] (byte 1)) + ^AdapterExerciser$OB OBadapter (fn [^AdapterExerciser a] (byte 1)) + ^AdapterExerciser$LD LDadapter (fn [^long a] (double 1)) + ^AdapterExerciser$DD DDadapter (fn [^double a] (double 1)) + ^AdapterExerciser$OD ODadapter (fn [^AdapterExerciser a] (double 1)) + ^AdapterExerciser$LF LFadapter (fn [^long a] (float 1)) + ^AdapterExerciser$DF DFadapter (fn [^double a] (float 1)) + ^AdapterExerciser$OF OFadapter (fn [^AdapterExerciser a] (float 1)) + ^AdapterExerciser$LZ LZadapter (fn [^long a] false) + ^AdapterExerciser$DZ DZadapter (fn [^double a] false) + ^AdapterExerciser$OZ OZadapter (fn [^AdapterExerciser a] false) + ^AdapterExerciser$LO LOadapter (fn [^long a] exerciser) + ^AdapterExerciser$DO DOadapter (fn [^double a] exerciser) + ^AdapterExerciser$OO OOadapter (fn [^AdapterExerciser a] exerciser) + ^AdapterExerciser$LLL LLLadapter (fn [^long a ^long b] (long 1)) + ^AdapterExerciser$LOL LOLadapter (fn [^long a ^AdapterExerciser b] (long 1)) + ^AdapterExerciser$OLL OLLadapter (fn [^AdapterExerciser a ^long b] (long 1)) + ^AdapterExerciser$DDL DDLadapter (fn [^double a ^double b] (long 1)) + ^AdapterExerciser$LDL LDLadapter (fn [^long a ^double b] (long 1)) + ^AdapterExerciser$DLL DLLadapter (fn [^double a ^long b] (long 1)) + ^AdapterExerciser$OOL OOLadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (long 1)) + ^AdapterExerciser$ODL ODLadapter (fn [^AdapterExerciser a ^double b] (long 1)) + ^AdapterExerciser$DOL DOLadapter (fn [^double a ^AdapterExerciser b] (long 1)) + ^AdapterExerciser$LLI LLIadapter (fn [^long a ^long b] 1) + ^AdapterExerciser$LOI LOIadapter (fn [^long a ^AdapterExerciser b] 1) + ^AdapterExerciser$OLI OLIadapter (fn [^AdapterExerciser a ^long b] 1) + ^AdapterExerciser$DDI DDIadapter (fn [^double a ^double b] 1) + ^AdapterExerciser$LDI LDIadapter (fn [^long a ^double b] 1) + ^AdapterExerciser$DLI DLIadapter (fn [^double a ^long b] 1) + ^AdapterExerciser$OOI OOIadapter (fn [^AdapterExerciser a ^AdapterExerciser b] 1) + ^AdapterExerciser$ODI ODIadapter (fn [^AdapterExerciser a ^double b] 1) + ^AdapterExerciser$DOI DOIadapter (fn [^double a ^AdapterExerciser b] 1) + ^AdapterExerciser$LLS LLSadapter (fn [^long a ^long b] (short 1)) + ^AdapterExerciser$LOS LOSadapter (fn [^long a ^AdapterExerciser b] (short 1)) + ^AdapterExerciser$OLS OLSadapter (fn [^AdapterExerciser a ^long b] (short 1)) + ^AdapterExerciser$DDS DDSadapter (fn [^double a ^double b] (short 1)) + ^AdapterExerciser$LDS LDSadapter (fn [^long a ^double b] (short 1)) + ^AdapterExerciser$DLS DLSadapter (fn [^double a ^long b] (short 1)) + ^AdapterExerciser$OOS OOSadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (short 1)) + ^AdapterExerciser$ODS ODSadapter (fn [^AdapterExerciser a ^double b] (short 1)) + ^AdapterExerciser$DOS DOSadapter (fn [^double a ^AdapterExerciser b] (short 1)) + ^AdapterExerciser$LLB LLBadapter (fn [^long a ^long b] (byte 1)) + ^AdapterExerciser$LOB LOBadapter (fn [^long a ^AdapterExerciser b] (byte 1)) + ^AdapterExerciser$OLB OLBadapter (fn [^AdapterExerciser a ^long b] (byte 1)) + ^AdapterExerciser$DDB DDBadapter (fn [^double a ^double b] (byte 1)) + ^AdapterExerciser$LDB LDBadapter (fn [^long a ^double b] (byte 1)) + ^AdapterExerciser$DLB DLBadapter (fn [^double a ^long b] (byte 1)) + ^AdapterExerciser$OOB OOBadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (byte 1)) + ^AdapterExerciser$ODB ODBadapter (fn [^AdapterExerciser a ^double b] (byte 1)) + ^AdapterExerciser$DOB DOBadapter (fn [^double a ^AdapterExerciser b] (byte 1)) + ^AdapterExerciser$LLD LLDadapter (fn [^long a ^long b] (double 1)) + ^AdapterExerciser$LOD LODadapter (fn [^long a ^AdapterExerciser b] (double 1)) + ^AdapterExerciser$OLD OLDadapter (fn [^AdapterExerciser a ^long b] (double 1)) + ^AdapterExerciser$DDD DDDadapter (fn [^double a ^double b] (double 1)) + ^AdapterExerciser$LDD LDDadapter (fn [^long a ^double b] (double 1)) + ^AdapterExerciser$DLD DLDadapter (fn [^double a ^long b] (double 1)) + ^AdapterExerciser$OOD OODadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (double 1)) + ^AdapterExerciser$ODD ODDadapter (fn [^AdapterExerciser a ^double b] (double 1)) + ^AdapterExerciser$DOD DODadapter (fn [^double a ^AdapterExerciser b] (double 1)) + ^AdapterExerciser$LLF LLFadapter (fn [^long a ^long b] (float 1)) + ^AdapterExerciser$LOF LOFadapter (fn [^long a ^AdapterExerciser b] (float 1)) + ^AdapterExerciser$OLF OLFadapter (fn [^AdapterExerciser a ^long b] (float 1)) + ^AdapterExerciser$DDF DDFadapter (fn [^double a ^double b] (float 1)) + ^AdapterExerciser$LDF LDFadapter (fn [^long a ^double b] (float 1)) + ^AdapterExerciser$DLF DLFadapter (fn [^double a ^long b] (float 1)) + ^AdapterExerciser$OOF OOFadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (float 1)) + ^AdapterExerciser$ODF ODFadapter (fn [^AdapterExerciser a ^double b] (float 1)) + ^AdapterExerciser$DOF DOFadapter (fn [^double a ^AdapterExerciser b] (float 1)) + ^AdapterExerciser$LLZ LLZadapter (fn [^long a ^long b] false) + ^AdapterExerciser$LOZ LOZadapter (fn [^long a ^AdapterExerciser b] false) + ^AdapterExerciser$OLZ OLZadapter (fn [^AdapterExerciser a ^long b] false) + ^AdapterExerciser$DDZ DDZadapter (fn [^double a ^double b] false) + ^AdapterExerciser$LDZ LDZadapter (fn [^long a ^double b] false) + ^AdapterExerciser$DLZ DLZadapter (fn [^double a ^long b] false) + ^AdapterExerciser$OOZ OOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b] false) + ^AdapterExerciser$ODZ ODZadapter (fn [^AdapterExerciser a ^double b] false) + ^AdapterExerciser$DOZ DOZadapter (fn [^double a ^AdapterExerciser b] false) + ^AdapterExerciser$LLO LLOadapter (fn [^long a ^long b] exerciser) + ^AdapterExerciser$LOO LOOadapter (fn [^long a ^AdapterExerciser b] exerciser) + ^AdapterExerciser$OLO OLOadapter (fn [^AdapterExerciser a ^long b] exerciser) + ^AdapterExerciser$DDO DDOadapter (fn [^double a ^double b] exerciser) + ^AdapterExerciser$LDO LDOadapter (fn [^long a ^double b] exerciser) + ^AdapterExerciser$DLO DLOadapter (fn [^double a ^long b] exerciser) + ^AdapterExerciser$OOO OOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b] exerciser) + ^AdapterExerciser$ODO ODOadapter (fn [^AdapterExerciser a ^double b] exerciser) + ^AdapterExerciser$DOO DOOadapter (fn [^double a ^AdapterExerciser b] exerciser) + ^AdapterExerciser$OOOZ OOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] false) + ^AdapterExerciser$OOOO OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser) + ^AdapterExerciser$OOOOZ OOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] false) + ^AdapterExerciser$OOOOO OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser) + ^AdapterExerciser$OOOOOZ OOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] false) + ^AdapterExerciser$OOOOOO OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser) + ^AdapterExerciser$OOOOOOZ OOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] false) + ^AdapterExerciser$OOOOOOO OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser) + ^AdapterExerciser$OOOOOOOZ OOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] false) + ^AdapterExerciser$OOOOOOOO OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser) + ^AdapterExerciser$OOOOOOOOZ OOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] false) + ^AdapterExerciser$OOOOOOOOO OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser) + ^AdapterExerciser$OOOOOOOOOZ OOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] false) + ^AdapterExerciser$OOOOOOOOOO OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser) + ^AdapterExerciser$OOOOOOOOOOZ OOOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] false) + ^AdapterExerciser$OOOOOOOOOOO OOOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] exerciser)] + (is (= (.takesLRetL LLadapter (long 1)) (long 1))) + (is (= (.takesDRetL DLadapter (double 1)) (long 1))) + (is (= (.takesORetL OLadapter exerciser) (long 1))) + (is (= (.takesLRetI LIadapter (long 1)) 1)) + (is (= (.takesDRetI DIadapter (double 1)) 1)) + (is (= (.takesORetI OIadapter exerciser) 1)) + (is (= (.takesLRetS LSadapter (long 1)) (short 1))) + (is (= (.takesDRetS DSadapter (double 1)) (short 1))) + (is (= (.takesORetS OSadapter exerciser) (short 1))) + (is (= (.takesLRetB LBadapter (long 1)) (byte 1))) + (is (= (.takesDRetB DBadapter (double 1)) (byte 1))) + (is (= (.takesORetB OBadapter exerciser) (byte 1))) + (is (= (.takesLRetD LDadapter (long 1)) (double 1))) + (is (= (.takesDRetD DDadapter (double 1)) (double 1))) + (is (= (.takesORetD ODadapter exerciser) (double 1))) + (is (= (.takesLRetF LFadapter (long 1)) (float 1))) + (is (= (.takesDRetF DFadapter (double 1)) (float 1))) + (is (= (.takesORetF OFadapter exerciser) (float 1))) + (is (= (.takesLRetZ LZadapter (long 1)) false)) + (is (= (.takesDRetZ DZadapter (double 1)) false)) + (is (= (.takesORetZ OZadapter exerciser) false)) + (is (= (.takesLRetO LOadapter (long 1)) exerciser)) + (is (= (.takesDRetO DOadapter (double 1)) exerciser)) + (is (= (.takesORetO OOadapter exerciser) exerciser)) + (is (= (.takesLLRetL LLLadapter (long 1) (long 1)) (long 1))) + (is (= (.takesLORetL LOLadapter (long 1) exerciser) (long 1))) + (is (= (.takesOLRetL OLLadapter exerciser (long 1)) (long 1))) + (is (= (.takesDDRetL DDLadapter (double 1) (double 1)) (long 1))) + (is (= (.takesLDRetL LDLadapter (long 1) (double 1)) (long 1))) + (is (= (.takesDLRetL DLLadapter (double 1) (long 1)) (long 1))) + (is (= (.takesOORetL OOLadapter exerciser exerciser) (long 1))) + (is (= (.takesODRetL ODLadapter exerciser (double 1)) (long 1))) + (is (= (.takesDORetL DOLadapter (double 1) exerciser) (long 1))) + (is (= (.takesLLRetI LLIadapter (long 1) (long 1)) 1)) + (is (= (.takesLORetI LOIadapter (long 1) exerciser) 1)) + (is (= (.takesOLRetI OLIadapter exerciser (long 1)) 1)) + (is (= (.takesDDRetI DDIadapter (double 1) (double 1)) 1)) + (is (= (.takesLDRetI LDIadapter (long 1) (double 1)) 1)) + (is (= (.takesDLRetI DLIadapter (double 1) (long 1)) 1)) + (is (= (.takesOORetI OOIadapter exerciser exerciser) 1)) + (is (= (.takesODRetI ODIadapter exerciser (double 1)) 1)) + (is (= (.takesDORetI DOIadapter (double 1) exerciser) 1)) + (is (= (.takesLLRetS LLSadapter (long 1) (long 1)) (short 1))) + (is (= (.takesLORetS LOSadapter (long 1) exerciser) (short 1))) + (is (= (.takesOLRetS OLSadapter exerciser (long 1)) (short 1))) + (is (= (.takesDDRetS DDSadapter (double 1) (double 1)) (short 1))) + (is (= (.takesLDRetS LDSadapter (long 1) (double 1)) (short 1))) + (is (= (.takesDLRetS DLSadapter (double 1) (long 1)) (short 1))) + (is (= (.takesOORetS OOSadapter exerciser exerciser) (short 1))) + (is (= (.takesODRetS ODSadapter exerciser (double 1)) (short 1))) + (is (= (.takesDORetS DOSadapter (double 1) exerciser) (short 1))) + (is (= (.takesLLRetB LLBadapter (long 1) (long 1)) (byte 1))) + (is (= (.takesLORetB LOBadapter (long 1) exerciser) (byte 1))) + (is (= (.takesOLRetB OLBadapter exerciser (long 1)) (byte 1))) + (is (= (.takesDDRetB DDBadapter (double 1) (double 1)) (byte 1))) + (is (= (.takesLDRetB LDBadapter (long 1) (double 1)) (byte 1))) + (is (= (.takesDLRetB DLBadapter (double 1) (long 1)) (byte 1))) + (is (= (.takesOORetB OOBadapter exerciser exerciser) (byte 1))) + (is (= (.takesODRetB ODBadapter exerciser (double 1)) (byte 1))) + (is (= (.takesDORetB DOBadapter (double 1) exerciser) (byte 1))) + (is (= (.takesLLRetD LLDadapter (long 1) (long 1)) (double 1))) + (is (= (.takesLORetD LODadapter (long 1) exerciser) (double 1))) + (is (= (.takesOLRetD OLDadapter exerciser (long 1)) (double 1))) + (is (= (.takesDDRetD DDDadapter (double 1) (double 1)) (double 1))) + (is (= (.takesLDRetD LDDadapter (long 1) (double 1)) (double 1))) + (is (= (.takesDLRetD DLDadapter (double 1) (long 1)) (double 1))) + (is (= (.takesOORetD OODadapter exerciser exerciser) (double 1))) + (is (= (.takesODRetD ODDadapter exerciser (double 1)) (double 1))) + (is (= (.takesDORetD DODadapter (double 1) exerciser) (double 1))) + (is (= (.takesLLRetF LLFadapter (long 1) (long 1)) (float 1))) + (is (= (.takesLORetF LOFadapter (long 1) exerciser) (float 1))) + (is (= (.takesOLRetF OLFadapter exerciser (long 1)) (float 1))) + (is (= (.takesDDRetF DDFadapter (double 1) (double 1)) (float 1))) + (is (= (.takesLDRetF LDFadapter (long 1) (double 1)) (float 1))) + (is (= (.takesDLRetF DLFadapter (double 1) (long 1)) (float 1))) + (is (= (.takesOORetF OOFadapter exerciser exerciser) (float 1))) + (is (= (.takesODRetF ODFadapter exerciser (double 1)) (float 1))) + (is (= (.takesDORetF DOFadapter (double 1) exerciser) (float 1))) + (is (= (.takesLLRetZ LLZadapter (long 1) (long 1)) false)) + (is (= (.takesLORetZ LOZadapter (long 1) exerciser) false)) + (is (= (.takesOLRetZ OLZadapter exerciser (long 1)) false)) + (is (= (.takesDDRetZ DDZadapter (double 1) (double 1)) false)) + (is (= (.takesLDRetZ LDZadapter (long 1) (double 1)) false)) + (is (= (.takesDLRetZ DLZadapter (double 1) (long 1)) false)) + (is (= (.takesOORetZ OOZadapter exerciser exerciser) false)) + (is (= (.takesODRetZ ODZadapter exerciser (double 1)) false)) + (is (= (.takesDORetZ DOZadapter (double 1) exerciser) false)) + (is (= (.takesLLRetO LLOadapter (long 1) (long 1)) exerciser)) + (is (= (.takesLORetO LOOadapter (long 1) exerciser) exerciser)) + (is (= (.takesOLRetO OLOadapter exerciser (long 1)) exerciser)) + (is (= (.takesDDRetO DDOadapter (double 1) (double 1)) exerciser)) + (is (= (.takesLDRetO LDOadapter (long 1) (double 1)) exerciser)) + (is (= (.takesDLRetO DLOadapter (double 1) (long 1)) exerciser)) + (is (= (.takesOORetO OOOadapter exerciser exerciser) exerciser)) + (is (= (.takesODRetO ODOadapter exerciser (double 1)) exerciser)) + (is (= (.takesDORetO DOOadapter (double 1) exerciser) exerciser)) + (is (= (.takesOOORetZ OOOZadapter exerciser exerciser exerciser) false)) + (is (= (.takesOOORetO OOOOadapter exerciser exerciser exerciser) exerciser)) + (is (= (.takesOOOORetZ OOOOZadapter exerciser exerciser exerciser exerciser) false)) + (is (= (.takesOOOORetO OOOOOadapter exerciser exerciser exerciser exerciser) exerciser)) + (is (= (.takesOOOOORetZ OOOOOZadapter exerciser exerciser exerciser exerciser exerciser) false)) + (is (= (.takesOOOOORetO OOOOOOadapter exerciser exerciser exerciser exerciser exerciser) exerciser)) + (is (= (.takesOOOOOORetZ OOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser) false)) + (is (= (.takesOOOOOORetO OOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) + (is (= (.takesOOOOOOORetZ OOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) + (is (= (.takesOOOOOOORetO OOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) + (is (= (.takesOOOOOOOORetZ OOOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) + (is (= (.takesOOOOOOOORetO OOOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) + (is (= (.takesOOOOOOOOORetZ OOOOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) + (is (= (.takesOOOOOOOOORetO OOOOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) + (is (= (.takesOOOOOOOOOORetZ OOOOOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) + (is (= (.takesOOOOOOOOOORetO OOOOOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)))) diff --git a/test/clojure/test_clojure/generated_functional_adapters_in_def.clj b/test/clojure/test_clojure/generated_functional_adapters_in_def.clj new file mode 100644 index 0000000000..5df76ce376 --- /dev/null +++ b/test/clojure/test_clojure/generated_functional_adapters_in_def.clj @@ -0,0 +1,231 @@ +(ns clojure.test-clojure.generated-functional-adapters-in-def + (:use clojure.test) + (:require [clojure.string :as str]) + (:import (clojure.test AdapterExerciser))) + +(deftest functional-adapters-in-def + (def exerciser (AdapterExerciser.)) + (def LLadapter (fn [^long a] (long 1))) + (is (= (.methodLL ^AdapterExerciser exerciser LLadapter) 0)) + (def DLadapter (fn [^double a] (long 1))) + (is (= (.methodDL ^AdapterExerciser exerciser DLadapter) 1)) + (def OLadapter (fn [^AdapterExerciser a] (long 1))) + (is (= (.methodOL ^AdapterExerciser exerciser OLadapter) 2)) + (def LIadapter (fn [^long a] 1)) + (is (= (.methodLI ^AdapterExerciser exerciser LIadapter) 3)) + (def DIadapter (fn [^double a] 1)) + (is (= (.methodDI ^AdapterExerciser exerciser DIadapter) 4)) + (def OIadapter (fn [^AdapterExerciser a] 1)) + (is (= (.methodOI ^AdapterExerciser exerciser OIadapter) 5)) + (def LSadapter (fn [^long a] (short 1))) + (is (= (.methodLS ^AdapterExerciser exerciser LSadapter) 6)) + (def DSadapter (fn [^double a] (short 1))) + (is (= (.methodDS ^AdapterExerciser exerciser DSadapter) 7)) + (def OSadapter (fn [^AdapterExerciser a] (short 1))) + (is (= (.methodOS ^AdapterExerciser exerciser OSadapter) 8)) + (def LBadapter (fn [^long a] (byte 1))) + (is (= (.methodLB ^AdapterExerciser exerciser LBadapter) 9)) + (def DBadapter (fn [^double a] (byte 1))) + (is (= (.methodDB ^AdapterExerciser exerciser DBadapter) 10)) + (def OBadapter (fn [^AdapterExerciser a] (byte 1))) + (is (= (.methodOB ^AdapterExerciser exerciser OBadapter) 11)) + (def LDadapter (fn [^long a] (double 1))) + (is (= (.methodLD ^AdapterExerciser exerciser LDadapter) 12)) + (def DDadapter (fn [^double a] (double 1))) + (is (= (.methodDD ^AdapterExerciser exerciser DDadapter) 13)) + (def ODadapter (fn [^AdapterExerciser a] (double 1))) + (is (= (.methodOD ^AdapterExerciser exerciser ODadapter) 14)) + (def LFadapter (fn [^long a] (float 1))) + (is (= (.methodLF ^AdapterExerciser exerciser LFadapter) 15)) + (def DFadapter (fn [^double a] (float 1))) + (is (= (.methodDF ^AdapterExerciser exerciser DFadapter) 16)) + (def OFadapter (fn [^AdapterExerciser a] (float 1))) + (is (= (.methodOF ^AdapterExerciser exerciser OFadapter) 17)) + (def LZadapter (fn [^long a] false)) + (is (= (.methodLZ ^AdapterExerciser exerciser LZadapter) 18)) + (def DZadapter (fn [^double a] false)) + (is (= (.methodDZ ^AdapterExerciser exerciser DZadapter) 19)) + (def OZadapter (fn [^AdapterExerciser a] false)) + (is (= (.methodOZ ^AdapterExerciser exerciser OZadapter) 20)) + (def LOadapter (fn [^long a] exerciser)) + (is (= (.methodLO ^AdapterExerciser exerciser LOadapter) 21)) + (def DOadapter (fn [^double a] exerciser)) + (is (= (.methodDO ^AdapterExerciser exerciser DOadapter) 22)) + (def OOadapter (fn [^AdapterExerciser a] exerciser)) + (is (= (.methodOO ^AdapterExerciser exerciser OOadapter) 23)) + (def LLLadapter (fn [^long a ^long b] (long 1))) + (is (= (.methodLLL ^AdapterExerciser exerciser LLLadapter) 24)) + (def LOLadapter (fn [^long a ^AdapterExerciser b] (long 1))) + (is (= (.methodLOL ^AdapterExerciser exerciser LOLadapter) 25)) + (def OLLadapter (fn [^AdapterExerciser a ^long b] (long 1))) + (is (= (.methodOLL ^AdapterExerciser exerciser OLLadapter) 26)) + (def DDLadapter (fn [^double a ^double b] (long 1))) + (is (= (.methodDDL ^AdapterExerciser exerciser DDLadapter) 27)) + (def LDLadapter (fn [^long a ^double b] (long 1))) + (is (= (.methodLDL ^AdapterExerciser exerciser LDLadapter) 28)) + (def DLLadapter (fn [^double a ^long b] (long 1))) + (is (= (.methodDLL ^AdapterExerciser exerciser DLLadapter) 29)) + (def OOLadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (long 1))) + (is (= (.methodOOL ^AdapterExerciser exerciser OOLadapter) 30)) + (def ODLadapter (fn [^AdapterExerciser a ^double b] (long 1))) + (is (= (.methodODL ^AdapterExerciser exerciser ODLadapter) 31)) + (def DOLadapter (fn [^double a ^AdapterExerciser b] (long 1))) + (is (= (.methodDOL ^AdapterExerciser exerciser DOLadapter) 32)) + (def LLIadapter (fn [^long a ^long b] 1)) + (is (= (.methodLLI ^AdapterExerciser exerciser LLIadapter) 33)) + (def LOIadapter (fn [^long a ^AdapterExerciser b] 1)) + (is (= (.methodLOI ^AdapterExerciser exerciser LOIadapter) 34)) + (def OLIadapter (fn [^AdapterExerciser a ^long b] 1)) + (is (= (.methodOLI ^AdapterExerciser exerciser OLIadapter) 35)) + (def DDIadapter (fn [^double a ^double b] 1)) + (is (= (.methodDDI ^AdapterExerciser exerciser DDIadapter) 36)) + (def LDIadapter (fn [^long a ^double b] 1)) + (is (= (.methodLDI ^AdapterExerciser exerciser LDIadapter) 37)) + (def DLIadapter (fn [^double a ^long b] 1)) + (is (= (.methodDLI ^AdapterExerciser exerciser DLIadapter) 38)) + (def OOIadapter (fn [^AdapterExerciser a ^AdapterExerciser b] 1)) + (is (= (.methodOOI ^AdapterExerciser exerciser OOIadapter) 39)) + (def ODIadapter (fn [^AdapterExerciser a ^double b] 1)) + (is (= (.methodODI ^AdapterExerciser exerciser ODIadapter) 40)) + (def DOIadapter (fn [^double a ^AdapterExerciser b] 1)) + (is (= (.methodDOI ^AdapterExerciser exerciser DOIadapter) 41)) + (def LLSadapter (fn [^long a ^long b] (short 1))) + (is (= (.methodLLS ^AdapterExerciser exerciser LLSadapter) 42)) + (def LOSadapter (fn [^long a ^AdapterExerciser b] (short 1))) + (is (= (.methodLOS ^AdapterExerciser exerciser LOSadapter) 43)) + (def OLSadapter (fn [^AdapterExerciser a ^long b] (short 1))) + (is (= (.methodOLS ^AdapterExerciser exerciser OLSadapter) 44)) + (def DDSadapter (fn [^double a ^double b] (short 1))) + (is (= (.methodDDS ^AdapterExerciser exerciser DDSadapter) 45)) + (def LDSadapter (fn [^long a ^double b] (short 1))) + (is (= (.methodLDS ^AdapterExerciser exerciser LDSadapter) 46)) + (def DLSadapter (fn [^double a ^long b] (short 1))) + (is (= (.methodDLS ^AdapterExerciser exerciser DLSadapter) 47)) + (def OOSadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (short 1))) + (is (= (.methodOOS ^AdapterExerciser exerciser OOSadapter) 48)) + (def ODSadapter (fn [^AdapterExerciser a ^double b] (short 1))) + (is (= (.methodODS ^AdapterExerciser exerciser ODSadapter) 49)) + (def DOSadapter (fn [^double a ^AdapterExerciser b] (short 1))) + (is (= (.methodDOS ^AdapterExerciser exerciser DOSadapter) 50)) + (def LLBadapter (fn [^long a ^long b] (byte 1))) + (is (= (.methodLLB ^AdapterExerciser exerciser LLBadapter) 51)) + (def LOBadapter (fn [^long a ^AdapterExerciser b] (byte 1))) + (is (= (.methodLOB ^AdapterExerciser exerciser LOBadapter) 52)) + (def OLBadapter (fn [^AdapterExerciser a ^long b] (byte 1))) + (is (= (.methodOLB ^AdapterExerciser exerciser OLBadapter) 53)) + (def DDBadapter (fn [^double a ^double b] (byte 1))) + (is (= (.methodDDB ^AdapterExerciser exerciser DDBadapter) 54)) + (def LDBadapter (fn [^long a ^double b] (byte 1))) + (is (= (.methodLDB ^AdapterExerciser exerciser LDBadapter) 55)) + (def DLBadapter (fn [^double a ^long b] (byte 1))) + (is (= (.methodDLB ^AdapterExerciser exerciser DLBadapter) 56)) + (def OOBadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (byte 1))) + (is (= (.methodOOB ^AdapterExerciser exerciser OOBadapter) 57)) + (def ODBadapter (fn [^AdapterExerciser a ^double b] (byte 1))) + (is (= (.methodODB ^AdapterExerciser exerciser ODBadapter) 58)) + (def DOBadapter (fn [^double a ^AdapterExerciser b] (byte 1))) + (is (= (.methodDOB ^AdapterExerciser exerciser DOBadapter) 59)) + (def LLDadapter (fn [^long a ^long b] (double 1))) + (is (= (.methodLLD ^AdapterExerciser exerciser LLDadapter) 60)) + (def LODadapter (fn [^long a ^AdapterExerciser b] (double 1))) + (is (= (.methodLOD ^AdapterExerciser exerciser LODadapter) 61)) + (def OLDadapter (fn [^AdapterExerciser a ^long b] (double 1))) + (is (= (.methodOLD ^AdapterExerciser exerciser OLDadapter) 62)) + (def DDDadapter (fn [^double a ^double b] (double 1))) + (is (= (.methodDDD ^AdapterExerciser exerciser DDDadapter) 63)) + (def LDDadapter (fn [^long a ^double b] (double 1))) + (is (= (.methodLDD ^AdapterExerciser exerciser LDDadapter) 64)) + (def DLDadapter (fn [^double a ^long b] (double 1))) + (is (= (.methodDLD ^AdapterExerciser exerciser DLDadapter) 65)) + (def OODadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (double 1))) + (is (= (.methodOOD ^AdapterExerciser exerciser OODadapter) 66)) + (def ODDadapter (fn [^AdapterExerciser a ^double b] (double 1))) + (is (= (.methodODD ^AdapterExerciser exerciser ODDadapter) 67)) + (def DODadapter (fn [^double a ^AdapterExerciser b] (double 1))) + (is (= (.methodDOD ^AdapterExerciser exerciser DODadapter) 68)) + (def LLFadapter (fn [^long a ^long b] (float 1))) + (is (= (.methodLLF ^AdapterExerciser exerciser LLFadapter) 69)) + (def LOFadapter (fn [^long a ^AdapterExerciser b] (float 1))) + (is (= (.methodLOF ^AdapterExerciser exerciser LOFadapter) 70)) + (def OLFadapter (fn [^AdapterExerciser a ^long b] (float 1))) + (is (= (.methodOLF ^AdapterExerciser exerciser OLFadapter) 71)) + (def DDFadapter (fn [^double a ^double b] (float 1))) + (is (= (.methodDDF ^AdapterExerciser exerciser DDFadapter) 72)) + (def LDFadapter (fn [^long a ^double b] (float 1))) + (is (= (.methodLDF ^AdapterExerciser exerciser LDFadapter) 73)) + (def DLFadapter (fn [^double a ^long b] (float 1))) + (is (= (.methodDLF ^AdapterExerciser exerciser DLFadapter) 74)) + (def OOFadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (float 1))) + (is (= (.methodOOF ^AdapterExerciser exerciser OOFadapter) 75)) + (def ODFadapter (fn [^AdapterExerciser a ^double b] (float 1))) + (is (= (.methodODF ^AdapterExerciser exerciser ODFadapter) 76)) + (def DOFadapter (fn [^double a ^AdapterExerciser b] (float 1))) + (is (= (.methodDOF ^AdapterExerciser exerciser DOFadapter) 77)) + (def LLZadapter (fn [^long a ^long b] false)) + (is (= (.methodLLZ ^AdapterExerciser exerciser LLZadapter) 78)) + (def LOZadapter (fn [^long a ^AdapterExerciser b] false)) + (is (= (.methodLOZ ^AdapterExerciser exerciser LOZadapter) 79)) + (def OLZadapter (fn [^AdapterExerciser a ^long b] false)) + (is (= (.methodOLZ ^AdapterExerciser exerciser OLZadapter) 80)) + (def DDZadapter (fn [^double a ^double b] false)) + (is (= (.methodDDZ ^AdapterExerciser exerciser DDZadapter) 81)) + (def LDZadapter (fn [^long a ^double b] false)) + (is (= (.methodLDZ ^AdapterExerciser exerciser LDZadapter) 82)) + (def DLZadapter (fn [^double a ^long b] false)) + (is (= (.methodDLZ ^AdapterExerciser exerciser DLZadapter) 83)) + (def OOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b] false)) + (is (= (.methodOOZ ^AdapterExerciser exerciser OOZadapter) 84)) + (def ODZadapter (fn [^AdapterExerciser a ^double b] false)) + (is (= (.methodODZ ^AdapterExerciser exerciser ODZadapter) 85)) + (def DOZadapter (fn [^double a ^AdapterExerciser b] false)) + (is (= (.methodDOZ ^AdapterExerciser exerciser DOZadapter) 86)) + (def LLOadapter (fn [^long a ^long b] exerciser)) + (is (= (.methodLLO ^AdapterExerciser exerciser LLOadapter) 87)) + (def LOOadapter (fn [^long a ^AdapterExerciser b] exerciser)) + (is (= (.methodLOO ^AdapterExerciser exerciser LOOadapter) 88)) + (def OLOadapter (fn [^AdapterExerciser a ^long b] exerciser)) + (is (= (.methodOLO ^AdapterExerciser exerciser OLOadapter) 89)) + (def DDOadapter (fn [^double a ^double b] exerciser)) + (is (= (.methodDDO ^AdapterExerciser exerciser DDOadapter) 90)) + (def LDOadapter (fn [^long a ^double b] exerciser)) + (is (= (.methodLDO ^AdapterExerciser exerciser LDOadapter) 91)) + (def DLOadapter (fn [^double a ^long b] exerciser)) + (is (= (.methodDLO ^AdapterExerciser exerciser DLOadapter) 92)) + (def OOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b] exerciser)) + (is (= (.methodOOO ^AdapterExerciser exerciser OOOadapter) 93)) + (def ODOadapter (fn [^AdapterExerciser a ^double b] exerciser)) + (is (= (.methodODO ^AdapterExerciser exerciser ODOadapter) 94)) + (def DOOadapter (fn [^double a ^AdapterExerciser b] exerciser)) + (is (= (.methodDOO ^AdapterExerciser exerciser DOOadapter) 95)) + (def OOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] false)) + (is (= (.methodOOOZ ^AdapterExerciser exerciser OOOZadapter) 96)) + (def OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser)) + (is (= (.methodOOOO ^AdapterExerciser exerciser OOOOadapter) 97)) + (def OOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] false)) + (is (= (.methodOOOOZ ^AdapterExerciser exerciser OOOOZadapter) 98)) + (def OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser)) + (is (= (.methodOOOOO ^AdapterExerciser exerciser OOOOOadapter) 99)) + (def OOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] false)) + (is (= (.methodOOOOOZ ^AdapterExerciser exerciser OOOOOZadapter) 100)) + (def OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser)) + (is (= (.methodOOOOOO ^AdapterExerciser exerciser OOOOOOadapter) 101)) + (def OOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] false)) + (is (= (.methodOOOOOOZ ^AdapterExerciser exerciser OOOOOOZadapter) 102)) + (def OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser)) + (is (= (.methodOOOOOOO ^AdapterExerciser exerciser OOOOOOOadapter) 103)) + (def OOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] false)) + (is (= (.methodOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOZadapter) 104)) + (def OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser)) + (is (= (.methodOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOadapter) 105)) + (def OOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] false)) + (is (= (.methodOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOZadapter) 106)) + (def OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser)) + (is (= (.methodOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOadapter) 107)) + (def OOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] false)) + (is (= (.methodOOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOOZadapter) 108)) + (def OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser)) + (is (= (.methodOOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOOadapter) 109)) + (def OOOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] false)) + (is (= (.methodOOOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOOOZadapter) 110)) + (def OOOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] exerciser)) + (is (= (.methodOOOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOOOadapter) 111))) diff --git a/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj b/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj new file mode 100644 index 0000000000..57919d03d6 --- /dev/null +++ b/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj @@ -0,0 +1,231 @@ +(ns clojure.test-clojure.generated-functional-adapters-in-def-requiring-reflection + (:use clojure.test) + (:require [clojure.string :as str]) + (:import (clojure.test AdapterExerciser))) + +(deftest functional-adapters-in-def + (def exerciser (AdapterExerciser.)) + (def LLadapter (fn [^long a] (long 1))) + (is (= (.methodLL exerciser LLadapter) 0)) + (def DLadapter (fn [^double a] (long 1))) + (is (= (.methodDL exerciser DLadapter) 1)) + (def OLadapter (fn [^AdapterExerciser a] (long 1))) + (is (= (.methodOL exerciser OLadapter) 2)) + (def LIadapter (fn [^long a] 1)) + (is (= (.methodLI exerciser LIadapter) 3)) + (def DIadapter (fn [^double a] 1)) + (is (= (.methodDI exerciser DIadapter) 4)) + (def OIadapter (fn [^AdapterExerciser a] 1)) + (is (= (.methodOI exerciser OIadapter) 5)) + (def LSadapter (fn [^long a] (short 1))) + (is (= (.methodLS exerciser LSadapter) 6)) + (def DSadapter (fn [^double a] (short 1))) + (is (= (.methodDS exerciser DSadapter) 7)) + (def OSadapter (fn [^AdapterExerciser a] (short 1))) + (is (= (.methodOS exerciser OSadapter) 8)) + (def LBadapter (fn [^long a] (byte 1))) + (is (= (.methodLB exerciser LBadapter) 9)) + (def DBadapter (fn [^double a] (byte 1))) + (is (= (.methodDB exerciser DBadapter) 10)) + (def OBadapter (fn [^AdapterExerciser a] (byte 1))) + (is (= (.methodOB exerciser OBadapter) 11)) + (def LDadapter (fn [^long a] (double 1))) + (is (= (.methodLD exerciser LDadapter) 12)) + (def DDadapter (fn [^double a] (double 1))) + (is (= (.methodDD exerciser DDadapter) 13)) + (def ODadapter (fn [^AdapterExerciser a] (double 1))) + (is (= (.methodOD exerciser ODadapter) 14)) + (def LFadapter (fn [^long a] (float 1))) + (is (= (.methodLF exerciser LFadapter) 15)) + (def DFadapter (fn [^double a] (float 1))) + (is (= (.methodDF exerciser DFadapter) 16)) + (def OFadapter (fn [^AdapterExerciser a] (float 1))) + (is (= (.methodOF exerciser OFadapter) 17)) + (def LZadapter (fn [^long a] false)) + (is (= (.methodLZ exerciser LZadapter) 18)) + (def DZadapter (fn [^double a] false)) + (is (= (.methodDZ exerciser DZadapter) 19)) + (def OZadapter (fn [^AdapterExerciser a] false)) + (is (= (.methodOZ exerciser OZadapter) 20)) + (def LOadapter (fn [^long a] exerciser)) + (is (= (.methodLO exerciser LOadapter) 21)) + (def DOadapter (fn [^double a] exerciser)) + (is (= (.methodDO exerciser DOadapter) 22)) + (def OOadapter (fn [^AdapterExerciser a] exerciser)) + (is (= (.methodOO exerciser OOadapter) 23)) + (def LLLadapter (fn [^long a ^long b] (long 1))) + (is (= (.methodLLL exerciser LLLadapter) 24)) + (def LOLadapter (fn [^long a ^AdapterExerciser b] (long 1))) + (is (= (.methodLOL exerciser LOLadapter) 25)) + (def OLLadapter (fn [^AdapterExerciser a ^long b] (long 1))) + (is (= (.methodOLL exerciser OLLadapter) 26)) + (def DDLadapter (fn [^double a ^double b] (long 1))) + (is (= (.methodDDL exerciser DDLadapter) 27)) + (def LDLadapter (fn [^long a ^double b] (long 1))) + (is (= (.methodLDL exerciser LDLadapter) 28)) + (def DLLadapter (fn [^double a ^long b] (long 1))) + (is (= (.methodDLL exerciser DLLadapter) 29)) + (def OOLadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (long 1))) + (is (= (.methodOOL exerciser OOLadapter) 30)) + (def ODLadapter (fn [^AdapterExerciser a ^double b] (long 1))) + (is (= (.methodODL exerciser ODLadapter) 31)) + (def DOLadapter (fn [^double a ^AdapterExerciser b] (long 1))) + (is (= (.methodDOL exerciser DOLadapter) 32)) + (def LLIadapter (fn [^long a ^long b] 1)) + (is (= (.methodLLI exerciser LLIadapter) 33)) + (def LOIadapter (fn [^long a ^AdapterExerciser b] 1)) + (is (= (.methodLOI exerciser LOIadapter) 34)) + (def OLIadapter (fn [^AdapterExerciser a ^long b] 1)) + (is (= (.methodOLI exerciser OLIadapter) 35)) + (def DDIadapter (fn [^double a ^double b] 1)) + (is (= (.methodDDI exerciser DDIadapter) 36)) + (def LDIadapter (fn [^long a ^double b] 1)) + (is (= (.methodLDI exerciser LDIadapter) 37)) + (def DLIadapter (fn [^double a ^long b] 1)) + (is (= (.methodDLI exerciser DLIadapter) 38)) + (def OOIadapter (fn [^AdapterExerciser a ^AdapterExerciser b] 1)) + (is (= (.methodOOI exerciser OOIadapter) 39)) + (def ODIadapter (fn [^AdapterExerciser a ^double b] 1)) + (is (= (.methodODI exerciser ODIadapter) 40)) + (def DOIadapter (fn [^double a ^AdapterExerciser b] 1)) + (is (= (.methodDOI exerciser DOIadapter) 41)) + (def LLSadapter (fn [^long a ^long b] (short 1))) + (is (= (.methodLLS exerciser LLSadapter) 42)) + (def LOSadapter (fn [^long a ^AdapterExerciser b] (short 1))) + (is (= (.methodLOS exerciser LOSadapter) 43)) + (def OLSadapter (fn [^AdapterExerciser a ^long b] (short 1))) + (is (= (.methodOLS exerciser OLSadapter) 44)) + (def DDSadapter (fn [^double a ^double b] (short 1))) + (is (= (.methodDDS exerciser DDSadapter) 45)) + (def LDSadapter (fn [^long a ^double b] (short 1))) + (is (= (.methodLDS exerciser LDSadapter) 46)) + (def DLSadapter (fn [^double a ^long b] (short 1))) + (is (= (.methodDLS exerciser DLSadapter) 47)) + (def OOSadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (short 1))) + (is (= (.methodOOS exerciser OOSadapter) 48)) + (def ODSadapter (fn [^AdapterExerciser a ^double b] (short 1))) + (is (= (.methodODS exerciser ODSadapter) 49)) + (def DOSadapter (fn [^double a ^AdapterExerciser b] (short 1))) + (is (= (.methodDOS exerciser DOSadapter) 50)) + (def LLBadapter (fn [^long a ^long b] (byte 1))) + (is (= (.methodLLB exerciser LLBadapter) 51)) + (def LOBadapter (fn [^long a ^AdapterExerciser b] (byte 1))) + (is (= (.methodLOB exerciser LOBadapter) 52)) + (def OLBadapter (fn [^AdapterExerciser a ^long b] (byte 1))) + (is (= (.methodOLB exerciser OLBadapter) 53)) + (def DDBadapter (fn [^double a ^double b] (byte 1))) + (is (= (.methodDDB exerciser DDBadapter) 54)) + (def LDBadapter (fn [^long a ^double b] (byte 1))) + (is (= (.methodLDB exerciser LDBadapter) 55)) + (def DLBadapter (fn [^double a ^long b] (byte 1))) + (is (= (.methodDLB exerciser DLBadapter) 56)) + (def OOBadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (byte 1))) + (is (= (.methodOOB exerciser OOBadapter) 57)) + (def ODBadapter (fn [^AdapterExerciser a ^double b] (byte 1))) + (is (= (.methodODB exerciser ODBadapter) 58)) + (def DOBadapter (fn [^double a ^AdapterExerciser b] (byte 1))) + (is (= (.methodDOB exerciser DOBadapter) 59)) + (def LLDadapter (fn [^long a ^long b] (double 1))) + (is (= (.methodLLD exerciser LLDadapter) 60)) + (def LODadapter (fn [^long a ^AdapterExerciser b] (double 1))) + (is (= (.methodLOD exerciser LODadapter) 61)) + (def OLDadapter (fn [^AdapterExerciser a ^long b] (double 1))) + (is (= (.methodOLD exerciser OLDadapter) 62)) + (def DDDadapter (fn [^double a ^double b] (double 1))) + (is (= (.methodDDD exerciser DDDadapter) 63)) + (def LDDadapter (fn [^long a ^double b] (double 1))) + (is (= (.methodLDD exerciser LDDadapter) 64)) + (def DLDadapter (fn [^double a ^long b] (double 1))) + (is (= (.methodDLD exerciser DLDadapter) 65)) + (def OODadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (double 1))) + (is (= (.methodOOD exerciser OODadapter) 66)) + (def ODDadapter (fn [^AdapterExerciser a ^double b] (double 1))) + (is (= (.methodODD exerciser ODDadapter) 67)) + (def DODadapter (fn [^double a ^AdapterExerciser b] (double 1))) + (is (= (.methodDOD exerciser DODadapter) 68)) + (def LLFadapter (fn [^long a ^long b] (float 1))) + (is (= (.methodLLF exerciser LLFadapter) 69)) + (def LOFadapter (fn [^long a ^AdapterExerciser b] (float 1))) + (is (= (.methodLOF exerciser LOFadapter) 70)) + (def OLFadapter (fn [^AdapterExerciser a ^long b] (float 1))) + (is (= (.methodOLF exerciser OLFadapter) 71)) + (def DDFadapter (fn [^double a ^double b] (float 1))) + (is (= (.methodDDF exerciser DDFadapter) 72)) + (def LDFadapter (fn [^long a ^double b] (float 1))) + (is (= (.methodLDF exerciser LDFadapter) 73)) + (def DLFadapter (fn [^double a ^long b] (float 1))) + (is (= (.methodDLF exerciser DLFadapter) 74)) + (def OOFadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (float 1))) + (is (= (.methodOOF exerciser OOFadapter) 75)) + (def ODFadapter (fn [^AdapterExerciser a ^double b] (float 1))) + (is (= (.methodODF exerciser ODFadapter) 76)) + (def DOFadapter (fn [^double a ^AdapterExerciser b] (float 1))) + (is (= (.methodDOF exerciser DOFadapter) 77)) + (def LLZadapter (fn [^long a ^long b] false)) + (is (= (.methodLLZ exerciser LLZadapter) 78)) + (def LOZadapter (fn [^long a ^AdapterExerciser b] false)) + (is (= (.methodLOZ exerciser LOZadapter) 79)) + (def OLZadapter (fn [^AdapterExerciser a ^long b] false)) + (is (= (.methodOLZ exerciser OLZadapter) 80)) + (def DDZadapter (fn [^double a ^double b] false)) + (is (= (.methodDDZ exerciser DDZadapter) 81)) + (def LDZadapter (fn [^long a ^double b] false)) + (is (= (.methodLDZ exerciser LDZadapter) 82)) + (def DLZadapter (fn [^double a ^long b] false)) + (is (= (.methodDLZ exerciser DLZadapter) 83)) + (def OOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b] false)) + (is (= (.methodOOZ exerciser OOZadapter) 84)) + (def ODZadapter (fn [^AdapterExerciser a ^double b] false)) + (is (= (.methodODZ exerciser ODZadapter) 85)) + (def DOZadapter (fn [^double a ^AdapterExerciser b] false)) + (is (= (.methodDOZ exerciser DOZadapter) 86)) + (def LLOadapter (fn [^long a ^long b] exerciser)) + (is (= (.methodLLO exerciser LLOadapter) 87)) + (def LOOadapter (fn [^long a ^AdapterExerciser b] exerciser)) + (is (= (.methodLOO exerciser LOOadapter) 88)) + (def OLOadapter (fn [^AdapterExerciser a ^long b] exerciser)) + (is (= (.methodOLO exerciser OLOadapter) 89)) + (def DDOadapter (fn [^double a ^double b] exerciser)) + (is (= (.methodDDO exerciser DDOadapter) 90)) + (def LDOadapter (fn [^long a ^double b] exerciser)) + (is (= (.methodLDO exerciser LDOadapter) 91)) + (def DLOadapter (fn [^double a ^long b] exerciser)) + (is (= (.methodDLO exerciser DLOadapter) 92)) + (def OOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b] exerciser)) + (is (= (.methodOOO exerciser OOOadapter) 93)) + (def ODOadapter (fn [^AdapterExerciser a ^double b] exerciser)) + (is (= (.methodODO exerciser ODOadapter) 94)) + (def DOOadapter (fn [^double a ^AdapterExerciser b] exerciser)) + (is (= (.methodDOO exerciser DOOadapter) 95)) + (def OOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] false)) + (is (= (.methodOOOZ exerciser OOOZadapter) 96)) + (def OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser)) + (is (= (.methodOOOO exerciser OOOOadapter) 97)) + (def OOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] false)) + (is (= (.methodOOOOZ exerciser OOOOZadapter) 98)) + (def OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser)) + (is (= (.methodOOOOO exerciser OOOOOadapter) 99)) + (def OOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] false)) + (is (= (.methodOOOOOZ exerciser OOOOOZadapter) 100)) + (def OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser)) + (is (= (.methodOOOOOO exerciser OOOOOOadapter) 101)) + (def OOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] false)) + (is (= (.methodOOOOOOZ exerciser OOOOOOZadapter) 102)) + (def OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser)) + (is (= (.methodOOOOOOO exerciser OOOOOOOadapter) 103)) + (def OOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] false)) + (is (= (.methodOOOOOOOZ exerciser OOOOOOOZadapter) 104)) + (def OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser)) + (is (= (.methodOOOOOOOO exerciser OOOOOOOOadapter) 105)) + (def OOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] false)) + (is (= (.methodOOOOOOOOZ exerciser OOOOOOOOZadapter) 106)) + (def OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser)) + (is (= (.methodOOOOOOOOO exerciser OOOOOOOOOadapter) 107)) + (def OOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] false)) + (is (= (.methodOOOOOOOOOZ exerciser OOOOOOOOOZadapter) 108)) + (def OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser)) + (is (= (.methodOOOOOOOOOO exerciser OOOOOOOOOOadapter) 109)) + (def OOOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] false)) + (is (= (.methodOOOOOOOOOOZ exerciser OOOOOOOOOOZadapter) 110)) + (def OOOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] exerciser)) + (is (= (.methodOOOOOOOOOOO exerciser OOOOOOOOOOOadapter) 111))) diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj index da7075d138..b27bc440a0 100644 --- a/test/clojure/test_clojure/java_interop.clj +++ b/test/clojure/test_clojure/java_interop.clj @@ -15,9 +15,14 @@ [clojure.inspector] [clojure.pprint :as pp] [clojure.set :as set] - [clojure.test-clojure.proxy.examples :as proxy-examples]) + [clojure.string :as str] + [clojure.test-clojure.proxy.examples :as proxy-examples] + [clojure.test-helper :refer [should-not-reflect]]) (:import java.util.Base64 - (java.util.concurrent.atomic AtomicLong AtomicInteger))) + (java.io File FileFilter FilenameFilter) + (java.util UUID) + (java.util.concurrent.atomic AtomicLong AtomicInteger) + (clojure.test FIConstructor FIStatic FunctionalTester))) ; http://clojure.org/java_interop ; http://clojure.org/compilation @@ -639,3 +644,215 @@ (deftest test-boxing-prevention-when-compiling-statements (is (= 1 (.get (doto (AtomicInteger. 0) inc-atomic-int)))) (is (= 1 (.get (doto (AtomicLong. 0) inc-atomic-long))))) + +(deftest array-type-symbols + (is (= long/1 (class (make-array Long/TYPE 0)))) + (is (= int/1 (class (make-array Integer/TYPE 0)))) + (is (= double/1 (class (make-array Double/TYPE 0)))) + (is (= short/1 (class (make-array Short/TYPE 0)))) + (is (= boolean/1 (class (make-array Boolean/TYPE 0)))) + (is (= byte/1 (class (make-array Byte/TYPE 0)))) + (is (= float/1 (class (make-array Float/TYPE 0)))) + (is (= String/1 (class (make-array String 0)))) + (is (= java.lang.String/1 (class (make-array String 0)))) + (is (= java.util.UUID/1 (class (make-array java.util.UUID 0)))) + (is (= `byte/1 'byte/1)) + (is (= `byte/3 'byte/3)) + (is (= `java.util.UUID/1 'java.util.UUID/1)) + (is (= `String/1 'java.lang.String/1)) + (is (= `java.lang.String/1 'java.lang.String/1)) + (is (= ['long/2] `[~'long/2]))) + + +(defn make-test-files [] + (let [id (str (UUID/randomUUID)) + temp-1 (java.io.File/createTempFile (str "test-1-" id)".edn") + temp-2 (java.io.File/createTempFile "test-2"".xml") + temp-3 (java.io.File/createTempFile (str "test-3-" id)".edn") + dir (File. (.getParent temp-3))] + {:dir dir :file-id id})) + +(defn return-long ^long [] + (let [^java.util.function.ToLongFunction f (fn ^long [x] 1)] + (Long/highestOneBit (.applyAsLong f :x)))) + +(deftest clojure-fn-as-java-fn + ;; pass Clojure fn as Java Predicate + (let [coll (java.util.ArrayList. [1 2 3 4 5])] + (is (true? (.removeIf coll even?))) + (is (= coll [1 3 5]))) + + ;; pass Clojure set as Java predicate - function return + ;; should use Clojure semantics to return logical true + (let [coll (java.util.ArrayList. [1 2 3 4 5])] + (is (true? (.removeIf coll #{1 2}))) + (is (= coll [3 4 5]))) + + ;; binding type hint triggers coercion + (is (instance? FileFilter + (let [^FileFilter ff (fn [f] true)] ff))) + + ;; coercion in let - reflection has types that should work + (let [{:keys [dir file-id]} (make-test-files) + ^FileFilter ff (fn [^File f] + (str/includes? (.getName f) file-id)) + filtered (.listFiles dir ff)] + (is (= 2 (count filtered)))) + + ;; coercion in let + (let [{:keys [dir file-id]} (make-test-files) + ^FileFilter ff (fn [^File f] + (str/includes? (.getName f) file-id)) + filtered (.listFiles ^File dir ff)] + (is (= 2 (count filtered)))) + + ;;; resolve method ambiguity using member symbol and param-tags + (let [{:keys [dir file-id]} (make-test-files) + ^FileFilter ff (fn [^File f] + (str/includes? (.getName f) file-id)) + filtered (^[FileFilter] File/.listFiles dir ff)] + (is (= 2 (count filtered)))) + + (defn files-with-ext [^File dir ext] + (vec (.list dir ^FilenameFilter #(str/ends-with? % ext)))) + + (let [{:keys [dir file-id]} (make-test-files) + ^FilenameFilter ff (fn [dir file-name] + (str/includes? file-name file-id)) + filtered (.list ^File dir ff)] + (is (= 2 (count filtered)))) + + (let [^java.util.function.DoubleToLongFunction f (fn [d] (int d))] + (is (instance? java.util.function.DoubleToLongFunction f)) + (is (= 10 (.applyAsLong f (double 10.6))))) + + (let [^java.util.function.IntConsumer f (fn [i] nil)] + (is (nil? (.accept f 42)))) + + (let [^java.util.function.IntPredicate f (fn [i] true)] + (is (true? (.test f 42)))) + + (let [arr (java.util.ArrayList. [1 2 3 4 5]) + ^java.util.function.ObjDoubleConsumer f (fn [arr i] nil)] + (is (nil? (.accept f arr 42)))) + + (let [f (constantly 100) + ^Runnable g f] + (is (identical? f g) "has been unintentionally adapted")) + + (let [^java.util.function.Predicate pred even? + coll1 (java.util.ArrayList. [1 2 3 4 5]) + coll2 (java.util.ArrayList. [6 7 8 9 10])] + (is (instance? java.util.function.Predicate pred)) + (is (true? (.removeIf coll1 pred))) + (is (= coll1 [1 3 5])) + (is (true? (.removeIf coll2 pred))) + (is (= coll2 [7 9]))) + + (let [^java.util.function.Predicate pred even? + coll1 (java.util.ArrayList. [1 2 3 4 5]) + cup-fn (java.util.ArrayList. [1 2 3 4 5])] + (is (instance? java.util.function.Predicate pred)) + (is (true? (.removeIf coll1 pred))) + (is (= coll1 [1 3 5])) + (is (true? (.removeIf cup-fn pred))) + (is (= cup-fn [1 3 5]))) + + (should-not-reflect #(clojure.test-clojure.java-interop/return-long)) + + ;; FI in class constructor + (let [^java.util.function.Predicate hinted-pred (fn [i] (> i 0)) + clj-pred (fn [i] (> i 0)) + fi-constructor-1 (FIConstructor. hinted-pred) + fi-constructor-2 (FIConstructor. clj-pred) + fi-constructor-3 (FIConstructor. (fn [i] (> i 0)))] + (is (= [1 2] (.numbers fi-constructor-1))) + (is (= [1 2] (.numbers fi-constructor-2))) + (is (= [1 2] (.numbers fi-constructor-3)))) + + ;; FI as arg to static + (let [^java.util.function.Predicate hinted-pred (fn [i] (> i 0)) + res (FIStatic/numbers hinted-pred)] + (is (= [1 2] res)))) + +(deftest eval-in-place-supplier-instance + (def stream (java.util.stream.Stream/generate ^java.util.function.Supplier (atom 42))) + (is (instance? java.util.stream.Stream stream))) + +(deftest eval-in-place-as-java-fn + (def filtered-list (.removeIf (java.util.ArrayList. [1 2 3 4 5]) even?)) + (is (true? filtered-list)) + + (def fi-constructor-numbers (.numbers (FIConstructor. (fn [i] (> i 0))))) + (is (= [1 2] fi-constructor-numbers)) + + (def fi-static (FIStatic/numbers (fn [i] (< i 0)))) + (is (= [-2 -1] fi-static))) + +;; newDirectoryStream is overloaded, takes ^[Path String] or ^[Path DirectoryStream$Filter] +;; so this method will reflect +(defn get-dir-stream [^java.nio.file.Path dir-path glob-pattern] + (let [path (.toPath (java.io.File. dir-path))] + (java.nio.file.Files/newDirectoryStream path glob-pattern))) + +(deftest test-reflection-to-overloaded-method-taking-FI + ;; all of these should resolve at runtime in reflection + (is (not (nil? (get-dir-stream "." "*")))) + (is (not (nil? (get-dir-stream "." (reify java.nio.file.DirectoryStream$Filter (accept [_ path] (.isDirectory (.toFile path)))))))) + ;; this one gets FI converted from IFn to DirectoryStream$Filter + (is (not (nil? (get-dir-stream "." (fn [^java.nio.file.Path path] (.isDirectory (.toFile path)))))))) + +;; we only support FI invoke coercion up to 10 args, this has 11 +(definterface ^{java.lang.FunctionalInterface true} FIWontWork + (invoke [a b c d e f g h i j k])) + +(definterface ReceivesFI + (call [^clojure.test_clojure.java_interop.FIWontWork fi])) + +(deftest test-reify-to-FI-allowed + ;; throws because there is no 11-arity invoker method and thus it is not possible to coerce + (is (thrown? ClassCastException + (eval '(let [^clojure.test_clojure.java_interop.FIWontWork f + (fn [p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11] p11)] + (.invoke f 1 2 3 4 5 6 7 8 9 10 11))))) + + (let [r (reify clojure.test_clojure.java_interop.ReceivesFI + (call [_ fi] (.invoke fi 0 0 0 0 0 0 0 0 0 0 1)))] + + ;; doesn't throw at compilation time, but throws at runtime + ;; because IFn cannot be implicitly converted + (is (thrown? ClassCastException + (.call r (fn [a b c d e f g h i j k] k)))) + + ;; works because the reify implements the FI, no conversion necessary + (is (= 1 (.call r (reify clojure.test_clojure.java_interop.FIWontWork (invoke [_ a b c d e f g h i j k] k))))))) + +(definterface ^{java.lang.FunctionalInterface true} FIPrims + (invoke [^long a ^long b ^long c ^long d])) + +(definterface ReceivesFIPrims + (call [^clojure.test_clojure.java_interop.FIPrims fi])) + +(deftest test-match-prim-args-only-to-2 + (let [r (reify clojure.test_clojure.java_interop.ReceivesFIPrims + (call [_ fi] (.invoke fi 1 2 3 4)))] + (is (= 4 (.call r (fn [^long a ^long b ^long c ^long d] d)))))) + +(deftest test-null-reify + (is (= "null" ((fn [x] (FIStatic/allowsNullFI x)) nil)))) + +(deftest test-FI-subtype + (is (= [1 2 3 4 5] (->> (java.util.stream.Stream/iterate 1 inc) stream-seq! (take 5))))) + +(deftest class-methods-with-fi-args + (testing "Constructor accepting FI arg, provided overloaded static class FI" + (let [fi (FunctionalTester. "Constructor" 0 FunctionalTester/getChar)] + (is (= \C (.testVar fi))))) + + (testing "Instance method accepting FI arg, provided overloaded static class FI" + (let [fi (FunctionalTester. "asf" 0 FunctionalTester/getChar)] + (.instanceMethodWithFIArg fi "Instance" 0 FunctionalTester/getChar) + (is (= \I (.testVar fi))))) + + (testing "Static method accepting FI arg, provided overloaded static class FI" + (is (= \S (FunctionalTester/staticMethodWithFIArg "Static" 0 FunctionalTester/getChar))))) diff --git a/test/java/clojure/test/AdapterExerciser.java b/test/java/clojure/test/AdapterExerciser.java new file mode 100644 index 0000000000..5edfd660ad --- /dev/null +++ b/test/java/clojure/test/AdapterExerciser.java @@ -0,0 +1,563 @@ +package clojure.test; + +public class AdapterExerciser { + @FunctionalInterface + public interface LL { + public long takesLRetL(long a); + } + @FunctionalInterface + public interface DL { + public long takesDRetL(double a); + } + @FunctionalInterface + public interface OL { + public long takesORetL(AdapterExerciser a); + } + @FunctionalInterface + public interface LI { + public int takesLRetI(long a); + } + @FunctionalInterface + public interface DI { + public int takesDRetI(double a); + } + @FunctionalInterface + public interface OI { + public int takesORetI(AdapterExerciser a); + } + @FunctionalInterface + public interface LS { + public short takesLRetS(long a); + } + @FunctionalInterface + public interface DS { + public short takesDRetS(double a); + } + @FunctionalInterface + public interface OS { + public short takesORetS(AdapterExerciser a); + } + @FunctionalInterface + public interface LB { + public byte takesLRetB(long a); + } + @FunctionalInterface + public interface DB { + public byte takesDRetB(double a); + } + @FunctionalInterface + public interface OB { + public byte takesORetB(AdapterExerciser a); + } + @FunctionalInterface + public interface LD { + public double takesLRetD(long a); + } + @FunctionalInterface + public interface DD { + public double takesDRetD(double a); + } + @FunctionalInterface + public interface OD { + public double takesORetD(AdapterExerciser a); + } + @FunctionalInterface + public interface LF { + public float takesLRetF(long a); + } + @FunctionalInterface + public interface DF { + public float takesDRetF(double a); + } + @FunctionalInterface + public interface OF { + public float takesORetF(AdapterExerciser a); + } + @FunctionalInterface + public interface LZ { + public boolean takesLRetZ(long a); + } + @FunctionalInterface + public interface DZ { + public boolean takesDRetZ(double a); + } + @FunctionalInterface + public interface OZ { + public boolean takesORetZ(AdapterExerciser a); + } + @FunctionalInterface + public interface LO { + public AdapterExerciser takesLRetO(long a); + } + @FunctionalInterface + public interface DO { + public AdapterExerciser takesDRetO(double a); + } + @FunctionalInterface + public interface OO { + public AdapterExerciser takesORetO(AdapterExerciser a); + } + @FunctionalInterface + public interface LLL { + public long takesLLRetL(long a, long b); + } + @FunctionalInterface + public interface LOL { + public long takesLORetL(long a, AdapterExerciser b); + } + @FunctionalInterface + public interface OLL { + public long takesOLRetL(AdapterExerciser a, long b); + } + @FunctionalInterface + public interface DDL { + public long takesDDRetL(double a, double b); + } + @FunctionalInterface + public interface LDL { + public long takesLDRetL(long a, double b); + } + @FunctionalInterface + public interface DLL { + public long takesDLRetL(double a, long b); + } + @FunctionalInterface + public interface OOL { + public long takesOORetL(AdapterExerciser a, AdapterExerciser b); + } + @FunctionalInterface + public interface ODL { + public long takesODRetL(AdapterExerciser a, double b); + } + @FunctionalInterface + public interface DOL { + public long takesDORetL(double a, AdapterExerciser b); + } + @FunctionalInterface + public interface LLI { + public int takesLLRetI(long a, long b); + } + @FunctionalInterface + public interface LOI { + public int takesLORetI(long a, AdapterExerciser b); + } + @FunctionalInterface + public interface OLI { + public int takesOLRetI(AdapterExerciser a, long b); + } + @FunctionalInterface + public interface DDI { + public int takesDDRetI(double a, double b); + } + @FunctionalInterface + public interface LDI { + public int takesLDRetI(long a, double b); + } + @FunctionalInterface + public interface DLI { + public int takesDLRetI(double a, long b); + } + @FunctionalInterface + public interface OOI { + public int takesOORetI(AdapterExerciser a, AdapterExerciser b); + } + @FunctionalInterface + public interface ODI { + public int takesODRetI(AdapterExerciser a, double b); + } + @FunctionalInterface + public interface DOI { + public int takesDORetI(double a, AdapterExerciser b); + } + @FunctionalInterface + public interface LLS { + public short takesLLRetS(long a, long b); + } + @FunctionalInterface + public interface LOS { + public short takesLORetS(long a, AdapterExerciser b); + } + @FunctionalInterface + public interface OLS { + public short takesOLRetS(AdapterExerciser a, long b); + } + @FunctionalInterface + public interface DDS { + public short takesDDRetS(double a, double b); + } + @FunctionalInterface + public interface LDS { + public short takesLDRetS(long a, double b); + } + @FunctionalInterface + public interface DLS { + public short takesDLRetS(double a, long b); + } + @FunctionalInterface + public interface OOS { + public short takesOORetS(AdapterExerciser a, AdapterExerciser b); + } + @FunctionalInterface + public interface ODS { + public short takesODRetS(AdapterExerciser a, double b); + } + @FunctionalInterface + public interface DOS { + public short takesDORetS(double a, AdapterExerciser b); + } + @FunctionalInterface + public interface LLB { + public byte takesLLRetB(long a, long b); + } + @FunctionalInterface + public interface LOB { + public byte takesLORetB(long a, AdapterExerciser b); + } + @FunctionalInterface + public interface OLB { + public byte takesOLRetB(AdapterExerciser a, long b); + } + @FunctionalInterface + public interface DDB { + public byte takesDDRetB(double a, double b); + } + @FunctionalInterface + public interface LDB { + public byte takesLDRetB(long a, double b); + } + @FunctionalInterface + public interface DLB { + public byte takesDLRetB(double a, long b); + } + @FunctionalInterface + public interface OOB { + public byte takesOORetB(AdapterExerciser a, AdapterExerciser b); + } + @FunctionalInterface + public interface ODB { + public byte takesODRetB(AdapterExerciser a, double b); + } + @FunctionalInterface + public interface DOB { + public byte takesDORetB(double a, AdapterExerciser b); + } + @FunctionalInterface + public interface LLD { + public double takesLLRetD(long a, long b); + } + @FunctionalInterface + public interface LOD { + public double takesLORetD(long a, AdapterExerciser b); + } + @FunctionalInterface + public interface OLD { + public double takesOLRetD(AdapterExerciser a, long b); + } + @FunctionalInterface + public interface DDD { + public double takesDDRetD(double a, double b); + } + @FunctionalInterface + public interface LDD { + public double takesLDRetD(long a, double b); + } + @FunctionalInterface + public interface DLD { + public double takesDLRetD(double a, long b); + } + @FunctionalInterface + public interface OOD { + public double takesOORetD(AdapterExerciser a, AdapterExerciser b); + } + @FunctionalInterface + public interface ODD { + public double takesODRetD(AdapterExerciser a, double b); + } + @FunctionalInterface + public interface DOD { + public double takesDORetD(double a, AdapterExerciser b); + } + @FunctionalInterface + public interface LLF { + public float takesLLRetF(long a, long b); + } + @FunctionalInterface + public interface LOF { + public float takesLORetF(long a, AdapterExerciser b); + } + @FunctionalInterface + public interface OLF { + public float takesOLRetF(AdapterExerciser a, long b); + } + @FunctionalInterface + public interface DDF { + public float takesDDRetF(double a, double b); + } + @FunctionalInterface + public interface LDF { + public float takesLDRetF(long a, double b); + } + @FunctionalInterface + public interface DLF { + public float takesDLRetF(double a, long b); + } + @FunctionalInterface + public interface OOF { + public float takesOORetF(AdapterExerciser a, AdapterExerciser b); + } + @FunctionalInterface + public interface ODF { + public float takesODRetF(AdapterExerciser a, double b); + } + @FunctionalInterface + public interface DOF { + public float takesDORetF(double a, AdapterExerciser b); + } + @FunctionalInterface + public interface LLZ { + public boolean takesLLRetZ(long a, long b); + } + @FunctionalInterface + public interface LOZ { + public boolean takesLORetZ(long a, AdapterExerciser b); + } + @FunctionalInterface + public interface OLZ { + public boolean takesOLRetZ(AdapterExerciser a, long b); + } + @FunctionalInterface + public interface DDZ { + public boolean takesDDRetZ(double a, double b); + } + @FunctionalInterface + public interface LDZ { + public boolean takesLDRetZ(long a, double b); + } + @FunctionalInterface + public interface DLZ { + public boolean takesDLRetZ(double a, long b); + } + @FunctionalInterface + public interface OOZ { + public boolean takesOORetZ(AdapterExerciser a, AdapterExerciser b); + } + @FunctionalInterface + public interface ODZ { + public boolean takesODRetZ(AdapterExerciser a, double b); + } + @FunctionalInterface + public interface DOZ { + public boolean takesDORetZ(double a, AdapterExerciser b); + } + @FunctionalInterface + public interface LLO { + public AdapterExerciser takesLLRetO(long a, long b); + } + @FunctionalInterface + public interface LOO { + public AdapterExerciser takesLORetO(long a, AdapterExerciser b); + } + @FunctionalInterface + public interface OLO { + public AdapterExerciser takesOLRetO(AdapterExerciser a, long b); + } + @FunctionalInterface + public interface DDO { + public AdapterExerciser takesDDRetO(double a, double b); + } + @FunctionalInterface + public interface LDO { + public AdapterExerciser takesLDRetO(long a, double b); + } + @FunctionalInterface + public interface DLO { + public AdapterExerciser takesDLRetO(double a, long b); + } + @FunctionalInterface + public interface OOO { + public AdapterExerciser takesOORetO(AdapterExerciser a, AdapterExerciser b); + } + @FunctionalInterface + public interface ODO { + public AdapterExerciser takesODRetO(AdapterExerciser a, double b); + } + @FunctionalInterface + public interface DOO { + public AdapterExerciser takesDORetO(double a, AdapterExerciser b); + } + @FunctionalInterface + public interface OOOZ { + public boolean takesOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c); + } + @FunctionalInterface + public interface OOOO { + public AdapterExerciser takesOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c); + } + @FunctionalInterface + public interface OOOOZ { + public boolean takesOOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d); + } + @FunctionalInterface + public interface OOOOO { + public AdapterExerciser takesOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d); + } + @FunctionalInterface + public interface OOOOOZ { + public boolean takesOOOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e); + } + @FunctionalInterface + public interface OOOOOO { + public AdapterExerciser takesOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e); + } + @FunctionalInterface + public interface OOOOOOZ { + public boolean takesOOOOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f); + } + @FunctionalInterface + public interface OOOOOOO { + public AdapterExerciser takesOOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f); + } + @FunctionalInterface + public interface OOOOOOOZ { + public boolean takesOOOOOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g); + } + @FunctionalInterface + public interface OOOOOOOO { + public AdapterExerciser takesOOOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g); + } + @FunctionalInterface + public interface OOOOOOOOZ { + public boolean takesOOOOOOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g, AdapterExerciser h); + } + @FunctionalInterface + public interface OOOOOOOOO { + public AdapterExerciser takesOOOOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g, AdapterExerciser h); + } + @FunctionalInterface + public interface OOOOOOOOOZ { + public boolean takesOOOOOOOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g, AdapterExerciser h, AdapterExerciser i); + } + @FunctionalInterface + public interface OOOOOOOOOO { + public AdapterExerciser takesOOOOOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g, AdapterExerciser h, AdapterExerciser i); + } + @FunctionalInterface + public interface OOOOOOOOOOZ { + public boolean takesOOOOOOOOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g, AdapterExerciser h, AdapterExerciser i, AdapterExerciser j); + } + @FunctionalInterface + public interface OOOOOOOOOOO { + public AdapterExerciser takesOOOOOOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g, AdapterExerciser h, AdapterExerciser i, AdapterExerciser j); + } + public int methodLL(LL a) { return 0; } + public int methodDL(DL a) { return 1; } + public int methodOL(OL a) { return 2; } + public int methodLI(LI a) { return 3; } + public int methodDI(DI a) { return 4; } + public int methodOI(OI a) { return 5; } + public int methodLS(LS a) { return 6; } + public int methodDS(DS a) { return 7; } + public int methodOS(OS a) { return 8; } + public int methodLB(LB a) { return 9; } + public int methodDB(DB a) { return 10; } + public int methodOB(OB a) { return 11; } + public int methodLD(LD a) { return 12; } + public int methodDD(DD a) { return 13; } + public int methodOD(OD a) { return 14; } + public int methodLF(LF a) { return 15; } + public int methodDF(DF a) { return 16; } + public int methodOF(OF a) { return 17; } + public int methodLZ(LZ a) { return 18; } + public int methodDZ(DZ a) { return 19; } + public int methodOZ(OZ a) { return 20; } + public int methodLO(LO a) { return 21; } + public int methodDO(DO a) { return 22; } + public int methodOO(OO a) { return 23; } + public int methodLLL(LLL a) { return 24; } + public int methodLOL(LOL a) { return 25; } + public int methodOLL(OLL a) { return 26; } + public int methodDDL(DDL a) { return 27; } + public int methodLDL(LDL a) { return 28; } + public int methodDLL(DLL a) { return 29; } + public int methodOOL(OOL a) { return 30; } + public int methodODL(ODL a) { return 31; } + public int methodDOL(DOL a) { return 32; } + public int methodLLI(LLI a) { return 33; } + public int methodLOI(LOI a) { return 34; } + public int methodOLI(OLI a) { return 35; } + public int methodDDI(DDI a) { return 36; } + public int methodLDI(LDI a) { return 37; } + public int methodDLI(DLI a) { return 38; } + public int methodOOI(OOI a) { return 39; } + public int methodODI(ODI a) { return 40; } + public int methodDOI(DOI a) { return 41; } + public int methodLLS(LLS a) { return 42; } + public int methodLOS(LOS a) { return 43; } + public int methodOLS(OLS a) { return 44; } + public int methodDDS(DDS a) { return 45; } + public int methodLDS(LDS a) { return 46; } + public int methodDLS(DLS a) { return 47; } + public int methodOOS(OOS a) { return 48; } + public int methodODS(ODS a) { return 49; } + public int methodDOS(DOS a) { return 50; } + public int methodLLB(LLB a) { return 51; } + public int methodLOB(LOB a) { return 52; } + public int methodOLB(OLB a) { return 53; } + public int methodDDB(DDB a) { return 54; } + public int methodLDB(LDB a) { return 55; } + public int methodDLB(DLB a) { return 56; } + public int methodOOB(OOB a) { return 57; } + public int methodODB(ODB a) { return 58; } + public int methodDOB(DOB a) { return 59; } + public int methodLLD(LLD a) { return 60; } + public int methodLOD(LOD a) { return 61; } + public int methodOLD(OLD a) { return 62; } + public int methodDDD(DDD a) { return 63; } + public int methodLDD(LDD a) { return 64; } + public int methodDLD(DLD a) { return 65; } + public int methodOOD(OOD a) { return 66; } + public int methodODD(ODD a) { return 67; } + public int methodDOD(DOD a) { return 68; } + public int methodLLF(LLF a) { return 69; } + public int methodLOF(LOF a) { return 70; } + public int methodOLF(OLF a) { return 71; } + public int methodDDF(DDF a) { return 72; } + public int methodLDF(LDF a) { return 73; } + public int methodDLF(DLF a) { return 74; } + public int methodOOF(OOF a) { return 75; } + public int methodODF(ODF a) { return 76; } + public int methodDOF(DOF a) { return 77; } + public int methodLLZ(LLZ a) { return 78; } + public int methodLOZ(LOZ a) { return 79; } + public int methodOLZ(OLZ a) { return 80; } + public int methodDDZ(DDZ a) { return 81; } + public int methodLDZ(LDZ a) { return 82; } + public int methodDLZ(DLZ a) { return 83; } + public int methodOOZ(OOZ a) { return 84; } + public int methodODZ(ODZ a) { return 85; } + public int methodDOZ(DOZ a) { return 86; } + public int methodLLO(LLO a) { return 87; } + public int methodLOO(LOO a) { return 88; } + public int methodOLO(OLO a) { return 89; } + public int methodDDO(DDO a) { return 90; } + public int methodLDO(LDO a) { return 91; } + public int methodDLO(DLO a) { return 92; } + public int methodOOO(OOO a) { return 93; } + public int methodODO(ODO a) { return 94; } + public int methodDOO(DOO a) { return 95; } + public int methodOOOZ(OOOZ a) { return 96; } + public int methodOOOO(OOOO a) { return 97; } + public int methodOOOOZ(OOOOZ a) { return 98; } + public int methodOOOOO(OOOOO a) { return 99; } + public int methodOOOOOZ(OOOOOZ a) { return 100; } + public int methodOOOOOO(OOOOOO a) { return 101; } + public int methodOOOOOOZ(OOOOOOZ a) { return 102; } + public int methodOOOOOOO(OOOOOOO a) { return 103; } + public int methodOOOOOOOZ(OOOOOOOZ a) { return 104; } + public int methodOOOOOOOO(OOOOOOOO a) { return 105; } + public int methodOOOOOOOOZ(OOOOOOOOZ a) { return 106; } + public int methodOOOOOOOOO(OOOOOOOOO a) { return 107; } + public int methodOOOOOOOOOZ(OOOOOOOOOZ a) { return 108; } + public int methodOOOOOOOOOO(OOOOOOOOOO a) { return 109; } + public int methodOOOOOOOOOOZ(OOOOOOOOOOZ a) { return 110; } + public int methodOOOOOOOOOOO(OOOOOOOOOOO a) { return 111; }} diff --git a/test/java/clojure/test/FIConstructor.java b/test/java/clojure/test/FIConstructor.java new file mode 100644 index 0000000000..42a4e6caa3 --- /dev/null +++ b/test/java/clojure/test/FIConstructor.java @@ -0,0 +1,17 @@ +package clojure.test; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +public class FIConstructor { + + public List numbers; + + public FIConstructor(Predicate pred) { + List numbers = Arrays.asList(-2, -1, 0, 1, 2); + Object[] filteredNumbers = numbers.stream().filter(pred).toArray(); + this.numbers = Arrays.asList(filteredNumbers); + } + +} diff --git a/test/java/clojure/test/FIStatic.java b/test/java/clojure/test/FIStatic.java new file mode 100644 index 0000000000..8273c357ee --- /dev/null +++ b/test/java/clojure/test/FIStatic.java @@ -0,0 +1,26 @@ +package clojure.test; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; + +public class FIStatic { + + public static List numbers(Predicate pred) { + List numbers = Arrays.asList(-2, -1, 0, 1, 2); + Object[] filteredNumbers = numbers.stream().filter(pred).toArray(); + return Arrays.asList(filteredNumbers); + } + + public static String allowsNullFI(Predicate pred) { + if(pred == null) { + return "null"; + } else { + if(pred.test("abc")) { + return "pass"; + } else { + return "fail"; + } + } + } +} diff --git a/test/java/clojure/test/FunctionalTester.java b/test/java/clojure/test/FunctionalTester.java new file mode 100644 index 0000000000..7b5383cc30 --- /dev/null +++ b/test/java/clojure/test/FunctionalTester.java @@ -0,0 +1,31 @@ +package clojure.test; + +public class FunctionalTester { + public char testVar; + + @FunctionalInterface + public interface FI { + char action(String str, int pos); + } + + public FunctionalTester(String str, int pos, FI fi) { + testVar = fi.action(str, pos); + } + + public void instanceMethodWithFIArg(String str, int pos, FI fi) { + testVar = fi.action(str, pos); + } + + public static char staticMethodWithFIArg(String str, int pos, FI fi) { + return fi.action(str, pos); + } + + public static char getChar(String str, int pos) { + return str.charAt(pos); + } + + public static char getChar(int value, long n) { + return "Fail".charAt(0); + } + +} \ No newline at end of file From 3e8cfcb194e23fe826e599101d3010d36bbc363c Mon Sep 17 00:00:00 2001 From: clojure-build Date: Thu, 23 May 2024 13:19:25 +0000 Subject: [PATCH 217/285] [maven-release-plugin] prepare release clojure-1.12.0-alpha12 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index df07f56549..1b3b67eca2 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0-alpha12 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0-alpha12 From 4d409434bbda460500804556ee0698744626936a Mon Sep 17 00:00:00 2001 From: clojure-build Date: Thu, 23 May 2024 13:19:25 +0000 Subject: [PATCH 218/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1b3b67eca2..df07f56549 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-alpha12 + 1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0-alpha12 + HEAD From 3eab1a5a5b4cfed86c1d0c9c21bd1892e1fb44fd Mon Sep 17 00:00:00 2001 From: Ray McDermott Date: Tue, 21 May 2024 10:19:51 -0400 Subject: [PATCH 219/285] Fix for #CLJ-2645 --- src/clj/clojure/core/server.clj | 4 ++-- src/clj/clojure/core_print.clj | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/clj/clojure/core/server.clj b/src/clj/clojure/core/server.clj index 05a5a20999..8f7013fdf0 100644 --- a/src/clj/clojure/core/server.clj +++ b/src/clj/clojure/core/server.clj @@ -223,8 +223,8 @@ (m/with-bindings (in-ns 'user) (binding [*in* (or stdin in-reader) - *out* (PrintWriter-on #(out-fn {:tag :out :val %1}) nil) - *err* (PrintWriter-on #(out-fn {:tag :err :val %1}) nil)] + *out* (PrintWriter-on #(out-fn {:tag :out :val %1}) nil true) + *err* (PrintWriter-on #(out-fn {:tag :err :val %1}) nil true)] (try (add-tap tapfn) (loop [] diff --git a/src/clj/clojure/core_print.clj b/src/clj/clojure/core_print.clj index 45b72d2971..7e59c9c809 100644 --- a/src/clj/clojure/core_print.clj +++ b/src/clj/clojure/core_print.clj @@ -561,10 +561,13 @@ (defn ^java.io.PrintWriter PrintWriter-on "implements java.io.PrintWriter given flush-fn, which will be called when .flush() is called, with a string built up since the last call to .flush(). - if not nil, close-fn will be called with no arguments when .close is called" + if not nil, close-fn will be called with no arguments when .close is called. + autoflush? determines if the PrintWriter will autoflush, false by default." {:added "1.10"} - [flush-fn close-fn] - (let [sb (StringBuilder.)] + ([flush-fn close-fn] + (PrintWriter-on flush-fn close-fn false)) + ([flush-fn close-fn autoflush?] + (let [sb (StringBuilder.)] (-> (proxy [Writer] [] (flush [] (when (pos? (.length sb)) @@ -580,4 +583,4 @@ (.append sb ^String str-cbuf ^int off ^int len) (.append sb ^chars str-cbuf ^int off ^int len))))) java.io.BufferedWriter. - java.io.PrintWriter.))) + (java.io.PrintWriter. ^boolean autoflush?))))) From 8ae9e4f95e2fbbd4ee4ee3c627088c45ab44fa68 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 28 May 2024 14:24:05 -0500 Subject: [PATCH 220/285] CLJ-1385 transient docstring should include usage model from docs --- src/clj/clojure/core.clj | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 584899d396..be8e61c949 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -3358,7 +3358,15 @@ ;;;;;;;;;;;;;;;;;;;;; editable collections ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defn transient - "Returns a new, transient version of the collection, in constant time." + "Returns a new, transient version of the collection, in constant time. + + Transients support a parallel set of 'changing' operations, with similar names + followed by ! - assoc!, conj! etc. These do the same things as their persistent + counterparts except the return values are themselves transient. + + Note in particular that transients are not designed to be bashed in-place. You + must capture and use the return value in the next call. In this way, they support + the same code structure as the functional persistent code they replace." {:added "1.1" :static true} [^clojure.lang.IEditableCollection coll] From c07c39cac49a91f6031fe05c2eb7a257aa089176 Mon Sep 17 00:00:00 2001 From: Fogus Date: Thu, 23 May 2024 15:21:42 -0400 Subject: [PATCH 221/285] CLJ-2853: Conveying the qualifying class as unresolved instance method error message context. --- src/jvm/clojure/lang/Reflector.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/jvm/clojure/lang/Reflector.java b/src/jvm/clojure/lang/Reflector.java index 7267074db5..f252bf2eb7 100644 --- a/src/jvm/clojure/lang/Reflector.java +++ b/src/jvm/clojure/lang/Reflector.java @@ -103,7 +103,7 @@ public static Object invokeInstanceMethodOfClass(Object target, Class c, String .map(method -> toAccessibleSuperMethod(method, target)) .filter(Objects::nonNull) .collect(Collectors.toList()); - return invokeMatchingMethod(methodName, methods, target, args); + return invokeMatchingMethod(methodName, methods, c, target, args); } public static Object invokeInstanceMethodOfClass(Object target, String className, String methodName, Object[] args) { @@ -122,9 +122,9 @@ private static RuntimeException throwCauseOrElseException(Exception e) { throw Util.sneakyThrow(e); } -private static String noMethodReport(String methodName, Object target, Object[] args){ +private static String noMethodReport(String methodName, Class contextClass, Object[] args){ return "No matching method " + methodName + " found taking " + args.length + " args" - + (target==null?"":" for " + target.getClass()); + + (contextClass != null ? " for " + contextClass : ""); } private static Method matchMethod(List methods, Object[] args) { @@ -155,12 +155,16 @@ private static Object[] widenBoxedArgs(Object[] args) { return widenedArgs; } -static Object invokeMatchingMethod(String methodName, List methods, Object target, Object[] args) +static Object invokeMatchingMethod(String methodName, List methods, Object target, Object[] args){ + return invokeMatchingMethod(methodName, methods, target != null ? target.getClass() : null, target, args); +} + +static Object invokeMatchingMethod(String methodName, List methods, Class contextClass, Object target, Object[] args) { Method m = null; if(methods.isEmpty()) { - throw new IllegalArgumentException(noMethodReport(methodName,target,args)); + throw new IllegalArgumentException(noMethodReport(methodName,contextClass,args)); } else if(methods.size() == 1) { @@ -176,13 +180,13 @@ else if(methods.size() == 1) } } if(m == null) - throw new IllegalArgumentException(noMethodReport(methodName,target,args)); + throw new IllegalArgumentException(noMethodReport(methodName,contextClass,args)); if(!Modifier.isPublic(m.getDeclaringClass().getModifiers()) || !canAccess(m, target)) { //public method of non-public class, try to find it in hierarchy Method oldm = m; - m = getAsMethodOfAccessibleBase(target.getClass(), m, target); + m = getAsMethodOfAccessibleBase(contextClass, m, target); if(m == null) throw new IllegalArgumentException("Can't call public method of non-public class: " + oldm.toString()); From 434fbefe05634b301ccb0034390ef64a4abb9e39 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 28 May 2024 15:42:48 -0500 Subject: [PATCH 222/285] CLJ-2770 invoke-tool should not take an external process name parameter --- src/clj/clojure/tools/deps/interop.clj | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/clj/clojure/tools/deps/interop.clj b/src/clj/clojure/tools/deps/interop.clj index 0fd5869948..148ca80240 100644 --- a/src/clj/clojure/tools/deps/interop.clj +++ b/src/clj/clojure/tools/deps/interop.clj @@ -21,17 +21,16 @@ :args - map of args to pass to function Options: - :command - CLI command, default=\"clojure\" :preserve-envelope - if true, return the full invocation envelope, default=false" {:added "1.12"} - [{:keys [tool-name tool-alias fn args command preserve-envelope] - :or {command "clojure", preserve-envelope false} + [{:keys [tool-name tool-alias fn args preserve-envelope] + :or {preserve-envelope false} :as opts}] (when-not (or tool-name tool-alias) (throw (ex-info "Either :tool-alias or :tool-name must be provided" (or opts {})))) (when-not (symbol? fn) (throw (ex-info (str "fn should be a symbol " fn) (or opts {})))) (let [args (conj [fn] (assoc args :clojure.exec/invoke :fn)) _ (when (:debug opts) (println "args" args)) - command-strs [command (str "-T" (or tool-alias tool-name)) "-"] + command-strs ["clojure" (str "-T" (or tool-alias tool-name)) "-"] _ (when (:debug opts) (apply println "Invoking: " command-strs)) {:keys [in out]} (apply proc/start command-strs)] (binding [*print-length* nil From 68dbd077c9f96bdbda28df96507945a83516271d Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 28 May 2024 14:03:58 -0500 Subject: [PATCH 223/285] CLJ-2859 Add adapting of 0-arg FIs (e.g. Supplier) --- codegen/gen_fn_adapter_tests.clj | 5 +- codegen/gen_fn_invokers.clj | 3 +- src/jvm/clojure/lang/Compiler.java | 5 +- src/jvm/clojure/lang/FnInvokers.java | 56 ++ .../generated_all_fi_adapters_in_let.clj | 704 +++++++++--------- .../generated_functional_adapters_in_def.clj | 469 ++++++------ ...l_adapters_in_def_requiring_reflection.clj | 469 ++++++------ test/java/clojure/test/AdapterExerciser.java | 265 ++++--- 8 files changed, 1066 insertions(+), 910 deletions(-) diff --git a/codegen/gen_fn_adapter_tests.clj b/codegen/gen_fn_adapter_tests.clj index c8039cedbd..5bff1746e1 100644 --- a/codegen/gen_fn_adapter_tests.clj +++ b/codegen/gen_fn_adapter_tests.clj @@ -17,7 +17,7 @@ (ns clojure.test-clojure.generated-all-fi-adapters-in-let (:use clojure.test) (:require [clojure.string :as str]) - (:import (clojure.test %s))) + (:import (clojure.test AdapterExerciser %s))) (deftest test-all-fi-adapters-in-let (let [^AdapterExerciser exerciser (AdapterExerciser.)" imported-methods)) @@ -45,6 +45,7 @@ public class AdapterExerciser {") (defn gen-sigs [] (let [small-rets ["L" "I" "S" "B" "D" "F" "Z" "O"] + zero-arity (sigs [""] small-rets) single-arity (sigs ["L" "D" "O"] small-rets) two-arity (sigs ["LL" "LO" "OL" "DD" "LD" "DL" "OO" "OD" "DO"] small-rets) big-rets ["Z" "O"] @@ -56,7 +57,7 @@ public class AdapterExerciser {") eight-arity (sigs ["OOOOOOOO"] big-rets) nine-arity (sigs ["OOOOOOOOO"] big-rets) ten-arity (sigs ["OOOOOOOOOO"] big-rets)] - (mapcat seq [single-arity two-arity three-arity four-arity five-arity six-arity seven-arity eight-arity nine-arity ten-arity]))) + (mapcat seq [zero-arity single-arity two-arity three-arity four-arity five-arity six-arity seven-arity eight-arity nine-arity ten-arity]))) (def alphabet (map char (range 97 122))) (def type-hints {:D "^double " diff --git a/codegen/gen_fn_invokers.clj b/codegen/gen_fn_invokers.clj index 2bb9baf6e6..f69c3ae58e 100644 --- a/codegen/gen_fn_invokers.clj +++ b/codegen/gen_fn_invokers.clj @@ -153,6 +153,7 @@ public class FnInvokers { (defn gen-sigs [] (let [small-rets ["L" "I" "S" "B" "D" "F" "Z" "O"] + zero-arity (sigs [""] small-rets) single-arity (sigs ["L" "D" "O"] small-rets) two-arity (sigs ["LL" "LO" "OL" "DD" "LD" "DL" "OO" "OD" "DO"] small-rets) big-rets ["Z" "O"] @@ -164,7 +165,7 @@ public class FnInvokers { eight-arity (sigs ["OOOOOOOO"] big-rets) nine-arity (sigs ["OOOOOOOOO"] big-rets) ten-arity (sigs ["OOOOOOOOOO"] big-rets)] - (mapcat seq [single-arity two-arity three-arity four-arity five-arity six-arity seven-arity eight-arity nine-arity ten-arity]))) + (mapcat seq [zero-arity single-arity two-arity three-arity four-arity five-arity six-arity seven-arity eight-arity nine-arity ten-arity]))) (defn gen-invokers [] (let [sb (StringBuilder. ^String header) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 64b4171a55..e65a589894 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1619,15 +1619,14 @@ static class FISupport { // Return FI method if: // 1) Target is a functional interface and not already implemented by AFn - // 2) Target method matches one of our fn invoker methods (0 < arity <= 10) + // 2) Target method matches one of our fn invoker methods (0 <= arity <= 10) static java.lang.reflect.Method maybeFIMethod(Class target) { if (target != null && target.isAnnotationPresent(FunctionalInterface.class) && !AFN_FIS.contains(target)) { java.lang.reflect.Method[] methods = target.getMethods(); for (java.lang.reflect.Method method : methods) { - // We do not support arity=0 (e.g. Supplier) b/c not functional - use IDeref instead - if (method.getParameterCount() > 0 && method.getParameterCount() <= 10 + if (method.getParameterCount() >= 0 && method.getParameterCount() <= 10 && Modifier.isAbstract(method.getModifiers()) && !OBJECT_METHODS.contains(method.getName())) return method; diff --git a/src/jvm/clojure/lang/FnInvokers.java b/src/jvm/clojure/lang/FnInvokers.java index a95afaa2f0..be79a90273 100644 --- a/src/jvm/clojure/lang/FnInvokers.java +++ b/src/jvm/clojure/lang/FnInvokers.java @@ -33,6 +33,62 @@ static char encodeInvokerType(Class c) { } } + public static long invokeL(IFn f0) { + if(f0 instanceof IFn.L) { + return ((IFn.L)f0).invokePrim(); + } else { + return RT.longCast(f0.invoke()); + } + } + + public static int invokeI(IFn f0) { + if(f0 instanceof IFn.L) { + return RT.intCast(((IFn.L)f0).invokePrim()); + } else { + return RT.intCast(f0.invoke()); + } + } + + public static short invokeS(IFn f0) { + if(f0 instanceof IFn.L) { + return RT.shortCast(((IFn.L)f0).invokePrim()); + } else { + return RT.shortCast(f0.invoke()); + } + } + + public static byte invokeB(IFn f0) { + if(f0 instanceof IFn.L) { + return RT.byteCast(((IFn.L)f0).invokePrim()); + } else { + return RT.byteCast(f0.invoke()); + } + } + + public static double invokeD(IFn f0) { + if(f0 instanceof IFn.D) { + return ((IFn.D)f0).invokePrim(); + } else { + return RT.doubleCast(f0.invoke()); + } + } + + public static float invokeF(IFn f0) { + if(f0 instanceof IFn.D) { + return RT.floatCast(((IFn.D)f0).invokePrim()); + } else { + return RT.floatCast(f0.invoke()); + } + } + + public static boolean invokeZ(IFn f0) { + return RT.booleanCast(f0.invoke()); + } + + public static Object invokeO(IFn f0) { + return f0.invoke(); + } + public static long invokeLL(IFn f0, long a) { if(f0 instanceof IFn.LL) { return ((IFn.LL)f0).invokePrim(a); diff --git a/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj b/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj index e74ac2ce57..d276dcc328 100644 --- a/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj +++ b/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj @@ -1,344 +1,368 @@ + (ns clojure.test-clojure.generated-all-fi-adapters-in-let (:use clojure.test) (:require [clojure.string :as str]) - (:import (clojure.test AdapterExerciser - AdapterExerciser$LL - AdapterExerciser$DL - AdapterExerciser$OL - AdapterExerciser$LI - AdapterExerciser$DI - AdapterExerciser$OI - AdapterExerciser$LS - AdapterExerciser$DS - AdapterExerciser$OS - AdapterExerciser$LB - AdapterExerciser$DB - AdapterExerciser$OB - AdapterExerciser$LD - AdapterExerciser$DD - AdapterExerciser$OD - AdapterExerciser$LF - AdapterExerciser$DF - AdapterExerciser$OF - AdapterExerciser$LZ - AdapterExerciser$DZ - AdapterExerciser$OZ - AdapterExerciser$LO - AdapterExerciser$DO - AdapterExerciser$OO - AdapterExerciser$LLL - AdapterExerciser$LOL - AdapterExerciser$OLL - AdapterExerciser$DDL - AdapterExerciser$LDL - AdapterExerciser$DLL - AdapterExerciser$OOL - AdapterExerciser$ODL - AdapterExerciser$DOL - AdapterExerciser$LLI - AdapterExerciser$LOI - AdapterExerciser$OLI - AdapterExerciser$DDI - AdapterExerciser$LDI - AdapterExerciser$DLI - AdapterExerciser$OOI - AdapterExerciser$ODI - AdapterExerciser$DOI - AdapterExerciser$LLS - AdapterExerciser$LOS - AdapterExerciser$OLS - AdapterExerciser$DDS - AdapterExerciser$LDS - AdapterExerciser$DLS - AdapterExerciser$OOS - AdapterExerciser$ODS - AdapterExerciser$DOS - AdapterExerciser$LLB - AdapterExerciser$LOB - AdapterExerciser$OLB - AdapterExerciser$DDB - AdapterExerciser$LDB - AdapterExerciser$DLB - AdapterExerciser$OOB - AdapterExerciser$ODB - AdapterExerciser$DOB - AdapterExerciser$LLD - AdapterExerciser$LOD - AdapterExerciser$OLD - AdapterExerciser$DDD - AdapterExerciser$LDD - AdapterExerciser$DLD - AdapterExerciser$OOD - AdapterExerciser$ODD - AdapterExerciser$DOD - AdapterExerciser$LLF - AdapterExerciser$LOF - AdapterExerciser$OLF - AdapterExerciser$DDF - AdapterExerciser$LDF - AdapterExerciser$DLF - AdapterExerciser$OOF - AdapterExerciser$ODF - AdapterExerciser$DOF - AdapterExerciser$LLZ - AdapterExerciser$LOZ - AdapterExerciser$OLZ - AdapterExerciser$DDZ - AdapterExerciser$LDZ - AdapterExerciser$DLZ - AdapterExerciser$OOZ - AdapterExerciser$ODZ - AdapterExerciser$DOZ - AdapterExerciser$LLO - AdapterExerciser$LOO - AdapterExerciser$OLO - AdapterExerciser$DDO - AdapterExerciser$LDO - AdapterExerciser$DLO - AdapterExerciser$OOO - AdapterExerciser$ODO - AdapterExerciser$DOO - AdapterExerciser$OOOZ - AdapterExerciser$OOOO - AdapterExerciser$OOOOZ - AdapterExerciser$OOOOO - AdapterExerciser$OOOOOZ - AdapterExerciser$OOOOOO - AdapterExerciser$OOOOOOZ - AdapterExerciser$OOOOOOO - AdapterExerciser$OOOOOOOZ - AdapterExerciser$OOOOOOOO - AdapterExerciser$OOOOOOOOZ - AdapterExerciser$OOOOOOOOO - AdapterExerciser$OOOOOOOOOZ - AdapterExerciser$OOOOOOOOOO - AdapterExerciser$OOOOOOOOOOZ - AdapterExerciser$OOOOOOOOOOO - ))) + (:import (clojure.test AdapterExerciser AdapterExerciser$L +AdapterExerciser$I +AdapterExerciser$S +AdapterExerciser$B +AdapterExerciser$D +AdapterExerciser$F +AdapterExerciser$Z +AdapterExerciser$O +AdapterExerciser$LL +AdapterExerciser$DL +AdapterExerciser$OL +AdapterExerciser$LI +AdapterExerciser$DI +AdapterExerciser$OI +AdapterExerciser$LS +AdapterExerciser$DS +AdapterExerciser$OS +AdapterExerciser$LB +AdapterExerciser$DB +AdapterExerciser$OB +AdapterExerciser$LD +AdapterExerciser$DD +AdapterExerciser$OD +AdapterExerciser$LF +AdapterExerciser$DF +AdapterExerciser$OF +AdapterExerciser$LZ +AdapterExerciser$DZ +AdapterExerciser$OZ +AdapterExerciser$LO +AdapterExerciser$DO +AdapterExerciser$OO +AdapterExerciser$LLL +AdapterExerciser$LOL +AdapterExerciser$OLL +AdapterExerciser$DDL +AdapterExerciser$LDL +AdapterExerciser$DLL +AdapterExerciser$OOL +AdapterExerciser$ODL +AdapterExerciser$DOL +AdapterExerciser$LLI +AdapterExerciser$LOI +AdapterExerciser$OLI +AdapterExerciser$DDI +AdapterExerciser$LDI +AdapterExerciser$DLI +AdapterExerciser$OOI +AdapterExerciser$ODI +AdapterExerciser$DOI +AdapterExerciser$LLS +AdapterExerciser$LOS +AdapterExerciser$OLS +AdapterExerciser$DDS +AdapterExerciser$LDS +AdapterExerciser$DLS +AdapterExerciser$OOS +AdapterExerciser$ODS +AdapterExerciser$DOS +AdapterExerciser$LLB +AdapterExerciser$LOB +AdapterExerciser$OLB +AdapterExerciser$DDB +AdapterExerciser$LDB +AdapterExerciser$DLB +AdapterExerciser$OOB +AdapterExerciser$ODB +AdapterExerciser$DOB +AdapterExerciser$LLD +AdapterExerciser$LOD +AdapterExerciser$OLD +AdapterExerciser$DDD +AdapterExerciser$LDD +AdapterExerciser$DLD +AdapterExerciser$OOD +AdapterExerciser$ODD +AdapterExerciser$DOD +AdapterExerciser$LLF +AdapterExerciser$LOF +AdapterExerciser$OLF +AdapterExerciser$DDF +AdapterExerciser$LDF +AdapterExerciser$DLF +AdapterExerciser$OOF +AdapterExerciser$ODF +AdapterExerciser$DOF +AdapterExerciser$LLZ +AdapterExerciser$LOZ +AdapterExerciser$OLZ +AdapterExerciser$DDZ +AdapterExerciser$LDZ +AdapterExerciser$DLZ +AdapterExerciser$OOZ +AdapterExerciser$ODZ +AdapterExerciser$DOZ +AdapterExerciser$LLO +AdapterExerciser$LOO +AdapterExerciser$OLO +AdapterExerciser$DDO +AdapterExerciser$LDO +AdapterExerciser$DLO +AdapterExerciser$OOO +AdapterExerciser$ODO +AdapterExerciser$DOO +AdapterExerciser$OOOZ +AdapterExerciser$OOOO +AdapterExerciser$OOOOZ +AdapterExerciser$OOOOO +AdapterExerciser$OOOOOZ +AdapterExerciser$OOOOOO +AdapterExerciser$OOOOOOZ +AdapterExerciser$OOOOOOO +AdapterExerciser$OOOOOOOZ +AdapterExerciser$OOOOOOOO +AdapterExerciser$OOOOOOOOZ +AdapterExerciser$OOOOOOOOO +AdapterExerciser$OOOOOOOOOZ +AdapterExerciser$OOOOOOOOOO +AdapterExerciser$OOOOOOOOOOZ +AdapterExerciser$OOOOOOOOOOO +))) -(deftest test-all-fi-adapters-in-let - (let [^AdapterExerciser exerciser (AdapterExerciser.) - ^AdapterExerciser$LL LLadapter (fn [^long a] (long 1)) - ^AdapterExerciser$DL DLadapter (fn [^double a] (long 1)) - ^AdapterExerciser$OL OLadapter (fn [^AdapterExerciser a] (long 1)) - ^AdapterExerciser$LI LIadapter (fn [^long a] 1) - ^AdapterExerciser$DI DIadapter (fn [^double a] 1) - ^AdapterExerciser$OI OIadapter (fn [^AdapterExerciser a] 1) - ^AdapterExerciser$LS LSadapter (fn [^long a] (short 1)) - ^AdapterExerciser$DS DSadapter (fn [^double a] (short 1)) - ^AdapterExerciser$OS OSadapter (fn [^AdapterExerciser a] (short 1)) - ^AdapterExerciser$LB LBadapter (fn [^long a] (byte 1)) - ^AdapterExerciser$DB DBadapter (fn [^double a] (byte 1)) - ^AdapterExerciser$OB OBadapter (fn [^AdapterExerciser a] (byte 1)) - ^AdapterExerciser$LD LDadapter (fn [^long a] (double 1)) - ^AdapterExerciser$DD DDadapter (fn [^double a] (double 1)) - ^AdapterExerciser$OD ODadapter (fn [^AdapterExerciser a] (double 1)) - ^AdapterExerciser$LF LFadapter (fn [^long a] (float 1)) - ^AdapterExerciser$DF DFadapter (fn [^double a] (float 1)) - ^AdapterExerciser$OF OFadapter (fn [^AdapterExerciser a] (float 1)) - ^AdapterExerciser$LZ LZadapter (fn [^long a] false) - ^AdapterExerciser$DZ DZadapter (fn [^double a] false) - ^AdapterExerciser$OZ OZadapter (fn [^AdapterExerciser a] false) - ^AdapterExerciser$LO LOadapter (fn [^long a] exerciser) - ^AdapterExerciser$DO DOadapter (fn [^double a] exerciser) - ^AdapterExerciser$OO OOadapter (fn [^AdapterExerciser a] exerciser) - ^AdapterExerciser$LLL LLLadapter (fn [^long a ^long b] (long 1)) - ^AdapterExerciser$LOL LOLadapter (fn [^long a ^AdapterExerciser b] (long 1)) - ^AdapterExerciser$OLL OLLadapter (fn [^AdapterExerciser a ^long b] (long 1)) - ^AdapterExerciser$DDL DDLadapter (fn [^double a ^double b] (long 1)) - ^AdapterExerciser$LDL LDLadapter (fn [^long a ^double b] (long 1)) - ^AdapterExerciser$DLL DLLadapter (fn [^double a ^long b] (long 1)) - ^AdapterExerciser$OOL OOLadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (long 1)) - ^AdapterExerciser$ODL ODLadapter (fn [^AdapterExerciser a ^double b] (long 1)) - ^AdapterExerciser$DOL DOLadapter (fn [^double a ^AdapterExerciser b] (long 1)) - ^AdapterExerciser$LLI LLIadapter (fn [^long a ^long b] 1) - ^AdapterExerciser$LOI LOIadapter (fn [^long a ^AdapterExerciser b] 1) - ^AdapterExerciser$OLI OLIadapter (fn [^AdapterExerciser a ^long b] 1) - ^AdapterExerciser$DDI DDIadapter (fn [^double a ^double b] 1) - ^AdapterExerciser$LDI LDIadapter (fn [^long a ^double b] 1) - ^AdapterExerciser$DLI DLIadapter (fn [^double a ^long b] 1) - ^AdapterExerciser$OOI OOIadapter (fn [^AdapterExerciser a ^AdapterExerciser b] 1) - ^AdapterExerciser$ODI ODIadapter (fn [^AdapterExerciser a ^double b] 1) - ^AdapterExerciser$DOI DOIadapter (fn [^double a ^AdapterExerciser b] 1) - ^AdapterExerciser$LLS LLSadapter (fn [^long a ^long b] (short 1)) - ^AdapterExerciser$LOS LOSadapter (fn [^long a ^AdapterExerciser b] (short 1)) - ^AdapterExerciser$OLS OLSadapter (fn [^AdapterExerciser a ^long b] (short 1)) - ^AdapterExerciser$DDS DDSadapter (fn [^double a ^double b] (short 1)) - ^AdapterExerciser$LDS LDSadapter (fn [^long a ^double b] (short 1)) - ^AdapterExerciser$DLS DLSadapter (fn [^double a ^long b] (short 1)) - ^AdapterExerciser$OOS OOSadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (short 1)) - ^AdapterExerciser$ODS ODSadapter (fn [^AdapterExerciser a ^double b] (short 1)) - ^AdapterExerciser$DOS DOSadapter (fn [^double a ^AdapterExerciser b] (short 1)) - ^AdapterExerciser$LLB LLBadapter (fn [^long a ^long b] (byte 1)) - ^AdapterExerciser$LOB LOBadapter (fn [^long a ^AdapterExerciser b] (byte 1)) - ^AdapterExerciser$OLB OLBadapter (fn [^AdapterExerciser a ^long b] (byte 1)) - ^AdapterExerciser$DDB DDBadapter (fn [^double a ^double b] (byte 1)) - ^AdapterExerciser$LDB LDBadapter (fn [^long a ^double b] (byte 1)) - ^AdapterExerciser$DLB DLBadapter (fn [^double a ^long b] (byte 1)) - ^AdapterExerciser$OOB OOBadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (byte 1)) - ^AdapterExerciser$ODB ODBadapter (fn [^AdapterExerciser a ^double b] (byte 1)) - ^AdapterExerciser$DOB DOBadapter (fn [^double a ^AdapterExerciser b] (byte 1)) - ^AdapterExerciser$LLD LLDadapter (fn [^long a ^long b] (double 1)) - ^AdapterExerciser$LOD LODadapter (fn [^long a ^AdapterExerciser b] (double 1)) - ^AdapterExerciser$OLD OLDadapter (fn [^AdapterExerciser a ^long b] (double 1)) - ^AdapterExerciser$DDD DDDadapter (fn [^double a ^double b] (double 1)) - ^AdapterExerciser$LDD LDDadapter (fn [^long a ^double b] (double 1)) - ^AdapterExerciser$DLD DLDadapter (fn [^double a ^long b] (double 1)) - ^AdapterExerciser$OOD OODadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (double 1)) - ^AdapterExerciser$ODD ODDadapter (fn [^AdapterExerciser a ^double b] (double 1)) - ^AdapterExerciser$DOD DODadapter (fn [^double a ^AdapterExerciser b] (double 1)) - ^AdapterExerciser$LLF LLFadapter (fn [^long a ^long b] (float 1)) - ^AdapterExerciser$LOF LOFadapter (fn [^long a ^AdapterExerciser b] (float 1)) - ^AdapterExerciser$OLF OLFadapter (fn [^AdapterExerciser a ^long b] (float 1)) - ^AdapterExerciser$DDF DDFadapter (fn [^double a ^double b] (float 1)) - ^AdapterExerciser$LDF LDFadapter (fn [^long a ^double b] (float 1)) - ^AdapterExerciser$DLF DLFadapter (fn [^double a ^long b] (float 1)) - ^AdapterExerciser$OOF OOFadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (float 1)) - ^AdapterExerciser$ODF ODFadapter (fn [^AdapterExerciser a ^double b] (float 1)) - ^AdapterExerciser$DOF DOFadapter (fn [^double a ^AdapterExerciser b] (float 1)) - ^AdapterExerciser$LLZ LLZadapter (fn [^long a ^long b] false) - ^AdapterExerciser$LOZ LOZadapter (fn [^long a ^AdapterExerciser b] false) - ^AdapterExerciser$OLZ OLZadapter (fn [^AdapterExerciser a ^long b] false) - ^AdapterExerciser$DDZ DDZadapter (fn [^double a ^double b] false) - ^AdapterExerciser$LDZ LDZadapter (fn [^long a ^double b] false) - ^AdapterExerciser$DLZ DLZadapter (fn [^double a ^long b] false) - ^AdapterExerciser$OOZ OOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b] false) - ^AdapterExerciser$ODZ ODZadapter (fn [^AdapterExerciser a ^double b] false) - ^AdapterExerciser$DOZ DOZadapter (fn [^double a ^AdapterExerciser b] false) - ^AdapterExerciser$LLO LLOadapter (fn [^long a ^long b] exerciser) - ^AdapterExerciser$LOO LOOadapter (fn [^long a ^AdapterExerciser b] exerciser) - ^AdapterExerciser$OLO OLOadapter (fn [^AdapterExerciser a ^long b] exerciser) - ^AdapterExerciser$DDO DDOadapter (fn [^double a ^double b] exerciser) - ^AdapterExerciser$LDO LDOadapter (fn [^long a ^double b] exerciser) - ^AdapterExerciser$DLO DLOadapter (fn [^double a ^long b] exerciser) - ^AdapterExerciser$OOO OOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b] exerciser) - ^AdapterExerciser$ODO ODOadapter (fn [^AdapterExerciser a ^double b] exerciser) - ^AdapterExerciser$DOO DOOadapter (fn [^double a ^AdapterExerciser b] exerciser) - ^AdapterExerciser$OOOZ OOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] false) - ^AdapterExerciser$OOOO OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser) - ^AdapterExerciser$OOOOZ OOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] false) - ^AdapterExerciser$OOOOO OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser) - ^AdapterExerciser$OOOOOZ OOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] false) - ^AdapterExerciser$OOOOOO OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser) - ^AdapterExerciser$OOOOOOZ OOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] false) - ^AdapterExerciser$OOOOOOO OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser) - ^AdapterExerciser$OOOOOOOZ OOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] false) - ^AdapterExerciser$OOOOOOOO OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser) - ^AdapterExerciser$OOOOOOOOZ OOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] false) - ^AdapterExerciser$OOOOOOOOO OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser) - ^AdapterExerciser$OOOOOOOOOZ OOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] false) - ^AdapterExerciser$OOOOOOOOOO OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser) - ^AdapterExerciser$OOOOOOOOOOZ OOOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] false) - ^AdapterExerciser$OOOOOOOOOOO OOOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] exerciser)] - (is (= (.takesLRetL LLadapter (long 1)) (long 1))) - (is (= (.takesDRetL DLadapter (double 1)) (long 1))) - (is (= (.takesORetL OLadapter exerciser) (long 1))) - (is (= (.takesLRetI LIadapter (long 1)) 1)) - (is (= (.takesDRetI DIadapter (double 1)) 1)) - (is (= (.takesORetI OIadapter exerciser) 1)) - (is (= (.takesLRetS LSadapter (long 1)) (short 1))) - (is (= (.takesDRetS DSadapter (double 1)) (short 1))) - (is (= (.takesORetS OSadapter exerciser) (short 1))) - (is (= (.takesLRetB LBadapter (long 1)) (byte 1))) - (is (= (.takesDRetB DBadapter (double 1)) (byte 1))) - (is (= (.takesORetB OBadapter exerciser) (byte 1))) - (is (= (.takesLRetD LDadapter (long 1)) (double 1))) - (is (= (.takesDRetD DDadapter (double 1)) (double 1))) - (is (= (.takesORetD ODadapter exerciser) (double 1))) - (is (= (.takesLRetF LFadapter (long 1)) (float 1))) - (is (= (.takesDRetF DFadapter (double 1)) (float 1))) - (is (= (.takesORetF OFadapter exerciser) (float 1))) - (is (= (.takesLRetZ LZadapter (long 1)) false)) - (is (= (.takesDRetZ DZadapter (double 1)) false)) - (is (= (.takesORetZ OZadapter exerciser) false)) - (is (= (.takesLRetO LOadapter (long 1)) exerciser)) - (is (= (.takesDRetO DOadapter (double 1)) exerciser)) - (is (= (.takesORetO OOadapter exerciser) exerciser)) - (is (= (.takesLLRetL LLLadapter (long 1) (long 1)) (long 1))) - (is (= (.takesLORetL LOLadapter (long 1) exerciser) (long 1))) - (is (= (.takesOLRetL OLLadapter exerciser (long 1)) (long 1))) - (is (= (.takesDDRetL DDLadapter (double 1) (double 1)) (long 1))) - (is (= (.takesLDRetL LDLadapter (long 1) (double 1)) (long 1))) - (is (= (.takesDLRetL DLLadapter (double 1) (long 1)) (long 1))) - (is (= (.takesOORetL OOLadapter exerciser exerciser) (long 1))) - (is (= (.takesODRetL ODLadapter exerciser (double 1)) (long 1))) - (is (= (.takesDORetL DOLadapter (double 1) exerciser) (long 1))) - (is (= (.takesLLRetI LLIadapter (long 1) (long 1)) 1)) - (is (= (.takesLORetI LOIadapter (long 1) exerciser) 1)) - (is (= (.takesOLRetI OLIadapter exerciser (long 1)) 1)) - (is (= (.takesDDRetI DDIadapter (double 1) (double 1)) 1)) - (is (= (.takesLDRetI LDIadapter (long 1) (double 1)) 1)) - (is (= (.takesDLRetI DLIadapter (double 1) (long 1)) 1)) - (is (= (.takesOORetI OOIadapter exerciser exerciser) 1)) - (is (= (.takesODRetI ODIadapter exerciser (double 1)) 1)) - (is (= (.takesDORetI DOIadapter (double 1) exerciser) 1)) - (is (= (.takesLLRetS LLSadapter (long 1) (long 1)) (short 1))) - (is (= (.takesLORetS LOSadapter (long 1) exerciser) (short 1))) - (is (= (.takesOLRetS OLSadapter exerciser (long 1)) (short 1))) - (is (= (.takesDDRetS DDSadapter (double 1) (double 1)) (short 1))) - (is (= (.takesLDRetS LDSadapter (long 1) (double 1)) (short 1))) - (is (= (.takesDLRetS DLSadapter (double 1) (long 1)) (short 1))) - (is (= (.takesOORetS OOSadapter exerciser exerciser) (short 1))) - (is (= (.takesODRetS ODSadapter exerciser (double 1)) (short 1))) - (is (= (.takesDORetS DOSadapter (double 1) exerciser) (short 1))) - (is (= (.takesLLRetB LLBadapter (long 1) (long 1)) (byte 1))) - (is (= (.takesLORetB LOBadapter (long 1) exerciser) (byte 1))) - (is (= (.takesOLRetB OLBadapter exerciser (long 1)) (byte 1))) - (is (= (.takesDDRetB DDBadapter (double 1) (double 1)) (byte 1))) - (is (= (.takesLDRetB LDBadapter (long 1) (double 1)) (byte 1))) - (is (= (.takesDLRetB DLBadapter (double 1) (long 1)) (byte 1))) - (is (= (.takesOORetB OOBadapter exerciser exerciser) (byte 1))) - (is (= (.takesODRetB ODBadapter exerciser (double 1)) (byte 1))) - (is (= (.takesDORetB DOBadapter (double 1) exerciser) (byte 1))) - (is (= (.takesLLRetD LLDadapter (long 1) (long 1)) (double 1))) - (is (= (.takesLORetD LODadapter (long 1) exerciser) (double 1))) - (is (= (.takesOLRetD OLDadapter exerciser (long 1)) (double 1))) - (is (= (.takesDDRetD DDDadapter (double 1) (double 1)) (double 1))) - (is (= (.takesLDRetD LDDadapter (long 1) (double 1)) (double 1))) - (is (= (.takesDLRetD DLDadapter (double 1) (long 1)) (double 1))) - (is (= (.takesOORetD OODadapter exerciser exerciser) (double 1))) - (is (= (.takesODRetD ODDadapter exerciser (double 1)) (double 1))) - (is (= (.takesDORetD DODadapter (double 1) exerciser) (double 1))) - (is (= (.takesLLRetF LLFadapter (long 1) (long 1)) (float 1))) - (is (= (.takesLORetF LOFadapter (long 1) exerciser) (float 1))) - (is (= (.takesOLRetF OLFadapter exerciser (long 1)) (float 1))) - (is (= (.takesDDRetF DDFadapter (double 1) (double 1)) (float 1))) - (is (= (.takesLDRetF LDFadapter (long 1) (double 1)) (float 1))) - (is (= (.takesDLRetF DLFadapter (double 1) (long 1)) (float 1))) - (is (= (.takesOORetF OOFadapter exerciser exerciser) (float 1))) - (is (= (.takesODRetF ODFadapter exerciser (double 1)) (float 1))) - (is (= (.takesDORetF DOFadapter (double 1) exerciser) (float 1))) - (is (= (.takesLLRetZ LLZadapter (long 1) (long 1)) false)) - (is (= (.takesLORetZ LOZadapter (long 1) exerciser) false)) - (is (= (.takesOLRetZ OLZadapter exerciser (long 1)) false)) - (is (= (.takesDDRetZ DDZadapter (double 1) (double 1)) false)) - (is (= (.takesLDRetZ LDZadapter (long 1) (double 1)) false)) - (is (= (.takesDLRetZ DLZadapter (double 1) (long 1)) false)) - (is (= (.takesOORetZ OOZadapter exerciser exerciser) false)) - (is (= (.takesODRetZ ODZadapter exerciser (double 1)) false)) - (is (= (.takesDORetZ DOZadapter (double 1) exerciser) false)) - (is (= (.takesLLRetO LLOadapter (long 1) (long 1)) exerciser)) - (is (= (.takesLORetO LOOadapter (long 1) exerciser) exerciser)) - (is (= (.takesOLRetO OLOadapter exerciser (long 1)) exerciser)) - (is (= (.takesDDRetO DDOadapter (double 1) (double 1)) exerciser)) - (is (= (.takesLDRetO LDOadapter (long 1) (double 1)) exerciser)) - (is (= (.takesDLRetO DLOadapter (double 1) (long 1)) exerciser)) - (is (= (.takesOORetO OOOadapter exerciser exerciser) exerciser)) - (is (= (.takesODRetO ODOadapter exerciser (double 1)) exerciser)) - (is (= (.takesDORetO DOOadapter (double 1) exerciser) exerciser)) - (is (= (.takesOOORetZ OOOZadapter exerciser exerciser exerciser) false)) - (is (= (.takesOOORetO OOOOadapter exerciser exerciser exerciser) exerciser)) - (is (= (.takesOOOORetZ OOOOZadapter exerciser exerciser exerciser exerciser) false)) - (is (= (.takesOOOORetO OOOOOadapter exerciser exerciser exerciser exerciser) exerciser)) - (is (= (.takesOOOOORetZ OOOOOZadapter exerciser exerciser exerciser exerciser exerciser) false)) - (is (= (.takesOOOOORetO OOOOOOadapter exerciser exerciser exerciser exerciser exerciser) exerciser)) - (is (= (.takesOOOOOORetZ OOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser) false)) - (is (= (.takesOOOOOORetO OOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) - (is (= (.takesOOOOOOORetZ OOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) - (is (= (.takesOOOOOOORetO OOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) - (is (= (.takesOOOOOOOORetZ OOOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) - (is (= (.takesOOOOOOOORetO OOOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) - (is (= (.takesOOOOOOOOORetZ OOOOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) - (is (= (.takesOOOOOOOOORetO OOOOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) - (is (= (.takesOOOOOOOOOORetZ OOOOOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) - (is (= (.takesOOOOOOOOOORetO OOOOOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)))) + (deftest test-all-fi-adapters-in-let + (let [^AdapterExerciser exerciser (AdapterExerciser.) + ^AdapterExerciser$L Ladapter (fn [] (long 1)) + ^AdapterExerciser$I Iadapter (fn [] 1) + ^AdapterExerciser$S Sadapter (fn [] (short 1)) + ^AdapterExerciser$B Badapter (fn [] (byte 1)) + ^AdapterExerciser$D Dadapter (fn [] (double 1)) + ^AdapterExerciser$F Fadapter (fn [] (float 1)) + ^AdapterExerciser$Z Zadapter (fn [] false) + ^AdapterExerciser$O Oadapter (fn [] exerciser) + ^AdapterExerciser$LL LLadapter (fn [^long a] (long 1)) + ^AdapterExerciser$DL DLadapter (fn [^double a] (long 1)) + ^AdapterExerciser$OL OLadapter (fn [^AdapterExerciser a] (long 1)) + ^AdapterExerciser$LI LIadapter (fn [^long a] 1) + ^AdapterExerciser$DI DIadapter (fn [^double a] 1) + ^AdapterExerciser$OI OIadapter (fn [^AdapterExerciser a] 1) + ^AdapterExerciser$LS LSadapter (fn [^long a] (short 1)) + ^AdapterExerciser$DS DSadapter (fn [^double a] (short 1)) + ^AdapterExerciser$OS OSadapter (fn [^AdapterExerciser a] (short 1)) + ^AdapterExerciser$LB LBadapter (fn [^long a] (byte 1)) + ^AdapterExerciser$DB DBadapter (fn [^double a] (byte 1)) + ^AdapterExerciser$OB OBadapter (fn [^AdapterExerciser a] (byte 1)) + ^AdapterExerciser$LD LDadapter (fn [^long a] (double 1)) + ^AdapterExerciser$DD DDadapter (fn [^double a] (double 1)) + ^AdapterExerciser$OD ODadapter (fn [^AdapterExerciser a] (double 1)) + ^AdapterExerciser$LF LFadapter (fn [^long a] (float 1)) + ^AdapterExerciser$DF DFadapter (fn [^double a] (float 1)) + ^AdapterExerciser$OF OFadapter (fn [^AdapterExerciser a] (float 1)) + ^AdapterExerciser$LZ LZadapter (fn [^long a] false) + ^AdapterExerciser$DZ DZadapter (fn [^double a] false) + ^AdapterExerciser$OZ OZadapter (fn [^AdapterExerciser a] false) + ^AdapterExerciser$LO LOadapter (fn [^long a] exerciser) + ^AdapterExerciser$DO DOadapter (fn [^double a] exerciser) + ^AdapterExerciser$OO OOadapter (fn [^AdapterExerciser a] exerciser) + ^AdapterExerciser$LLL LLLadapter (fn [^long a ^long b] (long 1)) + ^AdapterExerciser$LOL LOLadapter (fn [^long a ^AdapterExerciser b] (long 1)) + ^AdapterExerciser$OLL OLLadapter (fn [^AdapterExerciser a ^long b] (long 1)) + ^AdapterExerciser$DDL DDLadapter (fn [^double a ^double b] (long 1)) + ^AdapterExerciser$LDL LDLadapter (fn [^long a ^double b] (long 1)) + ^AdapterExerciser$DLL DLLadapter (fn [^double a ^long b] (long 1)) + ^AdapterExerciser$OOL OOLadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (long 1)) + ^AdapterExerciser$ODL ODLadapter (fn [^AdapterExerciser a ^double b] (long 1)) + ^AdapterExerciser$DOL DOLadapter (fn [^double a ^AdapterExerciser b] (long 1)) + ^AdapterExerciser$LLI LLIadapter (fn [^long a ^long b] 1) + ^AdapterExerciser$LOI LOIadapter (fn [^long a ^AdapterExerciser b] 1) + ^AdapterExerciser$OLI OLIadapter (fn [^AdapterExerciser a ^long b] 1) + ^AdapterExerciser$DDI DDIadapter (fn [^double a ^double b] 1) + ^AdapterExerciser$LDI LDIadapter (fn [^long a ^double b] 1) + ^AdapterExerciser$DLI DLIadapter (fn [^double a ^long b] 1) + ^AdapterExerciser$OOI OOIadapter (fn [^AdapterExerciser a ^AdapterExerciser b] 1) + ^AdapterExerciser$ODI ODIadapter (fn [^AdapterExerciser a ^double b] 1) + ^AdapterExerciser$DOI DOIadapter (fn [^double a ^AdapterExerciser b] 1) + ^AdapterExerciser$LLS LLSadapter (fn [^long a ^long b] (short 1)) + ^AdapterExerciser$LOS LOSadapter (fn [^long a ^AdapterExerciser b] (short 1)) + ^AdapterExerciser$OLS OLSadapter (fn [^AdapterExerciser a ^long b] (short 1)) + ^AdapterExerciser$DDS DDSadapter (fn [^double a ^double b] (short 1)) + ^AdapterExerciser$LDS LDSadapter (fn [^long a ^double b] (short 1)) + ^AdapterExerciser$DLS DLSadapter (fn [^double a ^long b] (short 1)) + ^AdapterExerciser$OOS OOSadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (short 1)) + ^AdapterExerciser$ODS ODSadapter (fn [^AdapterExerciser a ^double b] (short 1)) + ^AdapterExerciser$DOS DOSadapter (fn [^double a ^AdapterExerciser b] (short 1)) + ^AdapterExerciser$LLB LLBadapter (fn [^long a ^long b] (byte 1)) + ^AdapterExerciser$LOB LOBadapter (fn [^long a ^AdapterExerciser b] (byte 1)) + ^AdapterExerciser$OLB OLBadapter (fn [^AdapterExerciser a ^long b] (byte 1)) + ^AdapterExerciser$DDB DDBadapter (fn [^double a ^double b] (byte 1)) + ^AdapterExerciser$LDB LDBadapter (fn [^long a ^double b] (byte 1)) + ^AdapterExerciser$DLB DLBadapter (fn [^double a ^long b] (byte 1)) + ^AdapterExerciser$OOB OOBadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (byte 1)) + ^AdapterExerciser$ODB ODBadapter (fn [^AdapterExerciser a ^double b] (byte 1)) + ^AdapterExerciser$DOB DOBadapter (fn [^double a ^AdapterExerciser b] (byte 1)) + ^AdapterExerciser$LLD LLDadapter (fn [^long a ^long b] (double 1)) + ^AdapterExerciser$LOD LODadapter (fn [^long a ^AdapterExerciser b] (double 1)) + ^AdapterExerciser$OLD OLDadapter (fn [^AdapterExerciser a ^long b] (double 1)) + ^AdapterExerciser$DDD DDDadapter (fn [^double a ^double b] (double 1)) + ^AdapterExerciser$LDD LDDadapter (fn [^long a ^double b] (double 1)) + ^AdapterExerciser$DLD DLDadapter (fn [^double a ^long b] (double 1)) + ^AdapterExerciser$OOD OODadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (double 1)) + ^AdapterExerciser$ODD ODDadapter (fn [^AdapterExerciser a ^double b] (double 1)) + ^AdapterExerciser$DOD DODadapter (fn [^double a ^AdapterExerciser b] (double 1)) + ^AdapterExerciser$LLF LLFadapter (fn [^long a ^long b] (float 1)) + ^AdapterExerciser$LOF LOFadapter (fn [^long a ^AdapterExerciser b] (float 1)) + ^AdapterExerciser$OLF OLFadapter (fn [^AdapterExerciser a ^long b] (float 1)) + ^AdapterExerciser$DDF DDFadapter (fn [^double a ^double b] (float 1)) + ^AdapterExerciser$LDF LDFadapter (fn [^long a ^double b] (float 1)) + ^AdapterExerciser$DLF DLFadapter (fn [^double a ^long b] (float 1)) + ^AdapterExerciser$OOF OOFadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (float 1)) + ^AdapterExerciser$ODF ODFadapter (fn [^AdapterExerciser a ^double b] (float 1)) + ^AdapterExerciser$DOF DOFadapter (fn [^double a ^AdapterExerciser b] (float 1)) + ^AdapterExerciser$LLZ LLZadapter (fn [^long a ^long b] false) + ^AdapterExerciser$LOZ LOZadapter (fn [^long a ^AdapterExerciser b] false) + ^AdapterExerciser$OLZ OLZadapter (fn [^AdapterExerciser a ^long b] false) + ^AdapterExerciser$DDZ DDZadapter (fn [^double a ^double b] false) + ^AdapterExerciser$LDZ LDZadapter (fn [^long a ^double b] false) + ^AdapterExerciser$DLZ DLZadapter (fn [^double a ^long b] false) + ^AdapterExerciser$OOZ OOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b] false) + ^AdapterExerciser$ODZ ODZadapter (fn [^AdapterExerciser a ^double b] false) + ^AdapterExerciser$DOZ DOZadapter (fn [^double a ^AdapterExerciser b] false) + ^AdapterExerciser$LLO LLOadapter (fn [^long a ^long b] exerciser) + ^AdapterExerciser$LOO LOOadapter (fn [^long a ^AdapterExerciser b] exerciser) + ^AdapterExerciser$OLO OLOadapter (fn [^AdapterExerciser a ^long b] exerciser) + ^AdapterExerciser$DDO DDOadapter (fn [^double a ^double b] exerciser) + ^AdapterExerciser$LDO LDOadapter (fn [^long a ^double b] exerciser) + ^AdapterExerciser$DLO DLOadapter (fn [^double a ^long b] exerciser) + ^AdapterExerciser$OOO OOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b] exerciser) + ^AdapterExerciser$ODO ODOadapter (fn [^AdapterExerciser a ^double b] exerciser) + ^AdapterExerciser$DOO DOOadapter (fn [^double a ^AdapterExerciser b] exerciser) + ^AdapterExerciser$OOOZ OOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] false) + ^AdapterExerciser$OOOO OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser) + ^AdapterExerciser$OOOOZ OOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] false) + ^AdapterExerciser$OOOOO OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser) + ^AdapterExerciser$OOOOOZ OOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] false) + ^AdapterExerciser$OOOOOO OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser) + ^AdapterExerciser$OOOOOOZ OOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] false) + ^AdapterExerciser$OOOOOOO OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser) + ^AdapterExerciser$OOOOOOOZ OOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] false) + ^AdapterExerciser$OOOOOOOO OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser) + ^AdapterExerciser$OOOOOOOOZ OOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] false) + ^AdapterExerciser$OOOOOOOOO OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser) + ^AdapterExerciser$OOOOOOOOOZ OOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] false) + ^AdapterExerciser$OOOOOOOOOO OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser) + ^AdapterExerciser$OOOOOOOOOOZ OOOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] false) + ^AdapterExerciser$OOOOOOOOOOO OOOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] exerciser)] + (is (= (.takesRetL Ladapter ) (long 1))) + (is (= (.takesRetI Iadapter ) 1)) + (is (= (.takesRetS Sadapter ) (short 1))) + (is (= (.takesRetB Badapter ) (byte 1))) + (is (= (.takesRetD Dadapter ) (double 1))) + (is (= (.takesRetF Fadapter ) (float 1))) + (is (= (.takesRetZ Zadapter ) false)) + (is (= (.takesRetO Oadapter ) exerciser)) + (is (= (.takesLRetL LLadapter (long 1)) (long 1))) + (is (= (.takesDRetL DLadapter (double 1)) (long 1))) + (is (= (.takesORetL OLadapter exerciser) (long 1))) + (is (= (.takesLRetI LIadapter (long 1)) 1)) + (is (= (.takesDRetI DIadapter (double 1)) 1)) + (is (= (.takesORetI OIadapter exerciser) 1)) + (is (= (.takesLRetS LSadapter (long 1)) (short 1))) + (is (= (.takesDRetS DSadapter (double 1)) (short 1))) + (is (= (.takesORetS OSadapter exerciser) (short 1))) + (is (= (.takesLRetB LBadapter (long 1)) (byte 1))) + (is (= (.takesDRetB DBadapter (double 1)) (byte 1))) + (is (= (.takesORetB OBadapter exerciser) (byte 1))) + (is (= (.takesLRetD LDadapter (long 1)) (double 1))) + (is (= (.takesDRetD DDadapter (double 1)) (double 1))) + (is (= (.takesORetD ODadapter exerciser) (double 1))) + (is (= (.takesLRetF LFadapter (long 1)) (float 1))) + (is (= (.takesDRetF DFadapter (double 1)) (float 1))) + (is (= (.takesORetF OFadapter exerciser) (float 1))) + (is (= (.takesLRetZ LZadapter (long 1)) false)) + (is (= (.takesDRetZ DZadapter (double 1)) false)) + (is (= (.takesORetZ OZadapter exerciser) false)) + (is (= (.takesLRetO LOadapter (long 1)) exerciser)) + (is (= (.takesDRetO DOadapter (double 1)) exerciser)) + (is (= (.takesORetO OOadapter exerciser) exerciser)) + (is (= (.takesLLRetL LLLadapter (long 1) (long 1)) (long 1))) + (is (= (.takesLORetL LOLadapter (long 1) exerciser) (long 1))) + (is (= (.takesOLRetL OLLadapter exerciser (long 1)) (long 1))) + (is (= (.takesDDRetL DDLadapter (double 1) (double 1)) (long 1))) + (is (= (.takesLDRetL LDLadapter (long 1) (double 1)) (long 1))) + (is (= (.takesDLRetL DLLadapter (double 1) (long 1)) (long 1))) + (is (= (.takesOORetL OOLadapter exerciser exerciser) (long 1))) + (is (= (.takesODRetL ODLadapter exerciser (double 1)) (long 1))) + (is (= (.takesDORetL DOLadapter (double 1) exerciser) (long 1))) + (is (= (.takesLLRetI LLIadapter (long 1) (long 1)) 1)) + (is (= (.takesLORetI LOIadapter (long 1) exerciser) 1)) + (is (= (.takesOLRetI OLIadapter exerciser (long 1)) 1)) + (is (= (.takesDDRetI DDIadapter (double 1) (double 1)) 1)) + (is (= (.takesLDRetI LDIadapter (long 1) (double 1)) 1)) + (is (= (.takesDLRetI DLIadapter (double 1) (long 1)) 1)) + (is (= (.takesOORetI OOIadapter exerciser exerciser) 1)) + (is (= (.takesODRetI ODIadapter exerciser (double 1)) 1)) + (is (= (.takesDORetI DOIadapter (double 1) exerciser) 1)) + (is (= (.takesLLRetS LLSadapter (long 1) (long 1)) (short 1))) + (is (= (.takesLORetS LOSadapter (long 1) exerciser) (short 1))) + (is (= (.takesOLRetS OLSadapter exerciser (long 1)) (short 1))) + (is (= (.takesDDRetS DDSadapter (double 1) (double 1)) (short 1))) + (is (= (.takesLDRetS LDSadapter (long 1) (double 1)) (short 1))) + (is (= (.takesDLRetS DLSadapter (double 1) (long 1)) (short 1))) + (is (= (.takesOORetS OOSadapter exerciser exerciser) (short 1))) + (is (= (.takesODRetS ODSadapter exerciser (double 1)) (short 1))) + (is (= (.takesDORetS DOSadapter (double 1) exerciser) (short 1))) + (is (= (.takesLLRetB LLBadapter (long 1) (long 1)) (byte 1))) + (is (= (.takesLORetB LOBadapter (long 1) exerciser) (byte 1))) + (is (= (.takesOLRetB OLBadapter exerciser (long 1)) (byte 1))) + (is (= (.takesDDRetB DDBadapter (double 1) (double 1)) (byte 1))) + (is (= (.takesLDRetB LDBadapter (long 1) (double 1)) (byte 1))) + (is (= (.takesDLRetB DLBadapter (double 1) (long 1)) (byte 1))) + (is (= (.takesOORetB OOBadapter exerciser exerciser) (byte 1))) + (is (= (.takesODRetB ODBadapter exerciser (double 1)) (byte 1))) + (is (= (.takesDORetB DOBadapter (double 1) exerciser) (byte 1))) + (is (= (.takesLLRetD LLDadapter (long 1) (long 1)) (double 1))) + (is (= (.takesLORetD LODadapter (long 1) exerciser) (double 1))) + (is (= (.takesOLRetD OLDadapter exerciser (long 1)) (double 1))) + (is (= (.takesDDRetD DDDadapter (double 1) (double 1)) (double 1))) + (is (= (.takesLDRetD LDDadapter (long 1) (double 1)) (double 1))) + (is (= (.takesDLRetD DLDadapter (double 1) (long 1)) (double 1))) + (is (= (.takesOORetD OODadapter exerciser exerciser) (double 1))) + (is (= (.takesODRetD ODDadapter exerciser (double 1)) (double 1))) + (is (= (.takesDORetD DODadapter (double 1) exerciser) (double 1))) + (is (= (.takesLLRetF LLFadapter (long 1) (long 1)) (float 1))) + (is (= (.takesLORetF LOFadapter (long 1) exerciser) (float 1))) + (is (= (.takesOLRetF OLFadapter exerciser (long 1)) (float 1))) + (is (= (.takesDDRetF DDFadapter (double 1) (double 1)) (float 1))) + (is (= (.takesLDRetF LDFadapter (long 1) (double 1)) (float 1))) + (is (= (.takesDLRetF DLFadapter (double 1) (long 1)) (float 1))) + (is (= (.takesOORetF OOFadapter exerciser exerciser) (float 1))) + (is (= (.takesODRetF ODFadapter exerciser (double 1)) (float 1))) + (is (= (.takesDORetF DOFadapter (double 1) exerciser) (float 1))) + (is (= (.takesLLRetZ LLZadapter (long 1) (long 1)) false)) + (is (= (.takesLORetZ LOZadapter (long 1) exerciser) false)) + (is (= (.takesOLRetZ OLZadapter exerciser (long 1)) false)) + (is (= (.takesDDRetZ DDZadapter (double 1) (double 1)) false)) + (is (= (.takesLDRetZ LDZadapter (long 1) (double 1)) false)) + (is (= (.takesDLRetZ DLZadapter (double 1) (long 1)) false)) + (is (= (.takesOORetZ OOZadapter exerciser exerciser) false)) + (is (= (.takesODRetZ ODZadapter exerciser (double 1)) false)) + (is (= (.takesDORetZ DOZadapter (double 1) exerciser) false)) + (is (= (.takesLLRetO LLOadapter (long 1) (long 1)) exerciser)) + (is (= (.takesLORetO LOOadapter (long 1) exerciser) exerciser)) + (is (= (.takesOLRetO OLOadapter exerciser (long 1)) exerciser)) + (is (= (.takesDDRetO DDOadapter (double 1) (double 1)) exerciser)) + (is (= (.takesLDRetO LDOadapter (long 1) (double 1)) exerciser)) + (is (= (.takesDLRetO DLOadapter (double 1) (long 1)) exerciser)) + (is (= (.takesOORetO OOOadapter exerciser exerciser) exerciser)) + (is (= (.takesODRetO ODOadapter exerciser (double 1)) exerciser)) + (is (= (.takesDORetO DOOadapter (double 1) exerciser) exerciser)) + (is (= (.takesOOORetZ OOOZadapter exerciser exerciser exerciser) false)) + (is (= (.takesOOORetO OOOOadapter exerciser exerciser exerciser) exerciser)) + (is (= (.takesOOOORetZ OOOOZadapter exerciser exerciser exerciser exerciser) false)) + (is (= (.takesOOOORetO OOOOOadapter exerciser exerciser exerciser exerciser) exerciser)) + (is (= (.takesOOOOORetZ OOOOOZadapter exerciser exerciser exerciser exerciser exerciser) false)) + (is (= (.takesOOOOORetO OOOOOOadapter exerciser exerciser exerciser exerciser exerciser) exerciser)) + (is (= (.takesOOOOOORetZ OOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser) false)) + (is (= (.takesOOOOOORetO OOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) + (is (= (.takesOOOOOOORetZ OOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) + (is (= (.takesOOOOOOORetO OOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) + (is (= (.takesOOOOOOOORetZ OOOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) + (is (= (.takesOOOOOOOORetO OOOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) + (is (= (.takesOOOOOOOOORetZ OOOOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) + (is (= (.takesOOOOOOOOORetO OOOOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) + (is (= (.takesOOOOOOOOOORetZ OOOOOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) + (is (= (.takesOOOOOOOOOORetO OOOOOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)))) \ No newline at end of file diff --git a/test/clojure/test_clojure/generated_functional_adapters_in_def.clj b/test/clojure/test_clojure/generated_functional_adapters_in_def.clj index 5df76ce376..a101ce581f 100644 --- a/test/clojure/test_clojure/generated_functional_adapters_in_def.clj +++ b/test/clojure/test_clojure/generated_functional_adapters_in_def.clj @@ -1,231 +1,248 @@ + (ns clojure.test-clojure.generated-functional-adapters-in-def (:use clojure.test) (:require [clojure.string :as str]) (:import (clojure.test AdapterExerciser))) -(deftest functional-adapters-in-def - (def exerciser (AdapterExerciser.)) - (def LLadapter (fn [^long a] (long 1))) - (is (= (.methodLL ^AdapterExerciser exerciser LLadapter) 0)) - (def DLadapter (fn [^double a] (long 1))) - (is (= (.methodDL ^AdapterExerciser exerciser DLadapter) 1)) - (def OLadapter (fn [^AdapterExerciser a] (long 1))) - (is (= (.methodOL ^AdapterExerciser exerciser OLadapter) 2)) - (def LIadapter (fn [^long a] 1)) - (is (= (.methodLI ^AdapterExerciser exerciser LIadapter) 3)) - (def DIadapter (fn [^double a] 1)) - (is (= (.methodDI ^AdapterExerciser exerciser DIadapter) 4)) - (def OIadapter (fn [^AdapterExerciser a] 1)) - (is (= (.methodOI ^AdapterExerciser exerciser OIadapter) 5)) - (def LSadapter (fn [^long a] (short 1))) - (is (= (.methodLS ^AdapterExerciser exerciser LSadapter) 6)) - (def DSadapter (fn [^double a] (short 1))) - (is (= (.methodDS ^AdapterExerciser exerciser DSadapter) 7)) - (def OSadapter (fn [^AdapterExerciser a] (short 1))) - (is (= (.methodOS ^AdapterExerciser exerciser OSadapter) 8)) - (def LBadapter (fn [^long a] (byte 1))) - (is (= (.methodLB ^AdapterExerciser exerciser LBadapter) 9)) - (def DBadapter (fn [^double a] (byte 1))) - (is (= (.methodDB ^AdapterExerciser exerciser DBadapter) 10)) - (def OBadapter (fn [^AdapterExerciser a] (byte 1))) - (is (= (.methodOB ^AdapterExerciser exerciser OBadapter) 11)) - (def LDadapter (fn [^long a] (double 1))) - (is (= (.methodLD ^AdapterExerciser exerciser LDadapter) 12)) - (def DDadapter (fn [^double a] (double 1))) - (is (= (.methodDD ^AdapterExerciser exerciser DDadapter) 13)) - (def ODadapter (fn [^AdapterExerciser a] (double 1))) - (is (= (.methodOD ^AdapterExerciser exerciser ODadapter) 14)) - (def LFadapter (fn [^long a] (float 1))) - (is (= (.methodLF ^AdapterExerciser exerciser LFadapter) 15)) - (def DFadapter (fn [^double a] (float 1))) - (is (= (.methodDF ^AdapterExerciser exerciser DFadapter) 16)) - (def OFadapter (fn [^AdapterExerciser a] (float 1))) - (is (= (.methodOF ^AdapterExerciser exerciser OFadapter) 17)) - (def LZadapter (fn [^long a] false)) - (is (= (.methodLZ ^AdapterExerciser exerciser LZadapter) 18)) - (def DZadapter (fn [^double a] false)) - (is (= (.methodDZ ^AdapterExerciser exerciser DZadapter) 19)) - (def OZadapter (fn [^AdapterExerciser a] false)) - (is (= (.methodOZ ^AdapterExerciser exerciser OZadapter) 20)) - (def LOadapter (fn [^long a] exerciser)) - (is (= (.methodLO ^AdapterExerciser exerciser LOadapter) 21)) - (def DOadapter (fn [^double a] exerciser)) - (is (= (.methodDO ^AdapterExerciser exerciser DOadapter) 22)) - (def OOadapter (fn [^AdapterExerciser a] exerciser)) - (is (= (.methodOO ^AdapterExerciser exerciser OOadapter) 23)) - (def LLLadapter (fn [^long a ^long b] (long 1))) - (is (= (.methodLLL ^AdapterExerciser exerciser LLLadapter) 24)) - (def LOLadapter (fn [^long a ^AdapterExerciser b] (long 1))) - (is (= (.methodLOL ^AdapterExerciser exerciser LOLadapter) 25)) - (def OLLadapter (fn [^AdapterExerciser a ^long b] (long 1))) - (is (= (.methodOLL ^AdapterExerciser exerciser OLLadapter) 26)) - (def DDLadapter (fn [^double a ^double b] (long 1))) - (is (= (.methodDDL ^AdapterExerciser exerciser DDLadapter) 27)) - (def LDLadapter (fn [^long a ^double b] (long 1))) - (is (= (.methodLDL ^AdapterExerciser exerciser LDLadapter) 28)) - (def DLLadapter (fn [^double a ^long b] (long 1))) - (is (= (.methodDLL ^AdapterExerciser exerciser DLLadapter) 29)) - (def OOLadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (long 1))) - (is (= (.methodOOL ^AdapterExerciser exerciser OOLadapter) 30)) - (def ODLadapter (fn [^AdapterExerciser a ^double b] (long 1))) - (is (= (.methodODL ^AdapterExerciser exerciser ODLadapter) 31)) - (def DOLadapter (fn [^double a ^AdapterExerciser b] (long 1))) - (is (= (.methodDOL ^AdapterExerciser exerciser DOLadapter) 32)) - (def LLIadapter (fn [^long a ^long b] 1)) - (is (= (.methodLLI ^AdapterExerciser exerciser LLIadapter) 33)) - (def LOIadapter (fn [^long a ^AdapterExerciser b] 1)) - (is (= (.methodLOI ^AdapterExerciser exerciser LOIadapter) 34)) - (def OLIadapter (fn [^AdapterExerciser a ^long b] 1)) - (is (= (.methodOLI ^AdapterExerciser exerciser OLIadapter) 35)) - (def DDIadapter (fn [^double a ^double b] 1)) - (is (= (.methodDDI ^AdapterExerciser exerciser DDIadapter) 36)) - (def LDIadapter (fn [^long a ^double b] 1)) - (is (= (.methodLDI ^AdapterExerciser exerciser LDIadapter) 37)) - (def DLIadapter (fn [^double a ^long b] 1)) - (is (= (.methodDLI ^AdapterExerciser exerciser DLIadapter) 38)) - (def OOIadapter (fn [^AdapterExerciser a ^AdapterExerciser b] 1)) - (is (= (.methodOOI ^AdapterExerciser exerciser OOIadapter) 39)) - (def ODIadapter (fn [^AdapterExerciser a ^double b] 1)) - (is (= (.methodODI ^AdapterExerciser exerciser ODIadapter) 40)) - (def DOIadapter (fn [^double a ^AdapterExerciser b] 1)) - (is (= (.methodDOI ^AdapterExerciser exerciser DOIadapter) 41)) - (def LLSadapter (fn [^long a ^long b] (short 1))) - (is (= (.methodLLS ^AdapterExerciser exerciser LLSadapter) 42)) - (def LOSadapter (fn [^long a ^AdapterExerciser b] (short 1))) - (is (= (.methodLOS ^AdapterExerciser exerciser LOSadapter) 43)) - (def OLSadapter (fn [^AdapterExerciser a ^long b] (short 1))) - (is (= (.methodOLS ^AdapterExerciser exerciser OLSadapter) 44)) - (def DDSadapter (fn [^double a ^double b] (short 1))) - (is (= (.methodDDS ^AdapterExerciser exerciser DDSadapter) 45)) - (def LDSadapter (fn [^long a ^double b] (short 1))) - (is (= (.methodLDS ^AdapterExerciser exerciser LDSadapter) 46)) - (def DLSadapter (fn [^double a ^long b] (short 1))) - (is (= (.methodDLS ^AdapterExerciser exerciser DLSadapter) 47)) - (def OOSadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (short 1))) - (is (= (.methodOOS ^AdapterExerciser exerciser OOSadapter) 48)) - (def ODSadapter (fn [^AdapterExerciser a ^double b] (short 1))) - (is (= (.methodODS ^AdapterExerciser exerciser ODSadapter) 49)) - (def DOSadapter (fn [^double a ^AdapterExerciser b] (short 1))) - (is (= (.methodDOS ^AdapterExerciser exerciser DOSadapter) 50)) - (def LLBadapter (fn [^long a ^long b] (byte 1))) - (is (= (.methodLLB ^AdapterExerciser exerciser LLBadapter) 51)) - (def LOBadapter (fn [^long a ^AdapterExerciser b] (byte 1))) - (is (= (.methodLOB ^AdapterExerciser exerciser LOBadapter) 52)) - (def OLBadapter (fn [^AdapterExerciser a ^long b] (byte 1))) - (is (= (.methodOLB ^AdapterExerciser exerciser OLBadapter) 53)) - (def DDBadapter (fn [^double a ^double b] (byte 1))) - (is (= (.methodDDB ^AdapterExerciser exerciser DDBadapter) 54)) - (def LDBadapter (fn [^long a ^double b] (byte 1))) - (is (= (.methodLDB ^AdapterExerciser exerciser LDBadapter) 55)) - (def DLBadapter (fn [^double a ^long b] (byte 1))) - (is (= (.methodDLB ^AdapterExerciser exerciser DLBadapter) 56)) - (def OOBadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (byte 1))) - (is (= (.methodOOB ^AdapterExerciser exerciser OOBadapter) 57)) - (def ODBadapter (fn [^AdapterExerciser a ^double b] (byte 1))) - (is (= (.methodODB ^AdapterExerciser exerciser ODBadapter) 58)) - (def DOBadapter (fn [^double a ^AdapterExerciser b] (byte 1))) - (is (= (.methodDOB ^AdapterExerciser exerciser DOBadapter) 59)) - (def LLDadapter (fn [^long a ^long b] (double 1))) - (is (= (.methodLLD ^AdapterExerciser exerciser LLDadapter) 60)) - (def LODadapter (fn [^long a ^AdapterExerciser b] (double 1))) - (is (= (.methodLOD ^AdapterExerciser exerciser LODadapter) 61)) - (def OLDadapter (fn [^AdapterExerciser a ^long b] (double 1))) - (is (= (.methodOLD ^AdapterExerciser exerciser OLDadapter) 62)) - (def DDDadapter (fn [^double a ^double b] (double 1))) - (is (= (.methodDDD ^AdapterExerciser exerciser DDDadapter) 63)) - (def LDDadapter (fn [^long a ^double b] (double 1))) - (is (= (.methodLDD ^AdapterExerciser exerciser LDDadapter) 64)) - (def DLDadapter (fn [^double a ^long b] (double 1))) - (is (= (.methodDLD ^AdapterExerciser exerciser DLDadapter) 65)) - (def OODadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (double 1))) - (is (= (.methodOOD ^AdapterExerciser exerciser OODadapter) 66)) - (def ODDadapter (fn [^AdapterExerciser a ^double b] (double 1))) - (is (= (.methodODD ^AdapterExerciser exerciser ODDadapter) 67)) - (def DODadapter (fn [^double a ^AdapterExerciser b] (double 1))) - (is (= (.methodDOD ^AdapterExerciser exerciser DODadapter) 68)) - (def LLFadapter (fn [^long a ^long b] (float 1))) - (is (= (.methodLLF ^AdapterExerciser exerciser LLFadapter) 69)) - (def LOFadapter (fn [^long a ^AdapterExerciser b] (float 1))) - (is (= (.methodLOF ^AdapterExerciser exerciser LOFadapter) 70)) - (def OLFadapter (fn [^AdapterExerciser a ^long b] (float 1))) - (is (= (.methodOLF ^AdapterExerciser exerciser OLFadapter) 71)) - (def DDFadapter (fn [^double a ^double b] (float 1))) - (is (= (.methodDDF ^AdapterExerciser exerciser DDFadapter) 72)) - (def LDFadapter (fn [^long a ^double b] (float 1))) - (is (= (.methodLDF ^AdapterExerciser exerciser LDFadapter) 73)) - (def DLFadapter (fn [^double a ^long b] (float 1))) - (is (= (.methodDLF ^AdapterExerciser exerciser DLFadapter) 74)) - (def OOFadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (float 1))) - (is (= (.methodOOF ^AdapterExerciser exerciser OOFadapter) 75)) - (def ODFadapter (fn [^AdapterExerciser a ^double b] (float 1))) - (is (= (.methodODF ^AdapterExerciser exerciser ODFadapter) 76)) - (def DOFadapter (fn [^double a ^AdapterExerciser b] (float 1))) - (is (= (.methodDOF ^AdapterExerciser exerciser DOFadapter) 77)) - (def LLZadapter (fn [^long a ^long b] false)) - (is (= (.methodLLZ ^AdapterExerciser exerciser LLZadapter) 78)) - (def LOZadapter (fn [^long a ^AdapterExerciser b] false)) - (is (= (.methodLOZ ^AdapterExerciser exerciser LOZadapter) 79)) - (def OLZadapter (fn [^AdapterExerciser a ^long b] false)) - (is (= (.methodOLZ ^AdapterExerciser exerciser OLZadapter) 80)) - (def DDZadapter (fn [^double a ^double b] false)) - (is (= (.methodDDZ ^AdapterExerciser exerciser DDZadapter) 81)) - (def LDZadapter (fn [^long a ^double b] false)) - (is (= (.methodLDZ ^AdapterExerciser exerciser LDZadapter) 82)) - (def DLZadapter (fn [^double a ^long b] false)) - (is (= (.methodDLZ ^AdapterExerciser exerciser DLZadapter) 83)) - (def OOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b] false)) - (is (= (.methodOOZ ^AdapterExerciser exerciser OOZadapter) 84)) - (def ODZadapter (fn [^AdapterExerciser a ^double b] false)) - (is (= (.methodODZ ^AdapterExerciser exerciser ODZadapter) 85)) - (def DOZadapter (fn [^double a ^AdapterExerciser b] false)) - (is (= (.methodDOZ ^AdapterExerciser exerciser DOZadapter) 86)) - (def LLOadapter (fn [^long a ^long b] exerciser)) - (is (= (.methodLLO ^AdapterExerciser exerciser LLOadapter) 87)) - (def LOOadapter (fn [^long a ^AdapterExerciser b] exerciser)) - (is (= (.methodLOO ^AdapterExerciser exerciser LOOadapter) 88)) - (def OLOadapter (fn [^AdapterExerciser a ^long b] exerciser)) - (is (= (.methodOLO ^AdapterExerciser exerciser OLOadapter) 89)) - (def DDOadapter (fn [^double a ^double b] exerciser)) - (is (= (.methodDDO ^AdapterExerciser exerciser DDOadapter) 90)) - (def LDOadapter (fn [^long a ^double b] exerciser)) - (is (= (.methodLDO ^AdapterExerciser exerciser LDOadapter) 91)) - (def DLOadapter (fn [^double a ^long b] exerciser)) - (is (= (.methodDLO ^AdapterExerciser exerciser DLOadapter) 92)) - (def OOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b] exerciser)) - (is (= (.methodOOO ^AdapterExerciser exerciser OOOadapter) 93)) - (def ODOadapter (fn [^AdapterExerciser a ^double b] exerciser)) - (is (= (.methodODO ^AdapterExerciser exerciser ODOadapter) 94)) - (def DOOadapter (fn [^double a ^AdapterExerciser b] exerciser)) - (is (= (.methodDOO ^AdapterExerciser exerciser DOOadapter) 95)) - (def OOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] false)) - (is (= (.methodOOOZ ^AdapterExerciser exerciser OOOZadapter) 96)) - (def OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser)) - (is (= (.methodOOOO ^AdapterExerciser exerciser OOOOadapter) 97)) - (def OOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] false)) - (is (= (.methodOOOOZ ^AdapterExerciser exerciser OOOOZadapter) 98)) - (def OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser)) - (is (= (.methodOOOOO ^AdapterExerciser exerciser OOOOOadapter) 99)) - (def OOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] false)) - (is (= (.methodOOOOOZ ^AdapterExerciser exerciser OOOOOZadapter) 100)) - (def OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser)) - (is (= (.methodOOOOOO ^AdapterExerciser exerciser OOOOOOadapter) 101)) - (def OOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] false)) - (is (= (.methodOOOOOOZ ^AdapterExerciser exerciser OOOOOOZadapter) 102)) - (def OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser)) - (is (= (.methodOOOOOOO ^AdapterExerciser exerciser OOOOOOOadapter) 103)) - (def OOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] false)) - (is (= (.methodOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOZadapter) 104)) - (def OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser)) - (is (= (.methodOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOadapter) 105)) - (def OOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] false)) - (is (= (.methodOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOZadapter) 106)) - (def OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser)) - (is (= (.methodOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOadapter) 107)) - (def OOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] false)) - (is (= (.methodOOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOOZadapter) 108)) - (def OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser)) - (is (= (.methodOOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOOadapter) 109)) - (def OOOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] false)) - (is (= (.methodOOOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOOOZadapter) 110)) - (def OOOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] exerciser)) - (is (= (.methodOOOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOOOadapter) 111))) + (deftest functional-adapters-in-def + (def exerciser (AdapterExerciser.)) + (def Ladapter (fn [] (long 1))) + (is (= (.methodL ^AdapterExerciser exerciser Ladapter) 0)) + (def Iadapter (fn [] 1)) + (is (= (.methodI ^AdapterExerciser exerciser Iadapter) 1)) + (def Sadapter (fn [] (short 1))) + (is (= (.methodS ^AdapterExerciser exerciser Sadapter) 2)) + (def Badapter (fn [] (byte 1))) + (is (= (.methodB ^AdapterExerciser exerciser Badapter) 3)) + (def Dadapter (fn [] (double 1))) + (is (= (.methodD ^AdapterExerciser exerciser Dadapter) 4)) + (def Fadapter (fn [] (float 1))) + (is (= (.methodF ^AdapterExerciser exerciser Fadapter) 5)) + (def Zadapter (fn [] false)) + (is (= (.methodZ ^AdapterExerciser exerciser Zadapter) 6)) + (def Oadapter (fn [] exerciser)) + (is (= (.methodO ^AdapterExerciser exerciser Oadapter) 7)) + (def LLadapter (fn [^long a] (long 1))) + (is (= (.methodLL ^AdapterExerciser exerciser LLadapter) 8)) + (def DLadapter (fn [^double a] (long 1))) + (is (= (.methodDL ^AdapterExerciser exerciser DLadapter) 9)) + (def OLadapter (fn [^AdapterExerciser a] (long 1))) + (is (= (.methodOL ^AdapterExerciser exerciser OLadapter) 10)) + (def LIadapter (fn [^long a] 1)) + (is (= (.methodLI ^AdapterExerciser exerciser LIadapter) 11)) + (def DIadapter (fn [^double a] 1)) + (is (= (.methodDI ^AdapterExerciser exerciser DIadapter) 12)) + (def OIadapter (fn [^AdapterExerciser a] 1)) + (is (= (.methodOI ^AdapterExerciser exerciser OIadapter) 13)) + (def LSadapter (fn [^long a] (short 1))) + (is (= (.methodLS ^AdapterExerciser exerciser LSadapter) 14)) + (def DSadapter (fn [^double a] (short 1))) + (is (= (.methodDS ^AdapterExerciser exerciser DSadapter) 15)) + (def OSadapter (fn [^AdapterExerciser a] (short 1))) + (is (= (.methodOS ^AdapterExerciser exerciser OSadapter) 16)) + (def LBadapter (fn [^long a] (byte 1))) + (is (= (.methodLB ^AdapterExerciser exerciser LBadapter) 17)) + (def DBadapter (fn [^double a] (byte 1))) + (is (= (.methodDB ^AdapterExerciser exerciser DBadapter) 18)) + (def OBadapter (fn [^AdapterExerciser a] (byte 1))) + (is (= (.methodOB ^AdapterExerciser exerciser OBadapter) 19)) + (def LDadapter (fn [^long a] (double 1))) + (is (= (.methodLD ^AdapterExerciser exerciser LDadapter) 20)) + (def DDadapter (fn [^double a] (double 1))) + (is (= (.methodDD ^AdapterExerciser exerciser DDadapter) 21)) + (def ODadapter (fn [^AdapterExerciser a] (double 1))) + (is (= (.methodOD ^AdapterExerciser exerciser ODadapter) 22)) + (def LFadapter (fn [^long a] (float 1))) + (is (= (.methodLF ^AdapterExerciser exerciser LFadapter) 23)) + (def DFadapter (fn [^double a] (float 1))) + (is (= (.methodDF ^AdapterExerciser exerciser DFadapter) 24)) + (def OFadapter (fn [^AdapterExerciser a] (float 1))) + (is (= (.methodOF ^AdapterExerciser exerciser OFadapter) 25)) + (def LZadapter (fn [^long a] false)) + (is (= (.methodLZ ^AdapterExerciser exerciser LZadapter) 26)) + (def DZadapter (fn [^double a] false)) + (is (= (.methodDZ ^AdapterExerciser exerciser DZadapter) 27)) + (def OZadapter (fn [^AdapterExerciser a] false)) + (is (= (.methodOZ ^AdapterExerciser exerciser OZadapter) 28)) + (def LOadapter (fn [^long a] exerciser)) + (is (= (.methodLO ^AdapterExerciser exerciser LOadapter) 29)) + (def DOadapter (fn [^double a] exerciser)) + (is (= (.methodDO ^AdapterExerciser exerciser DOadapter) 30)) + (def OOadapter (fn [^AdapterExerciser a] exerciser)) + (is (= (.methodOO ^AdapterExerciser exerciser OOadapter) 31)) + (def LLLadapter (fn [^long a ^long b] (long 1))) + (is (= (.methodLLL ^AdapterExerciser exerciser LLLadapter) 32)) + (def LOLadapter (fn [^long a ^AdapterExerciser b] (long 1))) + (is (= (.methodLOL ^AdapterExerciser exerciser LOLadapter) 33)) + (def OLLadapter (fn [^AdapterExerciser a ^long b] (long 1))) + (is (= (.methodOLL ^AdapterExerciser exerciser OLLadapter) 34)) + (def DDLadapter (fn [^double a ^double b] (long 1))) + (is (= (.methodDDL ^AdapterExerciser exerciser DDLadapter) 35)) + (def LDLadapter (fn [^long a ^double b] (long 1))) + (is (= (.methodLDL ^AdapterExerciser exerciser LDLadapter) 36)) + (def DLLadapter (fn [^double a ^long b] (long 1))) + (is (= (.methodDLL ^AdapterExerciser exerciser DLLadapter) 37)) + (def OOLadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (long 1))) + (is (= (.methodOOL ^AdapterExerciser exerciser OOLadapter) 38)) + (def ODLadapter (fn [^AdapterExerciser a ^double b] (long 1))) + (is (= (.methodODL ^AdapterExerciser exerciser ODLadapter) 39)) + (def DOLadapter (fn [^double a ^AdapterExerciser b] (long 1))) + (is (= (.methodDOL ^AdapterExerciser exerciser DOLadapter) 40)) + (def LLIadapter (fn [^long a ^long b] 1)) + (is (= (.methodLLI ^AdapterExerciser exerciser LLIadapter) 41)) + (def LOIadapter (fn [^long a ^AdapterExerciser b] 1)) + (is (= (.methodLOI ^AdapterExerciser exerciser LOIadapter) 42)) + (def OLIadapter (fn [^AdapterExerciser a ^long b] 1)) + (is (= (.methodOLI ^AdapterExerciser exerciser OLIadapter) 43)) + (def DDIadapter (fn [^double a ^double b] 1)) + (is (= (.methodDDI ^AdapterExerciser exerciser DDIadapter) 44)) + (def LDIadapter (fn [^long a ^double b] 1)) + (is (= (.methodLDI ^AdapterExerciser exerciser LDIadapter) 45)) + (def DLIadapter (fn [^double a ^long b] 1)) + (is (= (.methodDLI ^AdapterExerciser exerciser DLIadapter) 46)) + (def OOIadapter (fn [^AdapterExerciser a ^AdapterExerciser b] 1)) + (is (= (.methodOOI ^AdapterExerciser exerciser OOIadapter) 47)) + (def ODIadapter (fn [^AdapterExerciser a ^double b] 1)) + (is (= (.methodODI ^AdapterExerciser exerciser ODIadapter) 48)) + (def DOIadapter (fn [^double a ^AdapterExerciser b] 1)) + (is (= (.methodDOI ^AdapterExerciser exerciser DOIadapter) 49)) + (def LLSadapter (fn [^long a ^long b] (short 1))) + (is (= (.methodLLS ^AdapterExerciser exerciser LLSadapter) 50)) + (def LOSadapter (fn [^long a ^AdapterExerciser b] (short 1))) + (is (= (.methodLOS ^AdapterExerciser exerciser LOSadapter) 51)) + (def OLSadapter (fn [^AdapterExerciser a ^long b] (short 1))) + (is (= (.methodOLS ^AdapterExerciser exerciser OLSadapter) 52)) + (def DDSadapter (fn [^double a ^double b] (short 1))) + (is (= (.methodDDS ^AdapterExerciser exerciser DDSadapter) 53)) + (def LDSadapter (fn [^long a ^double b] (short 1))) + (is (= (.methodLDS ^AdapterExerciser exerciser LDSadapter) 54)) + (def DLSadapter (fn [^double a ^long b] (short 1))) + (is (= (.methodDLS ^AdapterExerciser exerciser DLSadapter) 55)) + (def OOSadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (short 1))) + (is (= (.methodOOS ^AdapterExerciser exerciser OOSadapter) 56)) + (def ODSadapter (fn [^AdapterExerciser a ^double b] (short 1))) + (is (= (.methodODS ^AdapterExerciser exerciser ODSadapter) 57)) + (def DOSadapter (fn [^double a ^AdapterExerciser b] (short 1))) + (is (= (.methodDOS ^AdapterExerciser exerciser DOSadapter) 58)) + (def LLBadapter (fn [^long a ^long b] (byte 1))) + (is (= (.methodLLB ^AdapterExerciser exerciser LLBadapter) 59)) + (def LOBadapter (fn [^long a ^AdapterExerciser b] (byte 1))) + (is (= (.methodLOB ^AdapterExerciser exerciser LOBadapter) 60)) + (def OLBadapter (fn [^AdapterExerciser a ^long b] (byte 1))) + (is (= (.methodOLB ^AdapterExerciser exerciser OLBadapter) 61)) + (def DDBadapter (fn [^double a ^double b] (byte 1))) + (is (= (.methodDDB ^AdapterExerciser exerciser DDBadapter) 62)) + (def LDBadapter (fn [^long a ^double b] (byte 1))) + (is (= (.methodLDB ^AdapterExerciser exerciser LDBadapter) 63)) + (def DLBadapter (fn [^double a ^long b] (byte 1))) + (is (= (.methodDLB ^AdapterExerciser exerciser DLBadapter) 64)) + (def OOBadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (byte 1))) + (is (= (.methodOOB ^AdapterExerciser exerciser OOBadapter) 65)) + (def ODBadapter (fn [^AdapterExerciser a ^double b] (byte 1))) + (is (= (.methodODB ^AdapterExerciser exerciser ODBadapter) 66)) + (def DOBadapter (fn [^double a ^AdapterExerciser b] (byte 1))) + (is (= (.methodDOB ^AdapterExerciser exerciser DOBadapter) 67)) + (def LLDadapter (fn [^long a ^long b] (double 1))) + (is (= (.methodLLD ^AdapterExerciser exerciser LLDadapter) 68)) + (def LODadapter (fn [^long a ^AdapterExerciser b] (double 1))) + (is (= (.methodLOD ^AdapterExerciser exerciser LODadapter) 69)) + (def OLDadapter (fn [^AdapterExerciser a ^long b] (double 1))) + (is (= (.methodOLD ^AdapterExerciser exerciser OLDadapter) 70)) + (def DDDadapter (fn [^double a ^double b] (double 1))) + (is (= (.methodDDD ^AdapterExerciser exerciser DDDadapter) 71)) + (def LDDadapter (fn [^long a ^double b] (double 1))) + (is (= (.methodLDD ^AdapterExerciser exerciser LDDadapter) 72)) + (def DLDadapter (fn [^double a ^long b] (double 1))) + (is (= (.methodDLD ^AdapterExerciser exerciser DLDadapter) 73)) + (def OODadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (double 1))) + (is (= (.methodOOD ^AdapterExerciser exerciser OODadapter) 74)) + (def ODDadapter (fn [^AdapterExerciser a ^double b] (double 1))) + (is (= (.methodODD ^AdapterExerciser exerciser ODDadapter) 75)) + (def DODadapter (fn [^double a ^AdapterExerciser b] (double 1))) + (is (= (.methodDOD ^AdapterExerciser exerciser DODadapter) 76)) + (def LLFadapter (fn [^long a ^long b] (float 1))) + (is (= (.methodLLF ^AdapterExerciser exerciser LLFadapter) 77)) + (def LOFadapter (fn [^long a ^AdapterExerciser b] (float 1))) + (is (= (.methodLOF ^AdapterExerciser exerciser LOFadapter) 78)) + (def OLFadapter (fn [^AdapterExerciser a ^long b] (float 1))) + (is (= (.methodOLF ^AdapterExerciser exerciser OLFadapter) 79)) + (def DDFadapter (fn [^double a ^double b] (float 1))) + (is (= (.methodDDF ^AdapterExerciser exerciser DDFadapter) 80)) + (def LDFadapter (fn [^long a ^double b] (float 1))) + (is (= (.methodLDF ^AdapterExerciser exerciser LDFadapter) 81)) + (def DLFadapter (fn [^double a ^long b] (float 1))) + (is (= (.methodDLF ^AdapterExerciser exerciser DLFadapter) 82)) + (def OOFadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (float 1))) + (is (= (.methodOOF ^AdapterExerciser exerciser OOFadapter) 83)) + (def ODFadapter (fn [^AdapterExerciser a ^double b] (float 1))) + (is (= (.methodODF ^AdapterExerciser exerciser ODFadapter) 84)) + (def DOFadapter (fn [^double a ^AdapterExerciser b] (float 1))) + (is (= (.methodDOF ^AdapterExerciser exerciser DOFadapter) 85)) + (def LLZadapter (fn [^long a ^long b] false)) + (is (= (.methodLLZ ^AdapterExerciser exerciser LLZadapter) 86)) + (def LOZadapter (fn [^long a ^AdapterExerciser b] false)) + (is (= (.methodLOZ ^AdapterExerciser exerciser LOZadapter) 87)) + (def OLZadapter (fn [^AdapterExerciser a ^long b] false)) + (is (= (.methodOLZ ^AdapterExerciser exerciser OLZadapter) 88)) + (def DDZadapter (fn [^double a ^double b] false)) + (is (= (.methodDDZ ^AdapterExerciser exerciser DDZadapter) 89)) + (def LDZadapter (fn [^long a ^double b] false)) + (is (= (.methodLDZ ^AdapterExerciser exerciser LDZadapter) 90)) + (def DLZadapter (fn [^double a ^long b] false)) + (is (= (.methodDLZ ^AdapterExerciser exerciser DLZadapter) 91)) + (def OOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b] false)) + (is (= (.methodOOZ ^AdapterExerciser exerciser OOZadapter) 92)) + (def ODZadapter (fn [^AdapterExerciser a ^double b] false)) + (is (= (.methodODZ ^AdapterExerciser exerciser ODZadapter) 93)) + (def DOZadapter (fn [^double a ^AdapterExerciser b] false)) + (is (= (.methodDOZ ^AdapterExerciser exerciser DOZadapter) 94)) + (def LLOadapter (fn [^long a ^long b] exerciser)) + (is (= (.methodLLO ^AdapterExerciser exerciser LLOadapter) 95)) + (def LOOadapter (fn [^long a ^AdapterExerciser b] exerciser)) + (is (= (.methodLOO ^AdapterExerciser exerciser LOOadapter) 96)) + (def OLOadapter (fn [^AdapterExerciser a ^long b] exerciser)) + (is (= (.methodOLO ^AdapterExerciser exerciser OLOadapter) 97)) + (def DDOadapter (fn [^double a ^double b] exerciser)) + (is (= (.methodDDO ^AdapterExerciser exerciser DDOadapter) 98)) + (def LDOadapter (fn [^long a ^double b] exerciser)) + (is (= (.methodLDO ^AdapterExerciser exerciser LDOadapter) 99)) + (def DLOadapter (fn [^double a ^long b] exerciser)) + (is (= (.methodDLO ^AdapterExerciser exerciser DLOadapter) 100)) + (def OOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b] exerciser)) + (is (= (.methodOOO ^AdapterExerciser exerciser OOOadapter) 101)) + (def ODOadapter (fn [^AdapterExerciser a ^double b] exerciser)) + (is (= (.methodODO ^AdapterExerciser exerciser ODOadapter) 102)) + (def DOOadapter (fn [^double a ^AdapterExerciser b] exerciser)) + (is (= (.methodDOO ^AdapterExerciser exerciser DOOadapter) 103)) + (def OOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] false)) + (is (= (.methodOOOZ ^AdapterExerciser exerciser OOOZadapter) 104)) + (def OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser)) + (is (= (.methodOOOO ^AdapterExerciser exerciser OOOOadapter) 105)) + (def OOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] false)) + (is (= (.methodOOOOZ ^AdapterExerciser exerciser OOOOZadapter) 106)) + (def OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser)) + (is (= (.methodOOOOO ^AdapterExerciser exerciser OOOOOadapter) 107)) + (def OOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] false)) + (is (= (.methodOOOOOZ ^AdapterExerciser exerciser OOOOOZadapter) 108)) + (def OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser)) + (is (= (.methodOOOOOO ^AdapterExerciser exerciser OOOOOOadapter) 109)) + (def OOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] false)) + (is (= (.methodOOOOOOZ ^AdapterExerciser exerciser OOOOOOZadapter) 110)) + (def OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser)) + (is (= (.methodOOOOOOO ^AdapterExerciser exerciser OOOOOOOadapter) 111)) + (def OOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] false)) + (is (= (.methodOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOZadapter) 112)) + (def OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser)) + (is (= (.methodOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOadapter) 113)) + (def OOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] false)) + (is (= (.methodOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOZadapter) 114)) + (def OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser)) + (is (= (.methodOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOadapter) 115)) + (def OOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] false)) + (is (= (.methodOOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOOZadapter) 116)) + (def OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser)) + (is (= (.methodOOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOOadapter) 117)) + (def OOOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] false)) + (is (= (.methodOOOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOOOZadapter) 118)) + (def OOOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] exerciser)) + (is (= (.methodOOOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOOOadapter) 119))) \ No newline at end of file diff --git a/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj b/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj index 57919d03d6..f3072ea022 100644 --- a/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj +++ b/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj @@ -1,231 +1,248 @@ + (ns clojure.test-clojure.generated-functional-adapters-in-def-requiring-reflection (:use clojure.test) (:require [clojure.string :as str]) (:import (clojure.test AdapterExerciser))) -(deftest functional-adapters-in-def - (def exerciser (AdapterExerciser.)) - (def LLadapter (fn [^long a] (long 1))) - (is (= (.methodLL exerciser LLadapter) 0)) - (def DLadapter (fn [^double a] (long 1))) - (is (= (.methodDL exerciser DLadapter) 1)) - (def OLadapter (fn [^AdapterExerciser a] (long 1))) - (is (= (.methodOL exerciser OLadapter) 2)) - (def LIadapter (fn [^long a] 1)) - (is (= (.methodLI exerciser LIadapter) 3)) - (def DIadapter (fn [^double a] 1)) - (is (= (.methodDI exerciser DIadapter) 4)) - (def OIadapter (fn [^AdapterExerciser a] 1)) - (is (= (.methodOI exerciser OIadapter) 5)) - (def LSadapter (fn [^long a] (short 1))) - (is (= (.methodLS exerciser LSadapter) 6)) - (def DSadapter (fn [^double a] (short 1))) - (is (= (.methodDS exerciser DSadapter) 7)) - (def OSadapter (fn [^AdapterExerciser a] (short 1))) - (is (= (.methodOS exerciser OSadapter) 8)) - (def LBadapter (fn [^long a] (byte 1))) - (is (= (.methodLB exerciser LBadapter) 9)) - (def DBadapter (fn [^double a] (byte 1))) - (is (= (.methodDB exerciser DBadapter) 10)) - (def OBadapter (fn [^AdapterExerciser a] (byte 1))) - (is (= (.methodOB exerciser OBadapter) 11)) - (def LDadapter (fn [^long a] (double 1))) - (is (= (.methodLD exerciser LDadapter) 12)) - (def DDadapter (fn [^double a] (double 1))) - (is (= (.methodDD exerciser DDadapter) 13)) - (def ODadapter (fn [^AdapterExerciser a] (double 1))) - (is (= (.methodOD exerciser ODadapter) 14)) - (def LFadapter (fn [^long a] (float 1))) - (is (= (.methodLF exerciser LFadapter) 15)) - (def DFadapter (fn [^double a] (float 1))) - (is (= (.methodDF exerciser DFadapter) 16)) - (def OFadapter (fn [^AdapterExerciser a] (float 1))) - (is (= (.methodOF exerciser OFadapter) 17)) - (def LZadapter (fn [^long a] false)) - (is (= (.methodLZ exerciser LZadapter) 18)) - (def DZadapter (fn [^double a] false)) - (is (= (.methodDZ exerciser DZadapter) 19)) - (def OZadapter (fn [^AdapterExerciser a] false)) - (is (= (.methodOZ exerciser OZadapter) 20)) - (def LOadapter (fn [^long a] exerciser)) - (is (= (.methodLO exerciser LOadapter) 21)) - (def DOadapter (fn [^double a] exerciser)) - (is (= (.methodDO exerciser DOadapter) 22)) - (def OOadapter (fn [^AdapterExerciser a] exerciser)) - (is (= (.methodOO exerciser OOadapter) 23)) - (def LLLadapter (fn [^long a ^long b] (long 1))) - (is (= (.methodLLL exerciser LLLadapter) 24)) - (def LOLadapter (fn [^long a ^AdapterExerciser b] (long 1))) - (is (= (.methodLOL exerciser LOLadapter) 25)) - (def OLLadapter (fn [^AdapterExerciser a ^long b] (long 1))) - (is (= (.methodOLL exerciser OLLadapter) 26)) - (def DDLadapter (fn [^double a ^double b] (long 1))) - (is (= (.methodDDL exerciser DDLadapter) 27)) - (def LDLadapter (fn [^long a ^double b] (long 1))) - (is (= (.methodLDL exerciser LDLadapter) 28)) - (def DLLadapter (fn [^double a ^long b] (long 1))) - (is (= (.methodDLL exerciser DLLadapter) 29)) - (def OOLadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (long 1))) - (is (= (.methodOOL exerciser OOLadapter) 30)) - (def ODLadapter (fn [^AdapterExerciser a ^double b] (long 1))) - (is (= (.methodODL exerciser ODLadapter) 31)) - (def DOLadapter (fn [^double a ^AdapterExerciser b] (long 1))) - (is (= (.methodDOL exerciser DOLadapter) 32)) - (def LLIadapter (fn [^long a ^long b] 1)) - (is (= (.methodLLI exerciser LLIadapter) 33)) - (def LOIadapter (fn [^long a ^AdapterExerciser b] 1)) - (is (= (.methodLOI exerciser LOIadapter) 34)) - (def OLIadapter (fn [^AdapterExerciser a ^long b] 1)) - (is (= (.methodOLI exerciser OLIadapter) 35)) - (def DDIadapter (fn [^double a ^double b] 1)) - (is (= (.methodDDI exerciser DDIadapter) 36)) - (def LDIadapter (fn [^long a ^double b] 1)) - (is (= (.methodLDI exerciser LDIadapter) 37)) - (def DLIadapter (fn [^double a ^long b] 1)) - (is (= (.methodDLI exerciser DLIadapter) 38)) - (def OOIadapter (fn [^AdapterExerciser a ^AdapterExerciser b] 1)) - (is (= (.methodOOI exerciser OOIadapter) 39)) - (def ODIadapter (fn [^AdapterExerciser a ^double b] 1)) - (is (= (.methodODI exerciser ODIadapter) 40)) - (def DOIadapter (fn [^double a ^AdapterExerciser b] 1)) - (is (= (.methodDOI exerciser DOIadapter) 41)) - (def LLSadapter (fn [^long a ^long b] (short 1))) - (is (= (.methodLLS exerciser LLSadapter) 42)) - (def LOSadapter (fn [^long a ^AdapterExerciser b] (short 1))) - (is (= (.methodLOS exerciser LOSadapter) 43)) - (def OLSadapter (fn [^AdapterExerciser a ^long b] (short 1))) - (is (= (.methodOLS exerciser OLSadapter) 44)) - (def DDSadapter (fn [^double a ^double b] (short 1))) - (is (= (.methodDDS exerciser DDSadapter) 45)) - (def LDSadapter (fn [^long a ^double b] (short 1))) - (is (= (.methodLDS exerciser LDSadapter) 46)) - (def DLSadapter (fn [^double a ^long b] (short 1))) - (is (= (.methodDLS exerciser DLSadapter) 47)) - (def OOSadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (short 1))) - (is (= (.methodOOS exerciser OOSadapter) 48)) - (def ODSadapter (fn [^AdapterExerciser a ^double b] (short 1))) - (is (= (.methodODS exerciser ODSadapter) 49)) - (def DOSadapter (fn [^double a ^AdapterExerciser b] (short 1))) - (is (= (.methodDOS exerciser DOSadapter) 50)) - (def LLBadapter (fn [^long a ^long b] (byte 1))) - (is (= (.methodLLB exerciser LLBadapter) 51)) - (def LOBadapter (fn [^long a ^AdapterExerciser b] (byte 1))) - (is (= (.methodLOB exerciser LOBadapter) 52)) - (def OLBadapter (fn [^AdapterExerciser a ^long b] (byte 1))) - (is (= (.methodOLB exerciser OLBadapter) 53)) - (def DDBadapter (fn [^double a ^double b] (byte 1))) - (is (= (.methodDDB exerciser DDBadapter) 54)) - (def LDBadapter (fn [^long a ^double b] (byte 1))) - (is (= (.methodLDB exerciser LDBadapter) 55)) - (def DLBadapter (fn [^double a ^long b] (byte 1))) - (is (= (.methodDLB exerciser DLBadapter) 56)) - (def OOBadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (byte 1))) - (is (= (.methodOOB exerciser OOBadapter) 57)) - (def ODBadapter (fn [^AdapterExerciser a ^double b] (byte 1))) - (is (= (.methodODB exerciser ODBadapter) 58)) - (def DOBadapter (fn [^double a ^AdapterExerciser b] (byte 1))) - (is (= (.methodDOB exerciser DOBadapter) 59)) - (def LLDadapter (fn [^long a ^long b] (double 1))) - (is (= (.methodLLD exerciser LLDadapter) 60)) - (def LODadapter (fn [^long a ^AdapterExerciser b] (double 1))) - (is (= (.methodLOD exerciser LODadapter) 61)) - (def OLDadapter (fn [^AdapterExerciser a ^long b] (double 1))) - (is (= (.methodOLD exerciser OLDadapter) 62)) - (def DDDadapter (fn [^double a ^double b] (double 1))) - (is (= (.methodDDD exerciser DDDadapter) 63)) - (def LDDadapter (fn [^long a ^double b] (double 1))) - (is (= (.methodLDD exerciser LDDadapter) 64)) - (def DLDadapter (fn [^double a ^long b] (double 1))) - (is (= (.methodDLD exerciser DLDadapter) 65)) - (def OODadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (double 1))) - (is (= (.methodOOD exerciser OODadapter) 66)) - (def ODDadapter (fn [^AdapterExerciser a ^double b] (double 1))) - (is (= (.methodODD exerciser ODDadapter) 67)) - (def DODadapter (fn [^double a ^AdapterExerciser b] (double 1))) - (is (= (.methodDOD exerciser DODadapter) 68)) - (def LLFadapter (fn [^long a ^long b] (float 1))) - (is (= (.methodLLF exerciser LLFadapter) 69)) - (def LOFadapter (fn [^long a ^AdapterExerciser b] (float 1))) - (is (= (.methodLOF exerciser LOFadapter) 70)) - (def OLFadapter (fn [^AdapterExerciser a ^long b] (float 1))) - (is (= (.methodOLF exerciser OLFadapter) 71)) - (def DDFadapter (fn [^double a ^double b] (float 1))) - (is (= (.methodDDF exerciser DDFadapter) 72)) - (def LDFadapter (fn [^long a ^double b] (float 1))) - (is (= (.methodLDF exerciser LDFadapter) 73)) - (def DLFadapter (fn [^double a ^long b] (float 1))) - (is (= (.methodDLF exerciser DLFadapter) 74)) - (def OOFadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (float 1))) - (is (= (.methodOOF exerciser OOFadapter) 75)) - (def ODFadapter (fn [^AdapterExerciser a ^double b] (float 1))) - (is (= (.methodODF exerciser ODFadapter) 76)) - (def DOFadapter (fn [^double a ^AdapterExerciser b] (float 1))) - (is (= (.methodDOF exerciser DOFadapter) 77)) - (def LLZadapter (fn [^long a ^long b] false)) - (is (= (.methodLLZ exerciser LLZadapter) 78)) - (def LOZadapter (fn [^long a ^AdapterExerciser b] false)) - (is (= (.methodLOZ exerciser LOZadapter) 79)) - (def OLZadapter (fn [^AdapterExerciser a ^long b] false)) - (is (= (.methodOLZ exerciser OLZadapter) 80)) - (def DDZadapter (fn [^double a ^double b] false)) - (is (= (.methodDDZ exerciser DDZadapter) 81)) - (def LDZadapter (fn [^long a ^double b] false)) - (is (= (.methodLDZ exerciser LDZadapter) 82)) - (def DLZadapter (fn [^double a ^long b] false)) - (is (= (.methodDLZ exerciser DLZadapter) 83)) - (def OOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b] false)) - (is (= (.methodOOZ exerciser OOZadapter) 84)) - (def ODZadapter (fn [^AdapterExerciser a ^double b] false)) - (is (= (.methodODZ exerciser ODZadapter) 85)) - (def DOZadapter (fn [^double a ^AdapterExerciser b] false)) - (is (= (.methodDOZ exerciser DOZadapter) 86)) - (def LLOadapter (fn [^long a ^long b] exerciser)) - (is (= (.methodLLO exerciser LLOadapter) 87)) - (def LOOadapter (fn [^long a ^AdapterExerciser b] exerciser)) - (is (= (.methodLOO exerciser LOOadapter) 88)) - (def OLOadapter (fn [^AdapterExerciser a ^long b] exerciser)) - (is (= (.methodOLO exerciser OLOadapter) 89)) - (def DDOadapter (fn [^double a ^double b] exerciser)) - (is (= (.methodDDO exerciser DDOadapter) 90)) - (def LDOadapter (fn [^long a ^double b] exerciser)) - (is (= (.methodLDO exerciser LDOadapter) 91)) - (def DLOadapter (fn [^double a ^long b] exerciser)) - (is (= (.methodDLO exerciser DLOadapter) 92)) - (def OOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b] exerciser)) - (is (= (.methodOOO exerciser OOOadapter) 93)) - (def ODOadapter (fn [^AdapterExerciser a ^double b] exerciser)) - (is (= (.methodODO exerciser ODOadapter) 94)) - (def DOOadapter (fn [^double a ^AdapterExerciser b] exerciser)) - (is (= (.methodDOO exerciser DOOadapter) 95)) - (def OOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] false)) - (is (= (.methodOOOZ exerciser OOOZadapter) 96)) - (def OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser)) - (is (= (.methodOOOO exerciser OOOOadapter) 97)) - (def OOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] false)) - (is (= (.methodOOOOZ exerciser OOOOZadapter) 98)) - (def OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser)) - (is (= (.methodOOOOO exerciser OOOOOadapter) 99)) - (def OOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] false)) - (is (= (.methodOOOOOZ exerciser OOOOOZadapter) 100)) - (def OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser)) - (is (= (.methodOOOOOO exerciser OOOOOOadapter) 101)) - (def OOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] false)) - (is (= (.methodOOOOOOZ exerciser OOOOOOZadapter) 102)) - (def OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser)) - (is (= (.methodOOOOOOO exerciser OOOOOOOadapter) 103)) - (def OOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] false)) - (is (= (.methodOOOOOOOZ exerciser OOOOOOOZadapter) 104)) - (def OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser)) - (is (= (.methodOOOOOOOO exerciser OOOOOOOOadapter) 105)) - (def OOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] false)) - (is (= (.methodOOOOOOOOZ exerciser OOOOOOOOZadapter) 106)) - (def OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser)) - (is (= (.methodOOOOOOOOO exerciser OOOOOOOOOadapter) 107)) - (def OOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] false)) - (is (= (.methodOOOOOOOOOZ exerciser OOOOOOOOOZadapter) 108)) - (def OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser)) - (is (= (.methodOOOOOOOOOO exerciser OOOOOOOOOOadapter) 109)) - (def OOOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] false)) - (is (= (.methodOOOOOOOOOOZ exerciser OOOOOOOOOOZadapter) 110)) - (def OOOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] exerciser)) - (is (= (.methodOOOOOOOOOOO exerciser OOOOOOOOOOOadapter) 111))) + (deftest functional-adapters-in-def + (def exerciser (AdapterExerciser.)) + (def Ladapter (fn [] (long 1))) + (is (= (.methodL exerciser Ladapter) 0)) + (def Iadapter (fn [] 1)) + (is (= (.methodI exerciser Iadapter) 1)) + (def Sadapter (fn [] (short 1))) + (is (= (.methodS exerciser Sadapter) 2)) + (def Badapter (fn [] (byte 1))) + (is (= (.methodB exerciser Badapter) 3)) + (def Dadapter (fn [] (double 1))) + (is (= (.methodD exerciser Dadapter) 4)) + (def Fadapter (fn [] (float 1))) + (is (= (.methodF exerciser Fadapter) 5)) + (def Zadapter (fn [] false)) + (is (= (.methodZ exerciser Zadapter) 6)) + (def Oadapter (fn [] exerciser)) + (is (= (.methodO exerciser Oadapter) 7)) + (def LLadapter (fn [^long a] (long 1))) + (is (= (.methodLL exerciser LLadapter) 8)) + (def DLadapter (fn [^double a] (long 1))) + (is (= (.methodDL exerciser DLadapter) 9)) + (def OLadapter (fn [^AdapterExerciser a] (long 1))) + (is (= (.methodOL exerciser OLadapter) 10)) + (def LIadapter (fn [^long a] 1)) + (is (= (.methodLI exerciser LIadapter) 11)) + (def DIadapter (fn [^double a] 1)) + (is (= (.methodDI exerciser DIadapter) 12)) + (def OIadapter (fn [^AdapterExerciser a] 1)) + (is (= (.methodOI exerciser OIadapter) 13)) + (def LSadapter (fn [^long a] (short 1))) + (is (= (.methodLS exerciser LSadapter) 14)) + (def DSadapter (fn [^double a] (short 1))) + (is (= (.methodDS exerciser DSadapter) 15)) + (def OSadapter (fn [^AdapterExerciser a] (short 1))) + (is (= (.methodOS exerciser OSadapter) 16)) + (def LBadapter (fn [^long a] (byte 1))) + (is (= (.methodLB exerciser LBadapter) 17)) + (def DBadapter (fn [^double a] (byte 1))) + (is (= (.methodDB exerciser DBadapter) 18)) + (def OBadapter (fn [^AdapterExerciser a] (byte 1))) + (is (= (.methodOB exerciser OBadapter) 19)) + (def LDadapter (fn [^long a] (double 1))) + (is (= (.methodLD exerciser LDadapter) 20)) + (def DDadapter (fn [^double a] (double 1))) + (is (= (.methodDD exerciser DDadapter) 21)) + (def ODadapter (fn [^AdapterExerciser a] (double 1))) + (is (= (.methodOD exerciser ODadapter) 22)) + (def LFadapter (fn [^long a] (float 1))) + (is (= (.methodLF exerciser LFadapter) 23)) + (def DFadapter (fn [^double a] (float 1))) + (is (= (.methodDF exerciser DFadapter) 24)) + (def OFadapter (fn [^AdapterExerciser a] (float 1))) + (is (= (.methodOF exerciser OFadapter) 25)) + (def LZadapter (fn [^long a] false)) + (is (= (.methodLZ exerciser LZadapter) 26)) + (def DZadapter (fn [^double a] false)) + (is (= (.methodDZ exerciser DZadapter) 27)) + (def OZadapter (fn [^AdapterExerciser a] false)) + (is (= (.methodOZ exerciser OZadapter) 28)) + (def LOadapter (fn [^long a] exerciser)) + (is (= (.methodLO exerciser LOadapter) 29)) + (def DOadapter (fn [^double a] exerciser)) + (is (= (.methodDO exerciser DOadapter) 30)) + (def OOadapter (fn [^AdapterExerciser a] exerciser)) + (is (= (.methodOO exerciser OOadapter) 31)) + (def LLLadapter (fn [^long a ^long b] (long 1))) + (is (= (.methodLLL exerciser LLLadapter) 32)) + (def LOLadapter (fn [^long a ^AdapterExerciser b] (long 1))) + (is (= (.methodLOL exerciser LOLadapter) 33)) + (def OLLadapter (fn [^AdapterExerciser a ^long b] (long 1))) + (is (= (.methodOLL exerciser OLLadapter) 34)) + (def DDLadapter (fn [^double a ^double b] (long 1))) + (is (= (.methodDDL exerciser DDLadapter) 35)) + (def LDLadapter (fn [^long a ^double b] (long 1))) + (is (= (.methodLDL exerciser LDLadapter) 36)) + (def DLLadapter (fn [^double a ^long b] (long 1))) + (is (= (.methodDLL exerciser DLLadapter) 37)) + (def OOLadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (long 1))) + (is (= (.methodOOL exerciser OOLadapter) 38)) + (def ODLadapter (fn [^AdapterExerciser a ^double b] (long 1))) + (is (= (.methodODL exerciser ODLadapter) 39)) + (def DOLadapter (fn [^double a ^AdapterExerciser b] (long 1))) + (is (= (.methodDOL exerciser DOLadapter) 40)) + (def LLIadapter (fn [^long a ^long b] 1)) + (is (= (.methodLLI exerciser LLIadapter) 41)) + (def LOIadapter (fn [^long a ^AdapterExerciser b] 1)) + (is (= (.methodLOI exerciser LOIadapter) 42)) + (def OLIadapter (fn [^AdapterExerciser a ^long b] 1)) + (is (= (.methodOLI exerciser OLIadapter) 43)) + (def DDIadapter (fn [^double a ^double b] 1)) + (is (= (.methodDDI exerciser DDIadapter) 44)) + (def LDIadapter (fn [^long a ^double b] 1)) + (is (= (.methodLDI exerciser LDIadapter) 45)) + (def DLIadapter (fn [^double a ^long b] 1)) + (is (= (.methodDLI exerciser DLIadapter) 46)) + (def OOIadapter (fn [^AdapterExerciser a ^AdapterExerciser b] 1)) + (is (= (.methodOOI exerciser OOIadapter) 47)) + (def ODIadapter (fn [^AdapterExerciser a ^double b] 1)) + (is (= (.methodODI exerciser ODIadapter) 48)) + (def DOIadapter (fn [^double a ^AdapterExerciser b] 1)) + (is (= (.methodDOI exerciser DOIadapter) 49)) + (def LLSadapter (fn [^long a ^long b] (short 1))) + (is (= (.methodLLS exerciser LLSadapter) 50)) + (def LOSadapter (fn [^long a ^AdapterExerciser b] (short 1))) + (is (= (.methodLOS exerciser LOSadapter) 51)) + (def OLSadapter (fn [^AdapterExerciser a ^long b] (short 1))) + (is (= (.methodOLS exerciser OLSadapter) 52)) + (def DDSadapter (fn [^double a ^double b] (short 1))) + (is (= (.methodDDS exerciser DDSadapter) 53)) + (def LDSadapter (fn [^long a ^double b] (short 1))) + (is (= (.methodLDS exerciser LDSadapter) 54)) + (def DLSadapter (fn [^double a ^long b] (short 1))) + (is (= (.methodDLS exerciser DLSadapter) 55)) + (def OOSadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (short 1))) + (is (= (.methodOOS exerciser OOSadapter) 56)) + (def ODSadapter (fn [^AdapterExerciser a ^double b] (short 1))) + (is (= (.methodODS exerciser ODSadapter) 57)) + (def DOSadapter (fn [^double a ^AdapterExerciser b] (short 1))) + (is (= (.methodDOS exerciser DOSadapter) 58)) + (def LLBadapter (fn [^long a ^long b] (byte 1))) + (is (= (.methodLLB exerciser LLBadapter) 59)) + (def LOBadapter (fn [^long a ^AdapterExerciser b] (byte 1))) + (is (= (.methodLOB exerciser LOBadapter) 60)) + (def OLBadapter (fn [^AdapterExerciser a ^long b] (byte 1))) + (is (= (.methodOLB exerciser OLBadapter) 61)) + (def DDBadapter (fn [^double a ^double b] (byte 1))) + (is (= (.methodDDB exerciser DDBadapter) 62)) + (def LDBadapter (fn [^long a ^double b] (byte 1))) + (is (= (.methodLDB exerciser LDBadapter) 63)) + (def DLBadapter (fn [^double a ^long b] (byte 1))) + (is (= (.methodDLB exerciser DLBadapter) 64)) + (def OOBadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (byte 1))) + (is (= (.methodOOB exerciser OOBadapter) 65)) + (def ODBadapter (fn [^AdapterExerciser a ^double b] (byte 1))) + (is (= (.methodODB exerciser ODBadapter) 66)) + (def DOBadapter (fn [^double a ^AdapterExerciser b] (byte 1))) + (is (= (.methodDOB exerciser DOBadapter) 67)) + (def LLDadapter (fn [^long a ^long b] (double 1))) + (is (= (.methodLLD exerciser LLDadapter) 68)) + (def LODadapter (fn [^long a ^AdapterExerciser b] (double 1))) + (is (= (.methodLOD exerciser LODadapter) 69)) + (def OLDadapter (fn [^AdapterExerciser a ^long b] (double 1))) + (is (= (.methodOLD exerciser OLDadapter) 70)) + (def DDDadapter (fn [^double a ^double b] (double 1))) + (is (= (.methodDDD exerciser DDDadapter) 71)) + (def LDDadapter (fn [^long a ^double b] (double 1))) + (is (= (.methodLDD exerciser LDDadapter) 72)) + (def DLDadapter (fn [^double a ^long b] (double 1))) + (is (= (.methodDLD exerciser DLDadapter) 73)) + (def OODadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (double 1))) + (is (= (.methodOOD exerciser OODadapter) 74)) + (def ODDadapter (fn [^AdapterExerciser a ^double b] (double 1))) + (is (= (.methodODD exerciser ODDadapter) 75)) + (def DODadapter (fn [^double a ^AdapterExerciser b] (double 1))) + (is (= (.methodDOD exerciser DODadapter) 76)) + (def LLFadapter (fn [^long a ^long b] (float 1))) + (is (= (.methodLLF exerciser LLFadapter) 77)) + (def LOFadapter (fn [^long a ^AdapterExerciser b] (float 1))) + (is (= (.methodLOF exerciser LOFadapter) 78)) + (def OLFadapter (fn [^AdapterExerciser a ^long b] (float 1))) + (is (= (.methodOLF exerciser OLFadapter) 79)) + (def DDFadapter (fn [^double a ^double b] (float 1))) + (is (= (.methodDDF exerciser DDFadapter) 80)) + (def LDFadapter (fn [^long a ^double b] (float 1))) + (is (= (.methodLDF exerciser LDFadapter) 81)) + (def DLFadapter (fn [^double a ^long b] (float 1))) + (is (= (.methodDLF exerciser DLFadapter) 82)) + (def OOFadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (float 1))) + (is (= (.methodOOF exerciser OOFadapter) 83)) + (def ODFadapter (fn [^AdapterExerciser a ^double b] (float 1))) + (is (= (.methodODF exerciser ODFadapter) 84)) + (def DOFadapter (fn [^double a ^AdapterExerciser b] (float 1))) + (is (= (.methodDOF exerciser DOFadapter) 85)) + (def LLZadapter (fn [^long a ^long b] false)) + (is (= (.methodLLZ exerciser LLZadapter) 86)) + (def LOZadapter (fn [^long a ^AdapterExerciser b] false)) + (is (= (.methodLOZ exerciser LOZadapter) 87)) + (def OLZadapter (fn [^AdapterExerciser a ^long b] false)) + (is (= (.methodOLZ exerciser OLZadapter) 88)) + (def DDZadapter (fn [^double a ^double b] false)) + (is (= (.methodDDZ exerciser DDZadapter) 89)) + (def LDZadapter (fn [^long a ^double b] false)) + (is (= (.methodLDZ exerciser LDZadapter) 90)) + (def DLZadapter (fn [^double a ^long b] false)) + (is (= (.methodDLZ exerciser DLZadapter) 91)) + (def OOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b] false)) + (is (= (.methodOOZ exerciser OOZadapter) 92)) + (def ODZadapter (fn [^AdapterExerciser a ^double b] false)) + (is (= (.methodODZ exerciser ODZadapter) 93)) + (def DOZadapter (fn [^double a ^AdapterExerciser b] false)) + (is (= (.methodDOZ exerciser DOZadapter) 94)) + (def LLOadapter (fn [^long a ^long b] exerciser)) + (is (= (.methodLLO exerciser LLOadapter) 95)) + (def LOOadapter (fn [^long a ^AdapterExerciser b] exerciser)) + (is (= (.methodLOO exerciser LOOadapter) 96)) + (def OLOadapter (fn [^AdapterExerciser a ^long b] exerciser)) + (is (= (.methodOLO exerciser OLOadapter) 97)) + (def DDOadapter (fn [^double a ^double b] exerciser)) + (is (= (.methodDDO exerciser DDOadapter) 98)) + (def LDOadapter (fn [^long a ^double b] exerciser)) + (is (= (.methodLDO exerciser LDOadapter) 99)) + (def DLOadapter (fn [^double a ^long b] exerciser)) + (is (= (.methodDLO exerciser DLOadapter) 100)) + (def OOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b] exerciser)) + (is (= (.methodOOO exerciser OOOadapter) 101)) + (def ODOadapter (fn [^AdapterExerciser a ^double b] exerciser)) + (is (= (.methodODO exerciser ODOadapter) 102)) + (def DOOadapter (fn [^double a ^AdapterExerciser b] exerciser)) + (is (= (.methodDOO exerciser DOOadapter) 103)) + (def OOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] false)) + (is (= (.methodOOOZ exerciser OOOZadapter) 104)) + (def OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser)) + (is (= (.methodOOOO exerciser OOOOadapter) 105)) + (def OOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] false)) + (is (= (.methodOOOOZ exerciser OOOOZadapter) 106)) + (def OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser)) + (is (= (.methodOOOOO exerciser OOOOOadapter) 107)) + (def OOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] false)) + (is (= (.methodOOOOOZ exerciser OOOOOZadapter) 108)) + (def OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser)) + (is (= (.methodOOOOOO exerciser OOOOOOadapter) 109)) + (def OOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] false)) + (is (= (.methodOOOOOOZ exerciser OOOOOOZadapter) 110)) + (def OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser)) + (is (= (.methodOOOOOOO exerciser OOOOOOOadapter) 111)) + (def OOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] false)) + (is (= (.methodOOOOOOOZ exerciser OOOOOOOZadapter) 112)) + (def OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser)) + (is (= (.methodOOOOOOOO exerciser OOOOOOOOadapter) 113)) + (def OOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] false)) + (is (= (.methodOOOOOOOOZ exerciser OOOOOOOOZadapter) 114)) + (def OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser)) + (is (= (.methodOOOOOOOOO exerciser OOOOOOOOOadapter) 115)) + (def OOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] false)) + (is (= (.methodOOOOOOOOOZ exerciser OOOOOOOOOZadapter) 116)) + (def OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser)) + (is (= (.methodOOOOOOOOOO exerciser OOOOOOOOOOadapter) 117)) + (def OOOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] false)) + (is (= (.methodOOOOOOOOOOZ exerciser OOOOOOOOOOZadapter) 118)) + (def OOOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] exerciser)) + (is (= (.methodOOOOOOOOOOO exerciser OOOOOOOOOOOadapter) 119))) \ No newline at end of file diff --git a/test/java/clojure/test/AdapterExerciser.java b/test/java/clojure/test/AdapterExerciser.java index 5edfd660ad..90032bd398 100644 --- a/test/java/clojure/test/AdapterExerciser.java +++ b/test/java/clojure/test/AdapterExerciser.java @@ -1,6 +1,39 @@ + package clojure.test; public class AdapterExerciser { + @FunctionalInterface + public interface L { + public long takesRetL(); + } + @FunctionalInterface + public interface I { + public int takesRetI(); + } + @FunctionalInterface + public interface S { + public short takesRetS(); + } + @FunctionalInterface + public interface B { + public byte takesRetB(); + } + @FunctionalInterface + public interface D { + public double takesRetD(); + } + @FunctionalInterface + public interface F { + public float takesRetF(); + } + @FunctionalInterface + public interface Z { + public boolean takesRetZ(); + } + @FunctionalInterface + public interface O { + public AdapterExerciser takesRetO(); + } @FunctionalInterface public interface LL { public long takesLRetL(long a); @@ -449,115 +482,123 @@ public interface OOOOOOOOOOZ { public interface OOOOOOOOOOO { public AdapterExerciser takesOOOOOOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g, AdapterExerciser h, AdapterExerciser i, AdapterExerciser j); } - public int methodLL(LL a) { return 0; } - public int methodDL(DL a) { return 1; } - public int methodOL(OL a) { return 2; } - public int methodLI(LI a) { return 3; } - public int methodDI(DI a) { return 4; } - public int methodOI(OI a) { return 5; } - public int methodLS(LS a) { return 6; } - public int methodDS(DS a) { return 7; } - public int methodOS(OS a) { return 8; } - public int methodLB(LB a) { return 9; } - public int methodDB(DB a) { return 10; } - public int methodOB(OB a) { return 11; } - public int methodLD(LD a) { return 12; } - public int methodDD(DD a) { return 13; } - public int methodOD(OD a) { return 14; } - public int methodLF(LF a) { return 15; } - public int methodDF(DF a) { return 16; } - public int methodOF(OF a) { return 17; } - public int methodLZ(LZ a) { return 18; } - public int methodDZ(DZ a) { return 19; } - public int methodOZ(OZ a) { return 20; } - public int methodLO(LO a) { return 21; } - public int methodDO(DO a) { return 22; } - public int methodOO(OO a) { return 23; } - public int methodLLL(LLL a) { return 24; } - public int methodLOL(LOL a) { return 25; } - public int methodOLL(OLL a) { return 26; } - public int methodDDL(DDL a) { return 27; } - public int methodLDL(LDL a) { return 28; } - public int methodDLL(DLL a) { return 29; } - public int methodOOL(OOL a) { return 30; } - public int methodODL(ODL a) { return 31; } - public int methodDOL(DOL a) { return 32; } - public int methodLLI(LLI a) { return 33; } - public int methodLOI(LOI a) { return 34; } - public int methodOLI(OLI a) { return 35; } - public int methodDDI(DDI a) { return 36; } - public int methodLDI(LDI a) { return 37; } - public int methodDLI(DLI a) { return 38; } - public int methodOOI(OOI a) { return 39; } - public int methodODI(ODI a) { return 40; } - public int methodDOI(DOI a) { return 41; } - public int methodLLS(LLS a) { return 42; } - public int methodLOS(LOS a) { return 43; } - public int methodOLS(OLS a) { return 44; } - public int methodDDS(DDS a) { return 45; } - public int methodLDS(LDS a) { return 46; } - public int methodDLS(DLS a) { return 47; } - public int methodOOS(OOS a) { return 48; } - public int methodODS(ODS a) { return 49; } - public int methodDOS(DOS a) { return 50; } - public int methodLLB(LLB a) { return 51; } - public int methodLOB(LOB a) { return 52; } - public int methodOLB(OLB a) { return 53; } - public int methodDDB(DDB a) { return 54; } - public int methodLDB(LDB a) { return 55; } - public int methodDLB(DLB a) { return 56; } - public int methodOOB(OOB a) { return 57; } - public int methodODB(ODB a) { return 58; } - public int methodDOB(DOB a) { return 59; } - public int methodLLD(LLD a) { return 60; } - public int methodLOD(LOD a) { return 61; } - public int methodOLD(OLD a) { return 62; } - public int methodDDD(DDD a) { return 63; } - public int methodLDD(LDD a) { return 64; } - public int methodDLD(DLD a) { return 65; } - public int methodOOD(OOD a) { return 66; } - public int methodODD(ODD a) { return 67; } - public int methodDOD(DOD a) { return 68; } - public int methodLLF(LLF a) { return 69; } - public int methodLOF(LOF a) { return 70; } - public int methodOLF(OLF a) { return 71; } - public int methodDDF(DDF a) { return 72; } - public int methodLDF(LDF a) { return 73; } - public int methodDLF(DLF a) { return 74; } - public int methodOOF(OOF a) { return 75; } - public int methodODF(ODF a) { return 76; } - public int methodDOF(DOF a) { return 77; } - public int methodLLZ(LLZ a) { return 78; } - public int methodLOZ(LOZ a) { return 79; } - public int methodOLZ(OLZ a) { return 80; } - public int methodDDZ(DDZ a) { return 81; } - public int methodLDZ(LDZ a) { return 82; } - public int methodDLZ(DLZ a) { return 83; } - public int methodOOZ(OOZ a) { return 84; } - public int methodODZ(ODZ a) { return 85; } - public int methodDOZ(DOZ a) { return 86; } - public int methodLLO(LLO a) { return 87; } - public int methodLOO(LOO a) { return 88; } - public int methodOLO(OLO a) { return 89; } - public int methodDDO(DDO a) { return 90; } - public int methodLDO(LDO a) { return 91; } - public int methodDLO(DLO a) { return 92; } - public int methodOOO(OOO a) { return 93; } - public int methodODO(ODO a) { return 94; } - public int methodDOO(DOO a) { return 95; } - public int methodOOOZ(OOOZ a) { return 96; } - public int methodOOOO(OOOO a) { return 97; } - public int methodOOOOZ(OOOOZ a) { return 98; } - public int methodOOOOO(OOOOO a) { return 99; } - public int methodOOOOOZ(OOOOOZ a) { return 100; } - public int methodOOOOOO(OOOOOO a) { return 101; } - public int methodOOOOOOZ(OOOOOOZ a) { return 102; } - public int methodOOOOOOO(OOOOOOO a) { return 103; } - public int methodOOOOOOOZ(OOOOOOOZ a) { return 104; } - public int methodOOOOOOOO(OOOOOOOO a) { return 105; } - public int methodOOOOOOOOZ(OOOOOOOOZ a) { return 106; } - public int methodOOOOOOOOO(OOOOOOOOO a) { return 107; } - public int methodOOOOOOOOOZ(OOOOOOOOOZ a) { return 108; } - public int methodOOOOOOOOOO(OOOOOOOOOO a) { return 109; } - public int methodOOOOOOOOOOZ(OOOOOOOOOOZ a) { return 110; } - public int methodOOOOOOOOOOO(OOOOOOOOOOO a) { return 111; }} + public int methodL(L a) { return 0; } + public int methodI(I a) { return 1; } + public int methodS(S a) { return 2; } + public int methodB(B a) { return 3; } + public int methodD(D a) { return 4; } + public int methodF(F a) { return 5; } + public int methodZ(Z a) { return 6; } + public int methodO(O a) { return 7; } + public int methodLL(LL a) { return 8; } + public int methodDL(DL a) { return 9; } + public int methodOL(OL a) { return 10; } + public int methodLI(LI a) { return 11; } + public int methodDI(DI a) { return 12; } + public int methodOI(OI a) { return 13; } + public int methodLS(LS a) { return 14; } + public int methodDS(DS a) { return 15; } + public int methodOS(OS a) { return 16; } + public int methodLB(LB a) { return 17; } + public int methodDB(DB a) { return 18; } + public int methodOB(OB a) { return 19; } + public int methodLD(LD a) { return 20; } + public int methodDD(DD a) { return 21; } + public int methodOD(OD a) { return 22; } + public int methodLF(LF a) { return 23; } + public int methodDF(DF a) { return 24; } + public int methodOF(OF a) { return 25; } + public int methodLZ(LZ a) { return 26; } + public int methodDZ(DZ a) { return 27; } + public int methodOZ(OZ a) { return 28; } + public int methodLO(LO a) { return 29; } + public int methodDO(DO a) { return 30; } + public int methodOO(OO a) { return 31; } + public int methodLLL(LLL a) { return 32; } + public int methodLOL(LOL a) { return 33; } + public int methodOLL(OLL a) { return 34; } + public int methodDDL(DDL a) { return 35; } + public int methodLDL(LDL a) { return 36; } + public int methodDLL(DLL a) { return 37; } + public int methodOOL(OOL a) { return 38; } + public int methodODL(ODL a) { return 39; } + public int methodDOL(DOL a) { return 40; } + public int methodLLI(LLI a) { return 41; } + public int methodLOI(LOI a) { return 42; } + public int methodOLI(OLI a) { return 43; } + public int methodDDI(DDI a) { return 44; } + public int methodLDI(LDI a) { return 45; } + public int methodDLI(DLI a) { return 46; } + public int methodOOI(OOI a) { return 47; } + public int methodODI(ODI a) { return 48; } + public int methodDOI(DOI a) { return 49; } + public int methodLLS(LLS a) { return 50; } + public int methodLOS(LOS a) { return 51; } + public int methodOLS(OLS a) { return 52; } + public int methodDDS(DDS a) { return 53; } + public int methodLDS(LDS a) { return 54; } + public int methodDLS(DLS a) { return 55; } + public int methodOOS(OOS a) { return 56; } + public int methodODS(ODS a) { return 57; } + public int methodDOS(DOS a) { return 58; } + public int methodLLB(LLB a) { return 59; } + public int methodLOB(LOB a) { return 60; } + public int methodOLB(OLB a) { return 61; } + public int methodDDB(DDB a) { return 62; } + public int methodLDB(LDB a) { return 63; } + public int methodDLB(DLB a) { return 64; } + public int methodOOB(OOB a) { return 65; } + public int methodODB(ODB a) { return 66; } + public int methodDOB(DOB a) { return 67; } + public int methodLLD(LLD a) { return 68; } + public int methodLOD(LOD a) { return 69; } + public int methodOLD(OLD a) { return 70; } + public int methodDDD(DDD a) { return 71; } + public int methodLDD(LDD a) { return 72; } + public int methodDLD(DLD a) { return 73; } + public int methodOOD(OOD a) { return 74; } + public int methodODD(ODD a) { return 75; } + public int methodDOD(DOD a) { return 76; } + public int methodLLF(LLF a) { return 77; } + public int methodLOF(LOF a) { return 78; } + public int methodOLF(OLF a) { return 79; } + public int methodDDF(DDF a) { return 80; } + public int methodLDF(LDF a) { return 81; } + public int methodDLF(DLF a) { return 82; } + public int methodOOF(OOF a) { return 83; } + public int methodODF(ODF a) { return 84; } + public int methodDOF(DOF a) { return 85; } + public int methodLLZ(LLZ a) { return 86; } + public int methodLOZ(LOZ a) { return 87; } + public int methodOLZ(OLZ a) { return 88; } + public int methodDDZ(DDZ a) { return 89; } + public int methodLDZ(LDZ a) { return 90; } + public int methodDLZ(DLZ a) { return 91; } + public int methodOOZ(OOZ a) { return 92; } + public int methodODZ(ODZ a) { return 93; } + public int methodDOZ(DOZ a) { return 94; } + public int methodLLO(LLO a) { return 95; } + public int methodLOO(LOO a) { return 96; } + public int methodOLO(OLO a) { return 97; } + public int methodDDO(DDO a) { return 98; } + public int methodLDO(LDO a) { return 99; } + public int methodDLO(DLO a) { return 100; } + public int methodOOO(OOO a) { return 101; } + public int methodODO(ODO a) { return 102; } + public int methodDOO(DOO a) { return 103; } + public int methodOOOZ(OOOZ a) { return 104; } + public int methodOOOO(OOOO a) { return 105; } + public int methodOOOOZ(OOOOZ a) { return 106; } + public int methodOOOOO(OOOOO a) { return 107; } + public int methodOOOOOZ(OOOOOZ a) { return 108; } + public int methodOOOOOO(OOOOOO a) { return 109; } + public int methodOOOOOOZ(OOOOOOZ a) { return 110; } + public int methodOOOOOOO(OOOOOOO a) { return 111; } + public int methodOOOOOOOZ(OOOOOOOZ a) { return 112; } + public int methodOOOOOOOO(OOOOOOOO a) { return 113; } + public int methodOOOOOOOOZ(OOOOOOOOZ a) { return 114; } + public int methodOOOOOOOOO(OOOOOOOOO a) { return 115; } + public int methodOOOOOOOOOZ(OOOOOOOOOZ a) { return 116; } + public int methodOOOOOOOOOO(OOOOOOOOOO a) { return 117; } + public int methodOOOOOOOOOOZ(OOOOOOOOOOZ a) { return 118; } + public int methodOOOOOOOOOOO(OOOOOOOOOOO a) { return 119; }} \ No newline at end of file From 9048cd1d23042f9e64035cff4d9354cd1fff88f2 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 10 Jun 2024 13:52:51 -0500 Subject: [PATCH 224/285] CLJ-2858 Fix encoding of FnInvoker method for prim-returning FIs with arity > 2 --- codegen/gen_fn_adapter_tests.clj | 19 +- src/jvm/clojure/lang/Compiler.java | 6 +- .../generated_all_fi_adapters_in_let.clj | 2 +- .../generated_functional_adapters_in_def.clj | 240 +++++++++--------- ...l_adapters_in_def_requiring_reflection.clj | 240 +++++++++--------- test/clojure/test_clojure/java_interop.clj | 14 +- test/java/clojure/test/AdapterExerciser.java | 240 +++++++++--------- 7 files changed, 391 insertions(+), 370 deletions(-) diff --git a/codegen/gen_fn_adapter_tests.clj b/codegen/gen_fn_adapter_tests.clj index 5bff1746e1..7ebf39b1f4 100644 --- a/codegen/gen_fn_adapter_tests.clj +++ b/codegen/gen_fn_adapter_tests.clj @@ -126,24 +126,24 @@ public class AdapterExerciser {") (defn gen-test-functional-adapters-in-def [] (let [sb (StringBuilder. ^String (def-test-header "generated-functional-adapters-in-def")) adapter-signatures (gen-sigs)] - (doseq [[idx sig] (map-indexed (fn [idx itm] [idx itm]) adapter-signatures)] + (doseq [sig adapter-signatures] (let [{:keys [fn-vars fn-body]} (format-parts sig)] (.append sb "\n") (.append sb (format " (def %sadapter (fn [%s] %s))" sig fn-vars fn-body)) (.append sb "\n") - (.append sb (format " (is (= (.method%s ^AdapterExerciser exerciser %sadapter) %s))" sig sig idx)))) + (.append sb (format " (is (= (.method%s ^AdapterExerciser exerciser %sadapter) %s))" sig sig (str "\"" sig "\""))))) (.append sb ")") (spit "generated_functional_adapters_in_def.clj" (.toString sb)))) (defn gen-test-functional-adapters-in-def-requiring-reflection [] (let [sb (StringBuilder. ^String (def-test-header "generated-functional-adapters-in-def-requiring-reflection")) adapter-signatures (gen-sigs)] - (doseq [[idx sig] (map-indexed (fn [idx itm] [idx itm]) adapter-signatures)] + (doseq [sig adapter-signatures] (let [{:keys [fn-vars fn-body]} (format-parts sig)] (.append sb "\n") (.append sb (format " (def %sadapter (fn [%s] %s))" sig fn-vars fn-body)) (.append sb "\n") - (.append sb (format " (is (= (.method%s exerciser %sadapter) %s))" sig sig idx)))) + (.append sb (format " (is (= (.method%s exerciser %sadapter) %s))" sig sig (str "\"" sig "\""))))) (.append sb ")") (spit "generated_functional_adapters_in_def_requiring_reflection.clj" (.toString sb)))) @@ -157,13 +157,20 @@ public class AdapterExerciser {") (.append sb (format " public interface %s {\n" sig)) (.append sb (format " public %s takes%sRet%s(%s);\n" return-type (str/join "" input-types) return-type-initial java-vars)) (.append sb " }"))) - (doseq [[idx sig] (map-indexed (fn [idx itm] [idx itm]) adapter-signatures)] + (doseq [sig adapter-signatures] (.append sb "\n") - (.append sb (format " public int method%s(%s a) { return %s; }" sig sig idx))) + (.append sb (format " public String method%s(%s a) { return %s; }" sig sig (str "\"" sig "\"")))) (.append sb "}") (spit "AdapterExerciser.java" (.toString sb)))) +(defn gen-all [] + (gen-test-all-fi-adapters-in-let) + (gen-test-functional-adapters-in-def) + (gen-test-functional-adapters-in-def-requiring-reflection) + (gen-adapter-exerciser-class)) + (comment + (gen-all) (gen-test-all-fi-adapters-in-let) (gen-test-functional-adapters-in-def) (gen-test-functional-adapters-in-def-requiring-reflection) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index e65a589894..d711d67b03 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1672,7 +1672,11 @@ static boolean maybeEmitFIAdapter(ObjExpr objx, GeneratorAdapter gen, Expr expr, invokerParams[i + 1] = paramCount <= 2 ? toInvokerParamType(targetMethod.getParameterTypes()[i]) : Object.class; invokeMethodBuilder.append(FnInvokers.encodeInvokerType(invokerParams[i + 1])); } - char invokerReturnCode = FnInvokers.encodeInvokerType(targetMethod.getReturnType()); + // FnInvokers has prim returns for <= 2 params, only boolean or Object for higher + Class retType = targetMethod.getReturnType(); + char invokerReturnCode = FnInvokers.encodeInvokerType( + paramCount <= 2 ? retType : + (Boolean.TYPE.equals(retType) ? retType : Object.class)); invokeMethodBuilder.append(invokerReturnCode); String invokerMethodName = invokeMethodBuilder.toString(); diff --git a/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj b/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj index d276dcc328..a84144cee7 100644 --- a/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj +++ b/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj @@ -2,7 +2,7 @@ (ns clojure.test-clojure.generated-all-fi-adapters-in-let (:use clojure.test) (:require [clojure.string :as str]) - (:import (clojure.test AdapterExerciser AdapterExerciser$L + (:import (clojure.test AdapterExerciser AdapterExerciser$L AdapterExerciser$I AdapterExerciser$S AdapterExerciser$B diff --git a/test/clojure/test_clojure/generated_functional_adapters_in_def.clj b/test/clojure/test_clojure/generated_functional_adapters_in_def.clj index a101ce581f..12e9c4e043 100644 --- a/test/clojure/test_clojure/generated_functional_adapters_in_def.clj +++ b/test/clojure/test_clojure/generated_functional_adapters_in_def.clj @@ -7,242 +7,242 @@ (deftest functional-adapters-in-def (def exerciser (AdapterExerciser.)) (def Ladapter (fn [] (long 1))) - (is (= (.methodL ^AdapterExerciser exerciser Ladapter) 0)) + (is (= (.methodL ^AdapterExerciser exerciser Ladapter) "L")) (def Iadapter (fn [] 1)) - (is (= (.methodI ^AdapterExerciser exerciser Iadapter) 1)) + (is (= (.methodI ^AdapterExerciser exerciser Iadapter) "I")) (def Sadapter (fn [] (short 1))) - (is (= (.methodS ^AdapterExerciser exerciser Sadapter) 2)) + (is (= (.methodS ^AdapterExerciser exerciser Sadapter) "S")) (def Badapter (fn [] (byte 1))) - (is (= (.methodB ^AdapterExerciser exerciser Badapter) 3)) + (is (= (.methodB ^AdapterExerciser exerciser Badapter) "B")) (def Dadapter (fn [] (double 1))) - (is (= (.methodD ^AdapterExerciser exerciser Dadapter) 4)) + (is (= (.methodD ^AdapterExerciser exerciser Dadapter) "D")) (def Fadapter (fn [] (float 1))) - (is (= (.methodF ^AdapterExerciser exerciser Fadapter) 5)) + (is (= (.methodF ^AdapterExerciser exerciser Fadapter) "F")) (def Zadapter (fn [] false)) - (is (= (.methodZ ^AdapterExerciser exerciser Zadapter) 6)) + (is (= (.methodZ ^AdapterExerciser exerciser Zadapter) "Z")) (def Oadapter (fn [] exerciser)) - (is (= (.methodO ^AdapterExerciser exerciser Oadapter) 7)) + (is (= (.methodO ^AdapterExerciser exerciser Oadapter) "O")) (def LLadapter (fn [^long a] (long 1))) - (is (= (.methodLL ^AdapterExerciser exerciser LLadapter) 8)) + (is (= (.methodLL ^AdapterExerciser exerciser LLadapter) "LL")) (def DLadapter (fn [^double a] (long 1))) - (is (= (.methodDL ^AdapterExerciser exerciser DLadapter) 9)) + (is (= (.methodDL ^AdapterExerciser exerciser DLadapter) "DL")) (def OLadapter (fn [^AdapterExerciser a] (long 1))) - (is (= (.methodOL ^AdapterExerciser exerciser OLadapter) 10)) + (is (= (.methodOL ^AdapterExerciser exerciser OLadapter) "OL")) (def LIadapter (fn [^long a] 1)) - (is (= (.methodLI ^AdapterExerciser exerciser LIadapter) 11)) + (is (= (.methodLI ^AdapterExerciser exerciser LIadapter) "LI")) (def DIadapter (fn [^double a] 1)) - (is (= (.methodDI ^AdapterExerciser exerciser DIadapter) 12)) + (is (= (.methodDI ^AdapterExerciser exerciser DIadapter) "DI")) (def OIadapter (fn [^AdapterExerciser a] 1)) - (is (= (.methodOI ^AdapterExerciser exerciser OIadapter) 13)) + (is (= (.methodOI ^AdapterExerciser exerciser OIadapter) "OI")) (def LSadapter (fn [^long a] (short 1))) - (is (= (.methodLS ^AdapterExerciser exerciser LSadapter) 14)) + (is (= (.methodLS ^AdapterExerciser exerciser LSadapter) "LS")) (def DSadapter (fn [^double a] (short 1))) - (is (= (.methodDS ^AdapterExerciser exerciser DSadapter) 15)) + (is (= (.methodDS ^AdapterExerciser exerciser DSadapter) "DS")) (def OSadapter (fn [^AdapterExerciser a] (short 1))) - (is (= (.methodOS ^AdapterExerciser exerciser OSadapter) 16)) + (is (= (.methodOS ^AdapterExerciser exerciser OSadapter) "OS")) (def LBadapter (fn [^long a] (byte 1))) - (is (= (.methodLB ^AdapterExerciser exerciser LBadapter) 17)) + (is (= (.methodLB ^AdapterExerciser exerciser LBadapter) "LB")) (def DBadapter (fn [^double a] (byte 1))) - (is (= (.methodDB ^AdapterExerciser exerciser DBadapter) 18)) + (is (= (.methodDB ^AdapterExerciser exerciser DBadapter) "DB")) (def OBadapter (fn [^AdapterExerciser a] (byte 1))) - (is (= (.methodOB ^AdapterExerciser exerciser OBadapter) 19)) + (is (= (.methodOB ^AdapterExerciser exerciser OBadapter) "OB")) (def LDadapter (fn [^long a] (double 1))) - (is (= (.methodLD ^AdapterExerciser exerciser LDadapter) 20)) + (is (= (.methodLD ^AdapterExerciser exerciser LDadapter) "LD")) (def DDadapter (fn [^double a] (double 1))) - (is (= (.methodDD ^AdapterExerciser exerciser DDadapter) 21)) + (is (= (.methodDD ^AdapterExerciser exerciser DDadapter) "DD")) (def ODadapter (fn [^AdapterExerciser a] (double 1))) - (is (= (.methodOD ^AdapterExerciser exerciser ODadapter) 22)) + (is (= (.methodOD ^AdapterExerciser exerciser ODadapter) "OD")) (def LFadapter (fn [^long a] (float 1))) - (is (= (.methodLF ^AdapterExerciser exerciser LFadapter) 23)) + (is (= (.methodLF ^AdapterExerciser exerciser LFadapter) "LF")) (def DFadapter (fn [^double a] (float 1))) - (is (= (.methodDF ^AdapterExerciser exerciser DFadapter) 24)) + (is (= (.methodDF ^AdapterExerciser exerciser DFadapter) "DF")) (def OFadapter (fn [^AdapterExerciser a] (float 1))) - (is (= (.methodOF ^AdapterExerciser exerciser OFadapter) 25)) + (is (= (.methodOF ^AdapterExerciser exerciser OFadapter) "OF")) (def LZadapter (fn [^long a] false)) - (is (= (.methodLZ ^AdapterExerciser exerciser LZadapter) 26)) + (is (= (.methodLZ ^AdapterExerciser exerciser LZadapter) "LZ")) (def DZadapter (fn [^double a] false)) - (is (= (.methodDZ ^AdapterExerciser exerciser DZadapter) 27)) + (is (= (.methodDZ ^AdapterExerciser exerciser DZadapter) "DZ")) (def OZadapter (fn [^AdapterExerciser a] false)) - (is (= (.methodOZ ^AdapterExerciser exerciser OZadapter) 28)) + (is (= (.methodOZ ^AdapterExerciser exerciser OZadapter) "OZ")) (def LOadapter (fn [^long a] exerciser)) - (is (= (.methodLO ^AdapterExerciser exerciser LOadapter) 29)) + (is (= (.methodLO ^AdapterExerciser exerciser LOadapter) "LO")) (def DOadapter (fn [^double a] exerciser)) - (is (= (.methodDO ^AdapterExerciser exerciser DOadapter) 30)) + (is (= (.methodDO ^AdapterExerciser exerciser DOadapter) "DO")) (def OOadapter (fn [^AdapterExerciser a] exerciser)) - (is (= (.methodOO ^AdapterExerciser exerciser OOadapter) 31)) + (is (= (.methodOO ^AdapterExerciser exerciser OOadapter) "OO")) (def LLLadapter (fn [^long a ^long b] (long 1))) - (is (= (.methodLLL ^AdapterExerciser exerciser LLLadapter) 32)) + (is (= (.methodLLL ^AdapterExerciser exerciser LLLadapter) "LLL")) (def LOLadapter (fn [^long a ^AdapterExerciser b] (long 1))) - (is (= (.methodLOL ^AdapterExerciser exerciser LOLadapter) 33)) + (is (= (.methodLOL ^AdapterExerciser exerciser LOLadapter) "LOL")) (def OLLadapter (fn [^AdapterExerciser a ^long b] (long 1))) - (is (= (.methodOLL ^AdapterExerciser exerciser OLLadapter) 34)) + (is (= (.methodOLL ^AdapterExerciser exerciser OLLadapter) "OLL")) (def DDLadapter (fn [^double a ^double b] (long 1))) - (is (= (.methodDDL ^AdapterExerciser exerciser DDLadapter) 35)) + (is (= (.methodDDL ^AdapterExerciser exerciser DDLadapter) "DDL")) (def LDLadapter (fn [^long a ^double b] (long 1))) - (is (= (.methodLDL ^AdapterExerciser exerciser LDLadapter) 36)) + (is (= (.methodLDL ^AdapterExerciser exerciser LDLadapter) "LDL")) (def DLLadapter (fn [^double a ^long b] (long 1))) - (is (= (.methodDLL ^AdapterExerciser exerciser DLLadapter) 37)) + (is (= (.methodDLL ^AdapterExerciser exerciser DLLadapter) "DLL")) (def OOLadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (long 1))) - (is (= (.methodOOL ^AdapterExerciser exerciser OOLadapter) 38)) + (is (= (.methodOOL ^AdapterExerciser exerciser OOLadapter) "OOL")) (def ODLadapter (fn [^AdapterExerciser a ^double b] (long 1))) - (is (= (.methodODL ^AdapterExerciser exerciser ODLadapter) 39)) + (is (= (.methodODL ^AdapterExerciser exerciser ODLadapter) "ODL")) (def DOLadapter (fn [^double a ^AdapterExerciser b] (long 1))) - (is (= (.methodDOL ^AdapterExerciser exerciser DOLadapter) 40)) + (is (= (.methodDOL ^AdapterExerciser exerciser DOLadapter) "DOL")) (def LLIadapter (fn [^long a ^long b] 1)) - (is (= (.methodLLI ^AdapterExerciser exerciser LLIadapter) 41)) + (is (= (.methodLLI ^AdapterExerciser exerciser LLIadapter) "LLI")) (def LOIadapter (fn [^long a ^AdapterExerciser b] 1)) - (is (= (.methodLOI ^AdapterExerciser exerciser LOIadapter) 42)) + (is (= (.methodLOI ^AdapterExerciser exerciser LOIadapter) "LOI")) (def OLIadapter (fn [^AdapterExerciser a ^long b] 1)) - (is (= (.methodOLI ^AdapterExerciser exerciser OLIadapter) 43)) + (is (= (.methodOLI ^AdapterExerciser exerciser OLIadapter) "OLI")) (def DDIadapter (fn [^double a ^double b] 1)) - (is (= (.methodDDI ^AdapterExerciser exerciser DDIadapter) 44)) + (is (= (.methodDDI ^AdapterExerciser exerciser DDIadapter) "DDI")) (def LDIadapter (fn [^long a ^double b] 1)) - (is (= (.methodLDI ^AdapterExerciser exerciser LDIadapter) 45)) + (is (= (.methodLDI ^AdapterExerciser exerciser LDIadapter) "LDI")) (def DLIadapter (fn [^double a ^long b] 1)) - (is (= (.methodDLI ^AdapterExerciser exerciser DLIadapter) 46)) + (is (= (.methodDLI ^AdapterExerciser exerciser DLIadapter) "DLI")) (def OOIadapter (fn [^AdapterExerciser a ^AdapterExerciser b] 1)) - (is (= (.methodOOI ^AdapterExerciser exerciser OOIadapter) 47)) + (is (= (.methodOOI ^AdapterExerciser exerciser OOIadapter) "OOI")) (def ODIadapter (fn [^AdapterExerciser a ^double b] 1)) - (is (= (.methodODI ^AdapterExerciser exerciser ODIadapter) 48)) + (is (= (.methodODI ^AdapterExerciser exerciser ODIadapter) "ODI")) (def DOIadapter (fn [^double a ^AdapterExerciser b] 1)) - (is (= (.methodDOI ^AdapterExerciser exerciser DOIadapter) 49)) + (is (= (.methodDOI ^AdapterExerciser exerciser DOIadapter) "DOI")) (def LLSadapter (fn [^long a ^long b] (short 1))) - (is (= (.methodLLS ^AdapterExerciser exerciser LLSadapter) 50)) + (is (= (.methodLLS ^AdapterExerciser exerciser LLSadapter) "LLS")) (def LOSadapter (fn [^long a ^AdapterExerciser b] (short 1))) - (is (= (.methodLOS ^AdapterExerciser exerciser LOSadapter) 51)) + (is (= (.methodLOS ^AdapterExerciser exerciser LOSadapter) "LOS")) (def OLSadapter (fn [^AdapterExerciser a ^long b] (short 1))) - (is (= (.methodOLS ^AdapterExerciser exerciser OLSadapter) 52)) + (is (= (.methodOLS ^AdapterExerciser exerciser OLSadapter) "OLS")) (def DDSadapter (fn [^double a ^double b] (short 1))) - (is (= (.methodDDS ^AdapterExerciser exerciser DDSadapter) 53)) + (is (= (.methodDDS ^AdapterExerciser exerciser DDSadapter) "DDS")) (def LDSadapter (fn [^long a ^double b] (short 1))) - (is (= (.methodLDS ^AdapterExerciser exerciser LDSadapter) 54)) + (is (= (.methodLDS ^AdapterExerciser exerciser LDSadapter) "LDS")) (def DLSadapter (fn [^double a ^long b] (short 1))) - (is (= (.methodDLS ^AdapterExerciser exerciser DLSadapter) 55)) + (is (= (.methodDLS ^AdapterExerciser exerciser DLSadapter) "DLS")) (def OOSadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (short 1))) - (is (= (.methodOOS ^AdapterExerciser exerciser OOSadapter) 56)) + (is (= (.methodOOS ^AdapterExerciser exerciser OOSadapter) "OOS")) (def ODSadapter (fn [^AdapterExerciser a ^double b] (short 1))) - (is (= (.methodODS ^AdapterExerciser exerciser ODSadapter) 57)) + (is (= (.methodODS ^AdapterExerciser exerciser ODSadapter) "ODS")) (def DOSadapter (fn [^double a ^AdapterExerciser b] (short 1))) - (is (= (.methodDOS ^AdapterExerciser exerciser DOSadapter) 58)) + (is (= (.methodDOS ^AdapterExerciser exerciser DOSadapter) "DOS")) (def LLBadapter (fn [^long a ^long b] (byte 1))) - (is (= (.methodLLB ^AdapterExerciser exerciser LLBadapter) 59)) + (is (= (.methodLLB ^AdapterExerciser exerciser LLBadapter) "LLB")) (def LOBadapter (fn [^long a ^AdapterExerciser b] (byte 1))) - (is (= (.methodLOB ^AdapterExerciser exerciser LOBadapter) 60)) + (is (= (.methodLOB ^AdapterExerciser exerciser LOBadapter) "LOB")) (def OLBadapter (fn [^AdapterExerciser a ^long b] (byte 1))) - (is (= (.methodOLB ^AdapterExerciser exerciser OLBadapter) 61)) + (is (= (.methodOLB ^AdapterExerciser exerciser OLBadapter) "OLB")) (def DDBadapter (fn [^double a ^double b] (byte 1))) - (is (= (.methodDDB ^AdapterExerciser exerciser DDBadapter) 62)) + (is (= (.methodDDB ^AdapterExerciser exerciser DDBadapter) "DDB")) (def LDBadapter (fn [^long a ^double b] (byte 1))) - (is (= (.methodLDB ^AdapterExerciser exerciser LDBadapter) 63)) + (is (= (.methodLDB ^AdapterExerciser exerciser LDBadapter) "LDB")) (def DLBadapter (fn [^double a ^long b] (byte 1))) - (is (= (.methodDLB ^AdapterExerciser exerciser DLBadapter) 64)) + (is (= (.methodDLB ^AdapterExerciser exerciser DLBadapter) "DLB")) (def OOBadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (byte 1))) - (is (= (.methodOOB ^AdapterExerciser exerciser OOBadapter) 65)) + (is (= (.methodOOB ^AdapterExerciser exerciser OOBadapter) "OOB")) (def ODBadapter (fn [^AdapterExerciser a ^double b] (byte 1))) - (is (= (.methodODB ^AdapterExerciser exerciser ODBadapter) 66)) + (is (= (.methodODB ^AdapterExerciser exerciser ODBadapter) "ODB")) (def DOBadapter (fn [^double a ^AdapterExerciser b] (byte 1))) - (is (= (.methodDOB ^AdapterExerciser exerciser DOBadapter) 67)) + (is (= (.methodDOB ^AdapterExerciser exerciser DOBadapter) "DOB")) (def LLDadapter (fn [^long a ^long b] (double 1))) - (is (= (.methodLLD ^AdapterExerciser exerciser LLDadapter) 68)) + (is (= (.methodLLD ^AdapterExerciser exerciser LLDadapter) "LLD")) (def LODadapter (fn [^long a ^AdapterExerciser b] (double 1))) - (is (= (.methodLOD ^AdapterExerciser exerciser LODadapter) 69)) + (is (= (.methodLOD ^AdapterExerciser exerciser LODadapter) "LOD")) (def OLDadapter (fn [^AdapterExerciser a ^long b] (double 1))) - (is (= (.methodOLD ^AdapterExerciser exerciser OLDadapter) 70)) + (is (= (.methodOLD ^AdapterExerciser exerciser OLDadapter) "OLD")) (def DDDadapter (fn [^double a ^double b] (double 1))) - (is (= (.methodDDD ^AdapterExerciser exerciser DDDadapter) 71)) + (is (= (.methodDDD ^AdapterExerciser exerciser DDDadapter) "DDD")) (def LDDadapter (fn [^long a ^double b] (double 1))) - (is (= (.methodLDD ^AdapterExerciser exerciser LDDadapter) 72)) + (is (= (.methodLDD ^AdapterExerciser exerciser LDDadapter) "LDD")) (def DLDadapter (fn [^double a ^long b] (double 1))) - (is (= (.methodDLD ^AdapterExerciser exerciser DLDadapter) 73)) + (is (= (.methodDLD ^AdapterExerciser exerciser DLDadapter) "DLD")) (def OODadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (double 1))) - (is (= (.methodOOD ^AdapterExerciser exerciser OODadapter) 74)) + (is (= (.methodOOD ^AdapterExerciser exerciser OODadapter) "OOD")) (def ODDadapter (fn [^AdapterExerciser a ^double b] (double 1))) - (is (= (.methodODD ^AdapterExerciser exerciser ODDadapter) 75)) + (is (= (.methodODD ^AdapterExerciser exerciser ODDadapter) "ODD")) (def DODadapter (fn [^double a ^AdapterExerciser b] (double 1))) - (is (= (.methodDOD ^AdapterExerciser exerciser DODadapter) 76)) + (is (= (.methodDOD ^AdapterExerciser exerciser DODadapter) "DOD")) (def LLFadapter (fn [^long a ^long b] (float 1))) - (is (= (.methodLLF ^AdapterExerciser exerciser LLFadapter) 77)) + (is (= (.methodLLF ^AdapterExerciser exerciser LLFadapter) "LLF")) (def LOFadapter (fn [^long a ^AdapterExerciser b] (float 1))) - (is (= (.methodLOF ^AdapterExerciser exerciser LOFadapter) 78)) + (is (= (.methodLOF ^AdapterExerciser exerciser LOFadapter) "LOF")) (def OLFadapter (fn [^AdapterExerciser a ^long b] (float 1))) - (is (= (.methodOLF ^AdapterExerciser exerciser OLFadapter) 79)) + (is (= (.methodOLF ^AdapterExerciser exerciser OLFadapter) "OLF")) (def DDFadapter (fn [^double a ^double b] (float 1))) - (is (= (.methodDDF ^AdapterExerciser exerciser DDFadapter) 80)) + (is (= (.methodDDF ^AdapterExerciser exerciser DDFadapter) "DDF")) (def LDFadapter (fn [^long a ^double b] (float 1))) - (is (= (.methodLDF ^AdapterExerciser exerciser LDFadapter) 81)) + (is (= (.methodLDF ^AdapterExerciser exerciser LDFadapter) "LDF")) (def DLFadapter (fn [^double a ^long b] (float 1))) - (is (= (.methodDLF ^AdapterExerciser exerciser DLFadapter) 82)) + (is (= (.methodDLF ^AdapterExerciser exerciser DLFadapter) "DLF")) (def OOFadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (float 1))) - (is (= (.methodOOF ^AdapterExerciser exerciser OOFadapter) 83)) + (is (= (.methodOOF ^AdapterExerciser exerciser OOFadapter) "OOF")) (def ODFadapter (fn [^AdapterExerciser a ^double b] (float 1))) - (is (= (.methodODF ^AdapterExerciser exerciser ODFadapter) 84)) + (is (= (.methodODF ^AdapterExerciser exerciser ODFadapter) "ODF")) (def DOFadapter (fn [^double a ^AdapterExerciser b] (float 1))) - (is (= (.methodDOF ^AdapterExerciser exerciser DOFadapter) 85)) + (is (= (.methodDOF ^AdapterExerciser exerciser DOFadapter) "DOF")) (def LLZadapter (fn [^long a ^long b] false)) - (is (= (.methodLLZ ^AdapterExerciser exerciser LLZadapter) 86)) + (is (= (.methodLLZ ^AdapterExerciser exerciser LLZadapter) "LLZ")) (def LOZadapter (fn [^long a ^AdapterExerciser b] false)) - (is (= (.methodLOZ ^AdapterExerciser exerciser LOZadapter) 87)) + (is (= (.methodLOZ ^AdapterExerciser exerciser LOZadapter) "LOZ")) (def OLZadapter (fn [^AdapterExerciser a ^long b] false)) - (is (= (.methodOLZ ^AdapterExerciser exerciser OLZadapter) 88)) + (is (= (.methodOLZ ^AdapterExerciser exerciser OLZadapter) "OLZ")) (def DDZadapter (fn [^double a ^double b] false)) - (is (= (.methodDDZ ^AdapterExerciser exerciser DDZadapter) 89)) + (is (= (.methodDDZ ^AdapterExerciser exerciser DDZadapter) "DDZ")) (def LDZadapter (fn [^long a ^double b] false)) - (is (= (.methodLDZ ^AdapterExerciser exerciser LDZadapter) 90)) + (is (= (.methodLDZ ^AdapterExerciser exerciser LDZadapter) "LDZ")) (def DLZadapter (fn [^double a ^long b] false)) - (is (= (.methodDLZ ^AdapterExerciser exerciser DLZadapter) 91)) + (is (= (.methodDLZ ^AdapterExerciser exerciser DLZadapter) "DLZ")) (def OOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b] false)) - (is (= (.methodOOZ ^AdapterExerciser exerciser OOZadapter) 92)) + (is (= (.methodOOZ ^AdapterExerciser exerciser OOZadapter) "OOZ")) (def ODZadapter (fn [^AdapterExerciser a ^double b] false)) - (is (= (.methodODZ ^AdapterExerciser exerciser ODZadapter) 93)) + (is (= (.methodODZ ^AdapterExerciser exerciser ODZadapter) "ODZ")) (def DOZadapter (fn [^double a ^AdapterExerciser b] false)) - (is (= (.methodDOZ ^AdapterExerciser exerciser DOZadapter) 94)) + (is (= (.methodDOZ ^AdapterExerciser exerciser DOZadapter) "DOZ")) (def LLOadapter (fn [^long a ^long b] exerciser)) - (is (= (.methodLLO ^AdapterExerciser exerciser LLOadapter) 95)) + (is (= (.methodLLO ^AdapterExerciser exerciser LLOadapter) "LLO")) (def LOOadapter (fn [^long a ^AdapterExerciser b] exerciser)) - (is (= (.methodLOO ^AdapterExerciser exerciser LOOadapter) 96)) + (is (= (.methodLOO ^AdapterExerciser exerciser LOOadapter) "LOO")) (def OLOadapter (fn [^AdapterExerciser a ^long b] exerciser)) - (is (= (.methodOLO ^AdapterExerciser exerciser OLOadapter) 97)) + (is (= (.methodOLO ^AdapterExerciser exerciser OLOadapter) "OLO")) (def DDOadapter (fn [^double a ^double b] exerciser)) - (is (= (.methodDDO ^AdapterExerciser exerciser DDOadapter) 98)) + (is (= (.methodDDO ^AdapterExerciser exerciser DDOadapter) "DDO")) (def LDOadapter (fn [^long a ^double b] exerciser)) - (is (= (.methodLDO ^AdapterExerciser exerciser LDOadapter) 99)) + (is (= (.methodLDO ^AdapterExerciser exerciser LDOadapter) "LDO")) (def DLOadapter (fn [^double a ^long b] exerciser)) - (is (= (.methodDLO ^AdapterExerciser exerciser DLOadapter) 100)) + (is (= (.methodDLO ^AdapterExerciser exerciser DLOadapter) "DLO")) (def OOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b] exerciser)) - (is (= (.methodOOO ^AdapterExerciser exerciser OOOadapter) 101)) + (is (= (.methodOOO ^AdapterExerciser exerciser OOOadapter) "OOO")) (def ODOadapter (fn [^AdapterExerciser a ^double b] exerciser)) - (is (= (.methodODO ^AdapterExerciser exerciser ODOadapter) 102)) + (is (= (.methodODO ^AdapterExerciser exerciser ODOadapter) "ODO")) (def DOOadapter (fn [^double a ^AdapterExerciser b] exerciser)) - (is (= (.methodDOO ^AdapterExerciser exerciser DOOadapter) 103)) + (is (= (.methodDOO ^AdapterExerciser exerciser DOOadapter) "DOO")) (def OOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] false)) - (is (= (.methodOOOZ ^AdapterExerciser exerciser OOOZadapter) 104)) + (is (= (.methodOOOZ ^AdapterExerciser exerciser OOOZadapter) "OOOZ")) (def OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser)) - (is (= (.methodOOOO ^AdapterExerciser exerciser OOOOadapter) 105)) + (is (= (.methodOOOO ^AdapterExerciser exerciser OOOOadapter) "OOOO")) (def OOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] false)) - (is (= (.methodOOOOZ ^AdapterExerciser exerciser OOOOZadapter) 106)) + (is (= (.methodOOOOZ ^AdapterExerciser exerciser OOOOZadapter) "OOOOZ")) (def OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser)) - (is (= (.methodOOOOO ^AdapterExerciser exerciser OOOOOadapter) 107)) + (is (= (.methodOOOOO ^AdapterExerciser exerciser OOOOOadapter) "OOOOO")) (def OOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] false)) - (is (= (.methodOOOOOZ ^AdapterExerciser exerciser OOOOOZadapter) 108)) + (is (= (.methodOOOOOZ ^AdapterExerciser exerciser OOOOOZadapter) "OOOOOZ")) (def OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser)) - (is (= (.methodOOOOOO ^AdapterExerciser exerciser OOOOOOadapter) 109)) + (is (= (.methodOOOOOO ^AdapterExerciser exerciser OOOOOOadapter) "OOOOOO")) (def OOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] false)) - (is (= (.methodOOOOOOZ ^AdapterExerciser exerciser OOOOOOZadapter) 110)) + (is (= (.methodOOOOOOZ ^AdapterExerciser exerciser OOOOOOZadapter) "OOOOOOZ")) (def OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser)) - (is (= (.methodOOOOOOO ^AdapterExerciser exerciser OOOOOOOadapter) 111)) + (is (= (.methodOOOOOOO ^AdapterExerciser exerciser OOOOOOOadapter) "OOOOOOO")) (def OOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] false)) - (is (= (.methodOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOZadapter) 112)) + (is (= (.methodOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOZadapter) "OOOOOOOZ")) (def OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser)) - (is (= (.methodOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOadapter) 113)) + (is (= (.methodOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOadapter) "OOOOOOOO")) (def OOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] false)) - (is (= (.methodOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOZadapter) 114)) + (is (= (.methodOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOZadapter) "OOOOOOOOZ")) (def OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser)) - (is (= (.methodOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOadapter) 115)) + (is (= (.methodOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOadapter) "OOOOOOOOO")) (def OOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] false)) - (is (= (.methodOOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOOZadapter) 116)) + (is (= (.methodOOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOOZadapter) "OOOOOOOOOZ")) (def OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser)) - (is (= (.methodOOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOOadapter) 117)) + (is (= (.methodOOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOOadapter) "OOOOOOOOOO")) (def OOOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] false)) - (is (= (.methodOOOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOOOZadapter) 118)) + (is (= (.methodOOOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOOOZadapter) "OOOOOOOOOOZ")) (def OOOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] exerciser)) - (is (= (.methodOOOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOOOadapter) 119))) \ No newline at end of file + (is (= (.methodOOOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOOOadapter) "OOOOOOOOOOO"))) \ No newline at end of file diff --git a/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj b/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj index f3072ea022..5ddf78f542 100644 --- a/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj +++ b/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj @@ -7,242 +7,242 @@ (deftest functional-adapters-in-def (def exerciser (AdapterExerciser.)) (def Ladapter (fn [] (long 1))) - (is (= (.methodL exerciser Ladapter) 0)) + (is (= (.methodL exerciser Ladapter) "L")) (def Iadapter (fn [] 1)) - (is (= (.methodI exerciser Iadapter) 1)) + (is (= (.methodI exerciser Iadapter) "I")) (def Sadapter (fn [] (short 1))) - (is (= (.methodS exerciser Sadapter) 2)) + (is (= (.methodS exerciser Sadapter) "S")) (def Badapter (fn [] (byte 1))) - (is (= (.methodB exerciser Badapter) 3)) + (is (= (.methodB exerciser Badapter) "B")) (def Dadapter (fn [] (double 1))) - (is (= (.methodD exerciser Dadapter) 4)) + (is (= (.methodD exerciser Dadapter) "D")) (def Fadapter (fn [] (float 1))) - (is (= (.methodF exerciser Fadapter) 5)) + (is (= (.methodF exerciser Fadapter) "F")) (def Zadapter (fn [] false)) - (is (= (.methodZ exerciser Zadapter) 6)) + (is (= (.methodZ exerciser Zadapter) "Z")) (def Oadapter (fn [] exerciser)) - (is (= (.methodO exerciser Oadapter) 7)) + (is (= (.methodO exerciser Oadapter) "O")) (def LLadapter (fn [^long a] (long 1))) - (is (= (.methodLL exerciser LLadapter) 8)) + (is (= (.methodLL exerciser LLadapter) "LL")) (def DLadapter (fn [^double a] (long 1))) - (is (= (.methodDL exerciser DLadapter) 9)) + (is (= (.methodDL exerciser DLadapter) "DL")) (def OLadapter (fn [^AdapterExerciser a] (long 1))) - (is (= (.methodOL exerciser OLadapter) 10)) + (is (= (.methodOL exerciser OLadapter) "OL")) (def LIadapter (fn [^long a] 1)) - (is (= (.methodLI exerciser LIadapter) 11)) + (is (= (.methodLI exerciser LIadapter) "LI")) (def DIadapter (fn [^double a] 1)) - (is (= (.methodDI exerciser DIadapter) 12)) + (is (= (.methodDI exerciser DIadapter) "DI")) (def OIadapter (fn [^AdapterExerciser a] 1)) - (is (= (.methodOI exerciser OIadapter) 13)) + (is (= (.methodOI exerciser OIadapter) "OI")) (def LSadapter (fn [^long a] (short 1))) - (is (= (.methodLS exerciser LSadapter) 14)) + (is (= (.methodLS exerciser LSadapter) "LS")) (def DSadapter (fn [^double a] (short 1))) - (is (= (.methodDS exerciser DSadapter) 15)) + (is (= (.methodDS exerciser DSadapter) "DS")) (def OSadapter (fn [^AdapterExerciser a] (short 1))) - (is (= (.methodOS exerciser OSadapter) 16)) + (is (= (.methodOS exerciser OSadapter) "OS")) (def LBadapter (fn [^long a] (byte 1))) - (is (= (.methodLB exerciser LBadapter) 17)) + (is (= (.methodLB exerciser LBadapter) "LB")) (def DBadapter (fn [^double a] (byte 1))) - (is (= (.methodDB exerciser DBadapter) 18)) + (is (= (.methodDB exerciser DBadapter) "DB")) (def OBadapter (fn [^AdapterExerciser a] (byte 1))) - (is (= (.methodOB exerciser OBadapter) 19)) + (is (= (.methodOB exerciser OBadapter) "OB")) (def LDadapter (fn [^long a] (double 1))) - (is (= (.methodLD exerciser LDadapter) 20)) + (is (= (.methodLD exerciser LDadapter) "LD")) (def DDadapter (fn [^double a] (double 1))) - (is (= (.methodDD exerciser DDadapter) 21)) + (is (= (.methodDD exerciser DDadapter) "DD")) (def ODadapter (fn [^AdapterExerciser a] (double 1))) - (is (= (.methodOD exerciser ODadapter) 22)) + (is (= (.methodOD exerciser ODadapter) "OD")) (def LFadapter (fn [^long a] (float 1))) - (is (= (.methodLF exerciser LFadapter) 23)) + (is (= (.methodLF exerciser LFadapter) "LF")) (def DFadapter (fn [^double a] (float 1))) - (is (= (.methodDF exerciser DFadapter) 24)) + (is (= (.methodDF exerciser DFadapter) "DF")) (def OFadapter (fn [^AdapterExerciser a] (float 1))) - (is (= (.methodOF exerciser OFadapter) 25)) + (is (= (.methodOF exerciser OFadapter) "OF")) (def LZadapter (fn [^long a] false)) - (is (= (.methodLZ exerciser LZadapter) 26)) + (is (= (.methodLZ exerciser LZadapter) "LZ")) (def DZadapter (fn [^double a] false)) - (is (= (.methodDZ exerciser DZadapter) 27)) + (is (= (.methodDZ exerciser DZadapter) "DZ")) (def OZadapter (fn [^AdapterExerciser a] false)) - (is (= (.methodOZ exerciser OZadapter) 28)) + (is (= (.methodOZ exerciser OZadapter) "OZ")) (def LOadapter (fn [^long a] exerciser)) - (is (= (.methodLO exerciser LOadapter) 29)) + (is (= (.methodLO exerciser LOadapter) "LO")) (def DOadapter (fn [^double a] exerciser)) - (is (= (.methodDO exerciser DOadapter) 30)) + (is (= (.methodDO exerciser DOadapter) "DO")) (def OOadapter (fn [^AdapterExerciser a] exerciser)) - (is (= (.methodOO exerciser OOadapter) 31)) + (is (= (.methodOO exerciser OOadapter) "OO")) (def LLLadapter (fn [^long a ^long b] (long 1))) - (is (= (.methodLLL exerciser LLLadapter) 32)) + (is (= (.methodLLL exerciser LLLadapter) "LLL")) (def LOLadapter (fn [^long a ^AdapterExerciser b] (long 1))) - (is (= (.methodLOL exerciser LOLadapter) 33)) + (is (= (.methodLOL exerciser LOLadapter) "LOL")) (def OLLadapter (fn [^AdapterExerciser a ^long b] (long 1))) - (is (= (.methodOLL exerciser OLLadapter) 34)) + (is (= (.methodOLL exerciser OLLadapter) "OLL")) (def DDLadapter (fn [^double a ^double b] (long 1))) - (is (= (.methodDDL exerciser DDLadapter) 35)) + (is (= (.methodDDL exerciser DDLadapter) "DDL")) (def LDLadapter (fn [^long a ^double b] (long 1))) - (is (= (.methodLDL exerciser LDLadapter) 36)) + (is (= (.methodLDL exerciser LDLadapter) "LDL")) (def DLLadapter (fn [^double a ^long b] (long 1))) - (is (= (.methodDLL exerciser DLLadapter) 37)) + (is (= (.methodDLL exerciser DLLadapter) "DLL")) (def OOLadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (long 1))) - (is (= (.methodOOL exerciser OOLadapter) 38)) + (is (= (.methodOOL exerciser OOLadapter) "OOL")) (def ODLadapter (fn [^AdapterExerciser a ^double b] (long 1))) - (is (= (.methodODL exerciser ODLadapter) 39)) + (is (= (.methodODL exerciser ODLadapter) "ODL")) (def DOLadapter (fn [^double a ^AdapterExerciser b] (long 1))) - (is (= (.methodDOL exerciser DOLadapter) 40)) + (is (= (.methodDOL exerciser DOLadapter) "DOL")) (def LLIadapter (fn [^long a ^long b] 1)) - (is (= (.methodLLI exerciser LLIadapter) 41)) + (is (= (.methodLLI exerciser LLIadapter) "LLI")) (def LOIadapter (fn [^long a ^AdapterExerciser b] 1)) - (is (= (.methodLOI exerciser LOIadapter) 42)) + (is (= (.methodLOI exerciser LOIadapter) "LOI")) (def OLIadapter (fn [^AdapterExerciser a ^long b] 1)) - (is (= (.methodOLI exerciser OLIadapter) 43)) + (is (= (.methodOLI exerciser OLIadapter) "OLI")) (def DDIadapter (fn [^double a ^double b] 1)) - (is (= (.methodDDI exerciser DDIadapter) 44)) + (is (= (.methodDDI exerciser DDIadapter) "DDI")) (def LDIadapter (fn [^long a ^double b] 1)) - (is (= (.methodLDI exerciser LDIadapter) 45)) + (is (= (.methodLDI exerciser LDIadapter) "LDI")) (def DLIadapter (fn [^double a ^long b] 1)) - (is (= (.methodDLI exerciser DLIadapter) 46)) + (is (= (.methodDLI exerciser DLIadapter) "DLI")) (def OOIadapter (fn [^AdapterExerciser a ^AdapterExerciser b] 1)) - (is (= (.methodOOI exerciser OOIadapter) 47)) + (is (= (.methodOOI exerciser OOIadapter) "OOI")) (def ODIadapter (fn [^AdapterExerciser a ^double b] 1)) - (is (= (.methodODI exerciser ODIadapter) 48)) + (is (= (.methodODI exerciser ODIadapter) "ODI")) (def DOIadapter (fn [^double a ^AdapterExerciser b] 1)) - (is (= (.methodDOI exerciser DOIadapter) 49)) + (is (= (.methodDOI exerciser DOIadapter) "DOI")) (def LLSadapter (fn [^long a ^long b] (short 1))) - (is (= (.methodLLS exerciser LLSadapter) 50)) + (is (= (.methodLLS exerciser LLSadapter) "LLS")) (def LOSadapter (fn [^long a ^AdapterExerciser b] (short 1))) - (is (= (.methodLOS exerciser LOSadapter) 51)) + (is (= (.methodLOS exerciser LOSadapter) "LOS")) (def OLSadapter (fn [^AdapterExerciser a ^long b] (short 1))) - (is (= (.methodOLS exerciser OLSadapter) 52)) + (is (= (.methodOLS exerciser OLSadapter) "OLS")) (def DDSadapter (fn [^double a ^double b] (short 1))) - (is (= (.methodDDS exerciser DDSadapter) 53)) + (is (= (.methodDDS exerciser DDSadapter) "DDS")) (def LDSadapter (fn [^long a ^double b] (short 1))) - (is (= (.methodLDS exerciser LDSadapter) 54)) + (is (= (.methodLDS exerciser LDSadapter) "LDS")) (def DLSadapter (fn [^double a ^long b] (short 1))) - (is (= (.methodDLS exerciser DLSadapter) 55)) + (is (= (.methodDLS exerciser DLSadapter) "DLS")) (def OOSadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (short 1))) - (is (= (.methodOOS exerciser OOSadapter) 56)) + (is (= (.methodOOS exerciser OOSadapter) "OOS")) (def ODSadapter (fn [^AdapterExerciser a ^double b] (short 1))) - (is (= (.methodODS exerciser ODSadapter) 57)) + (is (= (.methodODS exerciser ODSadapter) "ODS")) (def DOSadapter (fn [^double a ^AdapterExerciser b] (short 1))) - (is (= (.methodDOS exerciser DOSadapter) 58)) + (is (= (.methodDOS exerciser DOSadapter) "DOS")) (def LLBadapter (fn [^long a ^long b] (byte 1))) - (is (= (.methodLLB exerciser LLBadapter) 59)) + (is (= (.methodLLB exerciser LLBadapter) "LLB")) (def LOBadapter (fn [^long a ^AdapterExerciser b] (byte 1))) - (is (= (.methodLOB exerciser LOBadapter) 60)) + (is (= (.methodLOB exerciser LOBadapter) "LOB")) (def OLBadapter (fn [^AdapterExerciser a ^long b] (byte 1))) - (is (= (.methodOLB exerciser OLBadapter) 61)) + (is (= (.methodOLB exerciser OLBadapter) "OLB")) (def DDBadapter (fn [^double a ^double b] (byte 1))) - (is (= (.methodDDB exerciser DDBadapter) 62)) + (is (= (.methodDDB exerciser DDBadapter) "DDB")) (def LDBadapter (fn [^long a ^double b] (byte 1))) - (is (= (.methodLDB exerciser LDBadapter) 63)) + (is (= (.methodLDB exerciser LDBadapter) "LDB")) (def DLBadapter (fn [^double a ^long b] (byte 1))) - (is (= (.methodDLB exerciser DLBadapter) 64)) + (is (= (.methodDLB exerciser DLBadapter) "DLB")) (def OOBadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (byte 1))) - (is (= (.methodOOB exerciser OOBadapter) 65)) + (is (= (.methodOOB exerciser OOBadapter) "OOB")) (def ODBadapter (fn [^AdapterExerciser a ^double b] (byte 1))) - (is (= (.methodODB exerciser ODBadapter) 66)) + (is (= (.methodODB exerciser ODBadapter) "ODB")) (def DOBadapter (fn [^double a ^AdapterExerciser b] (byte 1))) - (is (= (.methodDOB exerciser DOBadapter) 67)) + (is (= (.methodDOB exerciser DOBadapter) "DOB")) (def LLDadapter (fn [^long a ^long b] (double 1))) - (is (= (.methodLLD exerciser LLDadapter) 68)) + (is (= (.methodLLD exerciser LLDadapter) "LLD")) (def LODadapter (fn [^long a ^AdapterExerciser b] (double 1))) - (is (= (.methodLOD exerciser LODadapter) 69)) + (is (= (.methodLOD exerciser LODadapter) "LOD")) (def OLDadapter (fn [^AdapterExerciser a ^long b] (double 1))) - (is (= (.methodOLD exerciser OLDadapter) 70)) + (is (= (.methodOLD exerciser OLDadapter) "OLD")) (def DDDadapter (fn [^double a ^double b] (double 1))) - (is (= (.methodDDD exerciser DDDadapter) 71)) + (is (= (.methodDDD exerciser DDDadapter) "DDD")) (def LDDadapter (fn [^long a ^double b] (double 1))) - (is (= (.methodLDD exerciser LDDadapter) 72)) + (is (= (.methodLDD exerciser LDDadapter) "LDD")) (def DLDadapter (fn [^double a ^long b] (double 1))) - (is (= (.methodDLD exerciser DLDadapter) 73)) + (is (= (.methodDLD exerciser DLDadapter) "DLD")) (def OODadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (double 1))) - (is (= (.methodOOD exerciser OODadapter) 74)) + (is (= (.methodOOD exerciser OODadapter) "OOD")) (def ODDadapter (fn [^AdapterExerciser a ^double b] (double 1))) - (is (= (.methodODD exerciser ODDadapter) 75)) + (is (= (.methodODD exerciser ODDadapter) "ODD")) (def DODadapter (fn [^double a ^AdapterExerciser b] (double 1))) - (is (= (.methodDOD exerciser DODadapter) 76)) + (is (= (.methodDOD exerciser DODadapter) "DOD")) (def LLFadapter (fn [^long a ^long b] (float 1))) - (is (= (.methodLLF exerciser LLFadapter) 77)) + (is (= (.methodLLF exerciser LLFadapter) "LLF")) (def LOFadapter (fn [^long a ^AdapterExerciser b] (float 1))) - (is (= (.methodLOF exerciser LOFadapter) 78)) + (is (= (.methodLOF exerciser LOFadapter) "LOF")) (def OLFadapter (fn [^AdapterExerciser a ^long b] (float 1))) - (is (= (.methodOLF exerciser OLFadapter) 79)) + (is (= (.methodOLF exerciser OLFadapter) "OLF")) (def DDFadapter (fn [^double a ^double b] (float 1))) - (is (= (.methodDDF exerciser DDFadapter) 80)) + (is (= (.methodDDF exerciser DDFadapter) "DDF")) (def LDFadapter (fn [^long a ^double b] (float 1))) - (is (= (.methodLDF exerciser LDFadapter) 81)) + (is (= (.methodLDF exerciser LDFadapter) "LDF")) (def DLFadapter (fn [^double a ^long b] (float 1))) - (is (= (.methodDLF exerciser DLFadapter) 82)) + (is (= (.methodDLF exerciser DLFadapter) "DLF")) (def OOFadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (float 1))) - (is (= (.methodOOF exerciser OOFadapter) 83)) + (is (= (.methodOOF exerciser OOFadapter) "OOF")) (def ODFadapter (fn [^AdapterExerciser a ^double b] (float 1))) - (is (= (.methodODF exerciser ODFadapter) 84)) + (is (= (.methodODF exerciser ODFadapter) "ODF")) (def DOFadapter (fn [^double a ^AdapterExerciser b] (float 1))) - (is (= (.methodDOF exerciser DOFadapter) 85)) + (is (= (.methodDOF exerciser DOFadapter) "DOF")) (def LLZadapter (fn [^long a ^long b] false)) - (is (= (.methodLLZ exerciser LLZadapter) 86)) + (is (= (.methodLLZ exerciser LLZadapter) "LLZ")) (def LOZadapter (fn [^long a ^AdapterExerciser b] false)) - (is (= (.methodLOZ exerciser LOZadapter) 87)) + (is (= (.methodLOZ exerciser LOZadapter) "LOZ")) (def OLZadapter (fn [^AdapterExerciser a ^long b] false)) - (is (= (.methodOLZ exerciser OLZadapter) 88)) + (is (= (.methodOLZ exerciser OLZadapter) "OLZ")) (def DDZadapter (fn [^double a ^double b] false)) - (is (= (.methodDDZ exerciser DDZadapter) 89)) + (is (= (.methodDDZ exerciser DDZadapter) "DDZ")) (def LDZadapter (fn [^long a ^double b] false)) - (is (= (.methodLDZ exerciser LDZadapter) 90)) + (is (= (.methodLDZ exerciser LDZadapter) "LDZ")) (def DLZadapter (fn [^double a ^long b] false)) - (is (= (.methodDLZ exerciser DLZadapter) 91)) + (is (= (.methodDLZ exerciser DLZadapter) "DLZ")) (def OOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b] false)) - (is (= (.methodOOZ exerciser OOZadapter) 92)) + (is (= (.methodOOZ exerciser OOZadapter) "OOZ")) (def ODZadapter (fn [^AdapterExerciser a ^double b] false)) - (is (= (.methodODZ exerciser ODZadapter) 93)) + (is (= (.methodODZ exerciser ODZadapter) "ODZ")) (def DOZadapter (fn [^double a ^AdapterExerciser b] false)) - (is (= (.methodDOZ exerciser DOZadapter) 94)) + (is (= (.methodDOZ exerciser DOZadapter) "DOZ")) (def LLOadapter (fn [^long a ^long b] exerciser)) - (is (= (.methodLLO exerciser LLOadapter) 95)) + (is (= (.methodLLO exerciser LLOadapter) "LLO")) (def LOOadapter (fn [^long a ^AdapterExerciser b] exerciser)) - (is (= (.methodLOO exerciser LOOadapter) 96)) + (is (= (.methodLOO exerciser LOOadapter) "LOO")) (def OLOadapter (fn [^AdapterExerciser a ^long b] exerciser)) - (is (= (.methodOLO exerciser OLOadapter) 97)) + (is (= (.methodOLO exerciser OLOadapter) "OLO")) (def DDOadapter (fn [^double a ^double b] exerciser)) - (is (= (.methodDDO exerciser DDOadapter) 98)) + (is (= (.methodDDO exerciser DDOadapter) "DDO")) (def LDOadapter (fn [^long a ^double b] exerciser)) - (is (= (.methodLDO exerciser LDOadapter) 99)) + (is (= (.methodLDO exerciser LDOadapter) "LDO")) (def DLOadapter (fn [^double a ^long b] exerciser)) - (is (= (.methodDLO exerciser DLOadapter) 100)) + (is (= (.methodDLO exerciser DLOadapter) "DLO")) (def OOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b] exerciser)) - (is (= (.methodOOO exerciser OOOadapter) 101)) + (is (= (.methodOOO exerciser OOOadapter) "OOO")) (def ODOadapter (fn [^AdapterExerciser a ^double b] exerciser)) - (is (= (.methodODO exerciser ODOadapter) 102)) + (is (= (.methodODO exerciser ODOadapter) "ODO")) (def DOOadapter (fn [^double a ^AdapterExerciser b] exerciser)) - (is (= (.methodDOO exerciser DOOadapter) 103)) + (is (= (.methodDOO exerciser DOOadapter) "DOO")) (def OOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] false)) - (is (= (.methodOOOZ exerciser OOOZadapter) 104)) + (is (= (.methodOOOZ exerciser OOOZadapter) "OOOZ")) (def OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser)) - (is (= (.methodOOOO exerciser OOOOadapter) 105)) + (is (= (.methodOOOO exerciser OOOOadapter) "OOOO")) (def OOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] false)) - (is (= (.methodOOOOZ exerciser OOOOZadapter) 106)) + (is (= (.methodOOOOZ exerciser OOOOZadapter) "OOOOZ")) (def OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser)) - (is (= (.methodOOOOO exerciser OOOOOadapter) 107)) + (is (= (.methodOOOOO exerciser OOOOOadapter) "OOOOO")) (def OOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] false)) - (is (= (.methodOOOOOZ exerciser OOOOOZadapter) 108)) + (is (= (.methodOOOOOZ exerciser OOOOOZadapter) "OOOOOZ")) (def OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser)) - (is (= (.methodOOOOOO exerciser OOOOOOadapter) 109)) + (is (= (.methodOOOOOO exerciser OOOOOOadapter) "OOOOOO")) (def OOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] false)) - (is (= (.methodOOOOOOZ exerciser OOOOOOZadapter) 110)) + (is (= (.methodOOOOOOZ exerciser OOOOOOZadapter) "OOOOOOZ")) (def OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser)) - (is (= (.methodOOOOOOO exerciser OOOOOOOadapter) 111)) + (is (= (.methodOOOOOOO exerciser OOOOOOOadapter) "OOOOOOO")) (def OOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] false)) - (is (= (.methodOOOOOOOZ exerciser OOOOOOOZadapter) 112)) + (is (= (.methodOOOOOOOZ exerciser OOOOOOOZadapter) "OOOOOOOZ")) (def OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser)) - (is (= (.methodOOOOOOOO exerciser OOOOOOOOadapter) 113)) + (is (= (.methodOOOOOOOO exerciser OOOOOOOOadapter) "OOOOOOOO")) (def OOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] false)) - (is (= (.methodOOOOOOOOZ exerciser OOOOOOOOZadapter) 114)) + (is (= (.methodOOOOOOOOZ exerciser OOOOOOOOZadapter) "OOOOOOOOZ")) (def OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser)) - (is (= (.methodOOOOOOOOO exerciser OOOOOOOOOadapter) 115)) + (is (= (.methodOOOOOOOOO exerciser OOOOOOOOOadapter) "OOOOOOOOO")) (def OOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] false)) - (is (= (.methodOOOOOOOOOZ exerciser OOOOOOOOOZadapter) 116)) + (is (= (.methodOOOOOOOOOZ exerciser OOOOOOOOOZadapter) "OOOOOOOOOZ")) (def OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser)) - (is (= (.methodOOOOOOOOOO exerciser OOOOOOOOOOadapter) 117)) + (is (= (.methodOOOOOOOOOO exerciser OOOOOOOOOOadapter) "OOOOOOOOOO")) (def OOOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] false)) - (is (= (.methodOOOOOOOOOOZ exerciser OOOOOOOOOOZadapter) 118)) + (is (= (.methodOOOOOOOOOOZ exerciser OOOOOOOOOOZadapter) "OOOOOOOOOOZ")) (def OOOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] exerciser)) - (is (= (.methodOOOOOOOOOOO exerciser OOOOOOOOOOOadapter) 119))) \ No newline at end of file + (is (= (.methodOOOOOOOOOOO exerciser OOOOOOOOOOOadapter) "OOOOOOOOOOO"))) \ No newline at end of file diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj index b27bc440a0..888a0d7efc 100644 --- a/test/clojure/test_clojure/java_interop.clj +++ b/test/clojure/test_clojure/java_interop.clj @@ -22,7 +22,7 @@ (java.io File FileFilter FilenameFilter) (java.util UUID) (java.util.concurrent.atomic AtomicLong AtomicInteger) - (clojure.test FIConstructor FIStatic FunctionalTester))) + (clojure.test FIConstructor FIStatic FunctionalTester AdapterExerciser))) ; http://clojure.org/java_interop ; http://clojure.org/compilation @@ -828,7 +828,7 @@ (is (= 1 (.call r (reify clojure.test_clojure.java_interop.FIWontWork (invoke [_ a b c d e f g h i j k] k))))))) (definterface ^{java.lang.FunctionalInterface true} FIPrims - (invoke [^long a ^long b ^long c ^long d])) + (^long invoke [^long a ^long b ^long c ^long d])) (definterface ReceivesFIPrims (call [^clojure.test_clojure.java_interop.FIPrims fi])) @@ -838,6 +838,16 @@ (call [_ fi] (.invoke fi 1 2 3 4)))] (is (= 4 (.call r (fn [^long a ^long b ^long c ^long d] d)))))) +(deftest test-invoke-fiprim-rets + (let [^clojure.test_clojure.java_interop.FIPrims f (fn [a b c d] a)] + (is (instance? clojure.test_clojure.java_interop.FIPrims f)) + (is (= 1 (.invoke f 1 2 3 4)))) + + (is (= "LLL" (AdapterExerciser/.methodLLL (AdapterExerciser.) (fn ^long [^long a ^long b])))) + (is (= "OOOO" (AdapterExerciser/.methodOOOO (AdapterExerciser.) (fn ^long [^long a ^long b ^long c])))) + (is (= "OOOZ" (AdapterExerciser/.methodOOOZ (AdapterExerciser.) (fn [^long a ^long b ^long c])))) + ) + (deftest test-null-reify (is (= "null" ((fn [x] (FIStatic/allowsNullFI x)) nil)))) diff --git a/test/java/clojure/test/AdapterExerciser.java b/test/java/clojure/test/AdapterExerciser.java index 90032bd398..e6d7e5e424 100644 --- a/test/java/clojure/test/AdapterExerciser.java +++ b/test/java/clojure/test/AdapterExerciser.java @@ -482,123 +482,123 @@ public interface OOOOOOOOOOZ { public interface OOOOOOOOOOO { public AdapterExerciser takesOOOOOOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g, AdapterExerciser h, AdapterExerciser i, AdapterExerciser j); } - public int methodL(L a) { return 0; } - public int methodI(I a) { return 1; } - public int methodS(S a) { return 2; } - public int methodB(B a) { return 3; } - public int methodD(D a) { return 4; } - public int methodF(F a) { return 5; } - public int methodZ(Z a) { return 6; } - public int methodO(O a) { return 7; } - public int methodLL(LL a) { return 8; } - public int methodDL(DL a) { return 9; } - public int methodOL(OL a) { return 10; } - public int methodLI(LI a) { return 11; } - public int methodDI(DI a) { return 12; } - public int methodOI(OI a) { return 13; } - public int methodLS(LS a) { return 14; } - public int methodDS(DS a) { return 15; } - public int methodOS(OS a) { return 16; } - public int methodLB(LB a) { return 17; } - public int methodDB(DB a) { return 18; } - public int methodOB(OB a) { return 19; } - public int methodLD(LD a) { return 20; } - public int methodDD(DD a) { return 21; } - public int methodOD(OD a) { return 22; } - public int methodLF(LF a) { return 23; } - public int methodDF(DF a) { return 24; } - public int methodOF(OF a) { return 25; } - public int methodLZ(LZ a) { return 26; } - public int methodDZ(DZ a) { return 27; } - public int methodOZ(OZ a) { return 28; } - public int methodLO(LO a) { return 29; } - public int methodDO(DO a) { return 30; } - public int methodOO(OO a) { return 31; } - public int methodLLL(LLL a) { return 32; } - public int methodLOL(LOL a) { return 33; } - public int methodOLL(OLL a) { return 34; } - public int methodDDL(DDL a) { return 35; } - public int methodLDL(LDL a) { return 36; } - public int methodDLL(DLL a) { return 37; } - public int methodOOL(OOL a) { return 38; } - public int methodODL(ODL a) { return 39; } - public int methodDOL(DOL a) { return 40; } - public int methodLLI(LLI a) { return 41; } - public int methodLOI(LOI a) { return 42; } - public int methodOLI(OLI a) { return 43; } - public int methodDDI(DDI a) { return 44; } - public int methodLDI(LDI a) { return 45; } - public int methodDLI(DLI a) { return 46; } - public int methodOOI(OOI a) { return 47; } - public int methodODI(ODI a) { return 48; } - public int methodDOI(DOI a) { return 49; } - public int methodLLS(LLS a) { return 50; } - public int methodLOS(LOS a) { return 51; } - public int methodOLS(OLS a) { return 52; } - public int methodDDS(DDS a) { return 53; } - public int methodLDS(LDS a) { return 54; } - public int methodDLS(DLS a) { return 55; } - public int methodOOS(OOS a) { return 56; } - public int methodODS(ODS a) { return 57; } - public int methodDOS(DOS a) { return 58; } - public int methodLLB(LLB a) { return 59; } - public int methodLOB(LOB a) { return 60; } - public int methodOLB(OLB a) { return 61; } - public int methodDDB(DDB a) { return 62; } - public int methodLDB(LDB a) { return 63; } - public int methodDLB(DLB a) { return 64; } - public int methodOOB(OOB a) { return 65; } - public int methodODB(ODB a) { return 66; } - public int methodDOB(DOB a) { return 67; } - public int methodLLD(LLD a) { return 68; } - public int methodLOD(LOD a) { return 69; } - public int methodOLD(OLD a) { return 70; } - public int methodDDD(DDD a) { return 71; } - public int methodLDD(LDD a) { return 72; } - public int methodDLD(DLD a) { return 73; } - public int methodOOD(OOD a) { return 74; } - public int methodODD(ODD a) { return 75; } - public int methodDOD(DOD a) { return 76; } - public int methodLLF(LLF a) { return 77; } - public int methodLOF(LOF a) { return 78; } - public int methodOLF(OLF a) { return 79; } - public int methodDDF(DDF a) { return 80; } - public int methodLDF(LDF a) { return 81; } - public int methodDLF(DLF a) { return 82; } - public int methodOOF(OOF a) { return 83; } - public int methodODF(ODF a) { return 84; } - public int methodDOF(DOF a) { return 85; } - public int methodLLZ(LLZ a) { return 86; } - public int methodLOZ(LOZ a) { return 87; } - public int methodOLZ(OLZ a) { return 88; } - public int methodDDZ(DDZ a) { return 89; } - public int methodLDZ(LDZ a) { return 90; } - public int methodDLZ(DLZ a) { return 91; } - public int methodOOZ(OOZ a) { return 92; } - public int methodODZ(ODZ a) { return 93; } - public int methodDOZ(DOZ a) { return 94; } - public int methodLLO(LLO a) { return 95; } - public int methodLOO(LOO a) { return 96; } - public int methodOLO(OLO a) { return 97; } - public int methodDDO(DDO a) { return 98; } - public int methodLDO(LDO a) { return 99; } - public int methodDLO(DLO a) { return 100; } - public int methodOOO(OOO a) { return 101; } - public int methodODO(ODO a) { return 102; } - public int methodDOO(DOO a) { return 103; } - public int methodOOOZ(OOOZ a) { return 104; } - public int methodOOOO(OOOO a) { return 105; } - public int methodOOOOZ(OOOOZ a) { return 106; } - public int methodOOOOO(OOOOO a) { return 107; } - public int methodOOOOOZ(OOOOOZ a) { return 108; } - public int methodOOOOOO(OOOOOO a) { return 109; } - public int methodOOOOOOZ(OOOOOOZ a) { return 110; } - public int methodOOOOOOO(OOOOOOO a) { return 111; } - public int methodOOOOOOOZ(OOOOOOOZ a) { return 112; } - public int methodOOOOOOOO(OOOOOOOO a) { return 113; } - public int methodOOOOOOOOZ(OOOOOOOOZ a) { return 114; } - public int methodOOOOOOOOO(OOOOOOOOO a) { return 115; } - public int methodOOOOOOOOOZ(OOOOOOOOOZ a) { return 116; } - public int methodOOOOOOOOOO(OOOOOOOOOO a) { return 117; } - public int methodOOOOOOOOOOZ(OOOOOOOOOOZ a) { return 118; } - public int methodOOOOOOOOOOO(OOOOOOOOOOO a) { return 119; }} \ No newline at end of file + public String methodL(L a) { return "L"; } + public String methodI(I a) { return "I"; } + public String methodS(S a) { return "S"; } + public String methodB(B a) { return "B"; } + public String methodD(D a) { return "D"; } + public String methodF(F a) { return "F"; } + public String methodZ(Z a) { return "Z"; } + public String methodO(O a) { return "O"; } + public String methodLL(LL a) { return "LL"; } + public String methodDL(DL a) { return "DL"; } + public String methodOL(OL a) { return "OL"; } + public String methodLI(LI a) { return "LI"; } + public String methodDI(DI a) { return "DI"; } + public String methodOI(OI a) { return "OI"; } + public String methodLS(LS a) { return "LS"; } + public String methodDS(DS a) { return "DS"; } + public String methodOS(OS a) { return "OS"; } + public String methodLB(LB a) { return "LB"; } + public String methodDB(DB a) { return "DB"; } + public String methodOB(OB a) { return "OB"; } + public String methodLD(LD a) { return "LD"; } + public String methodDD(DD a) { return "DD"; } + public String methodOD(OD a) { return "OD"; } + public String methodLF(LF a) { return "LF"; } + public String methodDF(DF a) { return "DF"; } + public String methodOF(OF a) { return "OF"; } + public String methodLZ(LZ a) { return "LZ"; } + public String methodDZ(DZ a) { return "DZ"; } + public String methodOZ(OZ a) { return "OZ"; } + public String methodLO(LO a) { return "LO"; } + public String methodDO(DO a) { return "DO"; } + public String methodOO(OO a) { return "OO"; } + public String methodLLL(LLL a) { return "LLL"; } + public String methodLOL(LOL a) { return "LOL"; } + public String methodOLL(OLL a) { return "OLL"; } + public String methodDDL(DDL a) { return "DDL"; } + public String methodLDL(LDL a) { return "LDL"; } + public String methodDLL(DLL a) { return "DLL"; } + public String methodOOL(OOL a) { return "OOL"; } + public String methodODL(ODL a) { return "ODL"; } + public String methodDOL(DOL a) { return "DOL"; } + public String methodLLI(LLI a) { return "LLI"; } + public String methodLOI(LOI a) { return "LOI"; } + public String methodOLI(OLI a) { return "OLI"; } + public String methodDDI(DDI a) { return "DDI"; } + public String methodLDI(LDI a) { return "LDI"; } + public String methodDLI(DLI a) { return "DLI"; } + public String methodOOI(OOI a) { return "OOI"; } + public String methodODI(ODI a) { return "ODI"; } + public String methodDOI(DOI a) { return "DOI"; } + public String methodLLS(LLS a) { return "LLS"; } + public String methodLOS(LOS a) { return "LOS"; } + public String methodOLS(OLS a) { return "OLS"; } + public String methodDDS(DDS a) { return "DDS"; } + public String methodLDS(LDS a) { return "LDS"; } + public String methodDLS(DLS a) { return "DLS"; } + public String methodOOS(OOS a) { return "OOS"; } + public String methodODS(ODS a) { return "ODS"; } + public String methodDOS(DOS a) { return "DOS"; } + public String methodLLB(LLB a) { return "LLB"; } + public String methodLOB(LOB a) { return "LOB"; } + public String methodOLB(OLB a) { return "OLB"; } + public String methodDDB(DDB a) { return "DDB"; } + public String methodLDB(LDB a) { return "LDB"; } + public String methodDLB(DLB a) { return "DLB"; } + public String methodOOB(OOB a) { return "OOB"; } + public String methodODB(ODB a) { return "ODB"; } + public String methodDOB(DOB a) { return "DOB"; } + public String methodLLD(LLD a) { return "LLD"; } + public String methodLOD(LOD a) { return "LOD"; } + public String methodOLD(OLD a) { return "OLD"; } + public String methodDDD(DDD a) { return "DDD"; } + public String methodLDD(LDD a) { return "LDD"; } + public String methodDLD(DLD a) { return "DLD"; } + public String methodOOD(OOD a) { return "OOD"; } + public String methodODD(ODD a) { return "ODD"; } + public String methodDOD(DOD a) { return "DOD"; } + public String methodLLF(LLF a) { return "LLF"; } + public String methodLOF(LOF a) { return "LOF"; } + public String methodOLF(OLF a) { return "OLF"; } + public String methodDDF(DDF a) { return "DDF"; } + public String methodLDF(LDF a) { return "LDF"; } + public String methodDLF(DLF a) { return "DLF"; } + public String methodOOF(OOF a) { return "OOF"; } + public String methodODF(ODF a) { return "ODF"; } + public String methodDOF(DOF a) { return "DOF"; } + public String methodLLZ(LLZ a) { return "LLZ"; } + public String methodLOZ(LOZ a) { return "LOZ"; } + public String methodOLZ(OLZ a) { return "OLZ"; } + public String methodDDZ(DDZ a) { return "DDZ"; } + public String methodLDZ(LDZ a) { return "LDZ"; } + public String methodDLZ(DLZ a) { return "DLZ"; } + public String methodOOZ(OOZ a) { return "OOZ"; } + public String methodODZ(ODZ a) { return "ODZ"; } + public String methodDOZ(DOZ a) { return "DOZ"; } + public String methodLLO(LLO a) { return "LLO"; } + public String methodLOO(LOO a) { return "LOO"; } + public String methodOLO(OLO a) { return "OLO"; } + public String methodDDO(DDO a) { return "DDO"; } + public String methodLDO(LDO a) { return "LDO"; } + public String methodDLO(DLO a) { return "DLO"; } + public String methodOOO(OOO a) { return "OOO"; } + public String methodODO(ODO a) { return "ODO"; } + public String methodDOO(DOO a) { return "DOO"; } + public String methodOOOZ(OOOZ a) { return "OOOZ"; } + public String methodOOOO(OOOO a) { return "OOOO"; } + public String methodOOOOZ(OOOOZ a) { return "OOOOZ"; } + public String methodOOOOO(OOOOO a) { return "OOOOO"; } + public String methodOOOOOZ(OOOOOZ a) { return "OOOOOZ"; } + public String methodOOOOOO(OOOOOO a) { return "OOOOOO"; } + public String methodOOOOOOZ(OOOOOOZ a) { return "OOOOOOZ"; } + public String methodOOOOOOO(OOOOOOO a) { return "OOOOOOO"; } + public String methodOOOOOOOZ(OOOOOOOZ a) { return "OOOOOOOZ"; } + public String methodOOOOOOOO(OOOOOOOO a) { return "OOOOOOOO"; } + public String methodOOOOOOOOZ(OOOOOOOOZ a) { return "OOOOOOOOZ"; } + public String methodOOOOOOOOO(OOOOOOOOO a) { return "OOOOOOOOO"; } + public String methodOOOOOOOOOZ(OOOOOOOOOZ a) { return "OOOOOOOOOZ"; } + public String methodOOOOOOOOOO(OOOOOOOOOO a) { return "OOOOOOOOOO"; } + public String methodOOOOOOOOOOZ(OOOOOOOOOOZ a) { return "OOOOOOOOOOZ"; } + public String methodOOOOOOOOOOO(OOOOOOOOOOO a) { return "OOOOOOOOOOO"; }} \ No newline at end of file From 70880ce0c3032c62785de4bd5d9b0d50e6ef66ef Mon Sep 17 00:00:00 2001 From: Fogus Date: Mon, 10 Jun 2024 10:58:33 -0400 Subject: [PATCH 225/285] CLJ-2698: Ignore primitive type return hints in defprotocol. --- src/clj/clojure/core_deftype.clj | 20 +++++++++++--------- test/clojure/test_clojure/protocols.clj | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/clj/clojure/core_deftype.clj b/src/clj/clojure/core_deftype.clj index 17fce7012d..66eeb94d66 100644 --- a/src/clj/clojure/core_deftype.clj +++ b/src/clj/clojure/core_deftype.clj @@ -653,15 +653,17 @@ [opts sigs])) sigs (when sigs (reduce1 (fn [m s] - (let [tag-to-class (fn [tag] - (if-let [c (and (instance? clojure.lang.Symbol tag) - (= (.indexOf (.getName ^clojure.lang.Symbol tag) ".") -1) - (not (contains? '#{int long float double char short byte boolean void - ints longs floats doubles chars shorts bytes booleans objects} tag)) - (resolve tag))] - (symbol (.getName c)) - tag)) - name-meta (update-in (meta (first s)) [:tag] tag-to-class) + (let [disallowed? '#{int long float double char short byte boolean void} + array-tag? '#{ints longs floats doubles chars shorts bytes booleans objects} + resolve-class-symbol (fn [tag] + (when-not (disallowed? tag) + (if-let [c (and (instance? clojure.lang.Symbol tag) + (= (.indexOf (.getName ^clojure.lang.Symbol tag) ".") -1) + (not (array-tag? tag)) + (resolve tag))] + (symbol (.getName c)) + tag))) + name-meta (update-in (meta (first s)) [:tag] resolve-class-symbol) mname (with-meta (first s) nil) [arglists doc] (loop [as [] rs (rest s)] diff --git a/test/clojure/test_clojure/protocols.clj b/test/clojure/test_clojure/protocols.clj index 4e951449bb..4cd87a42b5 100644 --- a/test/clojure/test_clojure/protocols.clj +++ b/test/clojure/test_clojure/protocols.clj @@ -705,3 +705,17 @@ (f [s] (seq s))) (deftest test-resolve-type-hints-in-protocol-methods (is (= 4 (clojure.test-clojure.protocols/f "test")))) + +;; CLJ-2698 - Ignore primitive hints in defprotocol return + +(defprotocol PrimHinted + (^double f1 [p a]) + (^void f2 [p])) + +(deftest test-prim-ret-hints-ignored + (is (thrown-with-msg? + Exception + #"Receiver class" + (eval '(f1 (reify PrimHinted) :foo)))) + (is (= :foo (f1 (reify PrimHinted (f1 [_ x] x)) :foo))) + (is (= "foo" (f2 (reify PrimHinted (f2 [_] "foo")))))) From f4fea967aade620b415d0f3c344e10bcbbdc5285 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 11 Jun 2024 10:30:57 -0500 Subject: [PATCH 226/285] CLJ-2862 Update changelog for 1.12 --- changes.md | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) diff --git a/changes.md b/changes.md index 9cbc7a4504..98dd69c5bd 100644 --- a/changes.md +++ b/changes.md @@ -1,5 +1,212 @@ +# Changes to Clojure in Version 1.12.0 + +## 1 Compatibility + +### 1.1 Java 8 - Compatiblity EOL notice + +Clojure 1.12 produces Java 8 bytecode (same as Clojure 1.10 and 1.11), but this is expected to be the last release using a Java 8 baseline. Future releases will move the bytecode and minimum Java compatibility to a newer Java LTS release. + +### 1.2 Java 21 - Virtual thread pinning from user code under `synchronized` + +Clojure users want to use virtual threads on JDK 21. Prior to 1.12, Clojure lazy-seqs and delays, in order to enforce run-once behavior, ran user code under synchronized blocks, which as of JDK 21 don't yet participate in cooperative blocking. Thus if that code did e.g. blocking I/O it would pin a real thread. JDK 21 may emit warnings for this when using `-Djdk.tracePinnedThreads=full`. + +To avoid this pinning, in 1.12 `lazy-seq` and `delay` use locks instead of synchronized blocks. + +See: [CLJ-2804](https://clojure.atlassian.net/browse/CLJ-2804) + +### 1.3 Security + +Fix [CVE-2024-22871](https://nvd.nist.gov/vuln/detail/CVE-2024-22871) detailed in [GHSA-vr64-r9qj-h27f](https://github.com/advisories/GHSA-vr64-r9qj-h27f): + +* [CLJ-2839](https://clojure.atlassian.net/browse/CLJ-2839) `iterate`, `cycle`, `repeat` - infinite seqs have infinite `hashCode()` + +### 1.4 Serialization + +[CLJ-1327](https://clojure.atlassian.net/browse/CLJ-1327) explicitly sets the Java serialization identifier for the classes in Clojure that implement Java serialization. In Clojure 1.11.0 this changed for two classes unnecessarily and we reverted those changes in Clojure 1.11.1 - this completes that work for the rest of the classes. + +Clojure data types have implemented the Java serialization interfaces since Clojure 1.0. Java serialization is designed to save graphs of Java instances into a byte stream. Every class has an identifier (the serialVersionUID) that is automatically generated based on the class name, it's type hierarchy, and the serialized fields. At deserialization time, deserialization can only occur when the available class has an identifier that matches the class id recorded in the serialized bytes. + +Clojure has never provided a guarantee of serialization consistency across Clojure versions, but we do not wish to break compatibility any more than necessary and these changes will give us more control over that in the future. + +See: [CLJ-1327](https://clojure.atlassian.net/browse/CLJ-1327) + +### 1.5 Dependencies + +Updated dependencies: + +* spec.alpha dependency to 0.5.238 - [changes](https://github.com/clojure/spec.alpha/blob/master/CHANGES.md) +* core.specs.alpha dependency to 0.4.74 - [changes](https://github.com/clojure/core.specs.alpha/blob/master/CHANGES.md) + +See: [CLJ-2852](https://clojure.atlassian.net/browse/CLJ-2852) + +## 2 Features + +### 2.1 Add libraries for interactive use + +There are many development-time cases where it would be useful to add a library interactively without restarting the JVM - speculative evaluation, adding a known dependency to your project, or adding a library to accomplish a specific task. + +Clojure now provides new functions to add libraries interactively, without restarting the JVM or losing the state of your work: + +* [add-lib](https://clojure.github.io/clojure/branch-master/clojure.repl-api.html#clojure.repl.deps/add-lib) takes a lib that is not available on the classpath, and makes it available by downloading (if necessary) and adding to the classloader. Libs already on the classpath are not updated. If the coordinate is not provided, the newest Maven or git (if the library has an inferred git repo name) version or tag are used. +* [add-libs](https://clojure.github.io/clojure/branch-master/clojure.repl-api.html#clojure.repl.deps/add-libs) is like `add-lib`, but resolves a set of new libraries and versions together. +* [sync-deps](https://clojure.github.io/clojure/branch-master/clojure.repl-api.html#clojure.repl.deps/sync-deps) calls `add-libs` with any libs present in deps.edn, but not yet present on the classpath. + +These new functions are intended only for development-time interactive use at the repl - using a deps.edn is still the proper way to build and maintain production code. To this end, these functions all check that [\*repl*](https://clojure.github.io/clojure/branch-master/clojure.core-api.html#clojure.core/%2Arepl%2A) is bound to true (that flag is bound automatically by `clojure.main/repl`). In a clojure.main REPL, these new functions are automatically referred in the `user` namespace. In other repls, you may need to `(require '[clojure.repl.deps :refer :all])` before use. + +Library resolution and download are provided by [tools.deps](https://github.com/clojure/tools.deps). However, you do not want to add tools.deps and its many dependencies to your project classpath during development, and thus we have also added a new api for invoking functions out of process via the Clojure CLI. + +See: [CLJ-2761](https://clojure.atlassian.net/browse/CLJ-2761), [CLJ-2757](https://clojure.atlassian.net/browse/CLJ-2757), [CLJ-2788](https://clojure.atlassian.net/browse/CLJ-2788), [CLJ-2767](https://clojure.atlassian.net/browse/CLJ-2767), [CLJ-2769](https://clojure.atlassian.net/browse/CLJ-2769), [CLJ-2770](https://clojure.atlassian.net/browse/CLJ-2770) + +### 2.2 Invoke tool functions out of process + +There are many useful tools you can use at development time, but which are not part of your project's actual dependencies. The Clojure CLI provides explicit support for [tools](https://clojure.org/reference/clojure_cli#tool_install) with their own classpath, but there was not previously a way to invoke these interactively. + +Clojure now includes [clojure.tools.deps.interop/invoke-tool](https://clojure.github.io/clojure/branch-master/clojure.tools.deps.interop-api.html#clojure.tools.deps.interop/invoke-tool) to invoke a tool function out of process. The classpath for the tool is defined in deps.edn and you do not need to add the tool's dependencies to your project classpath. + +`add-lib` functionality is built using `invoke-tool` but you can also use it to build or invoke your own tools for interactive use. Find more about the function execution protocol on the [CLI reference](https://clojure.org/reference/clojure_cli#function_protocol). + +See: [CLJ-2760](https://clojure.atlassian.net/browse/CLJ-2760) + +### 2.3 Start and control external processes + +For a long time, we've had the `clojure.java.shell` namespace, but over time Java has provided new APIs for process info, process control, and I/O redirection. This release adds a new namespace [clojure.java.process](https://clojure.github.io/clojure/branch-master/index.html#clojure.java.process) that takes advantage of these APIs and is easier to use. See: + +* [start](https://clojure.github.io/clojure/branch-master/clojure.java.process-api.html#clojure.java.process/start) - full control over streams with access to the underlying Java objects for advanced usage +* [exec](https://clojure.github.io/clojure/branch-master/clojure.java.process-api.html#clojure.java.process/exec) - covers the common case of executing an external process and returning its stdout on completion + +See: [CLJ-2759](https://clojure.atlassian.net/browse/CLJ-2759), [CLJ-2777](https://clojure.atlassian.net/browse/CLJ-2777), [CLJ-2828](https://clojure.atlassian.net/browse/CLJ-2828), [CLJ-2773](https://clojure.atlassian.net/browse/CLJ-2773), [CLJ-2776](https://clojure.atlassian.net/browse/CLJ-2776), [CLJ-2774](https://clojure.atlassian.net/browse/CLJ-2774), [CLJ-2778](https://clojure.atlassian.net/browse/CLJ-2778), [CLJ-2779](https://clojure.atlassian.net/browse/CLJ-2779) + +### 2.4 Method values + +Clojure programmers often want to use Java methods in higher-order functions (e.g. passing a Java method to `map`). Until now, programmers have had to manually wrap methods in functions. This is verbose, and might require manual hinting for overload disambiguation, or incur incidental reflection or boxing. + +Programmers can now use [qualified methods](#25-qualified-methods---classmethod-classmethod-and-classnew) as ordinary functions in value contexts - the compiler will automatically generate the wrapping function. The compiler will generate a reflective call when a qualified method does not resolve due to overloading. Developers can supply [:param-tags](#26-param-tags-metadata) metadata on qualified methods to specify the signature of a single desired method, 'resolving' it. + +See: [CLJ-2793](https://clojure.atlassian.net/browse/CLJ-2793), [CLJ-2844](https://clojure.atlassian.net/browse/CLJ-2844), [CLJ-2835](https://clojure.atlassian.net/browse/CLJ-2835) + +### 2.5 Qualified methods - `Class/method`, `Class/.method`, and `Class/new` + +Java members inherently exist in a class. For method values we need a way to explicitly specify the class of an instance method because there is no possibility for inference. + +Qualified methods have value semantics when used in non-invocation positions: + +* `Classname/method` - value is a Clojure function that invokes a static method +* `Classname/.method` - value is a Clojure function that invokes an instance method +* `Classname/new` - value is a Clojure function that invokes a constructor + +Note: developers must use `Classname/method` and `Classname/.method` syntax to differentiate between static and instance methods. + +Qualified method invocations with [param-tags](#26-param-tags-metadata) use only the tags to resolve the method. Without param-tags they behave like the equivalent [dot syntax](https://clojure.org/reference/java_interop#_the_dot_special_form), except the qualifying class takes precedence over hints of the target object, and over its runtime type when invoked via reflection. + +Note: Static fields are values and should be referenced without parens unless they are intended as function calls, e.g `(System/out)` should be `System/out`. Future Clojure releases will treat the field's value as something invokable and invoke it. + +See: [CLJ-2844](https://clojure.atlassian.net/browse/CLJ-2844), [CLJ-2848](https://clojure.atlassian.net/browse/CLJ-2848), [CLJ-2847](https://clojure.atlassian.net/browse/CLJ-2847), [CLJ-2853](https://clojure.atlassian.net/browse/CLJ-2853) + +### 2.6 :param-tags metadata + +When used as values, qualified methods supply only the class and method name, and thus cannot resolve overloaded methods. + +Developers can supply `:param-tags` metadata on qualified methods to specify the signature of a single desired method, 'resolving' it. The `:param-tags` metadata is a vector of zero or more tags: `[tag ...]`. A tag is any existing valid `:tag` metadata value. Each tag corresponds to a parameter in the desired signature (arity should match the number of tags). Parameters with non-overloaded types can use the placeholder `_` in lieu of the tag. When you supply :param-tags metadata on a qualified method, the metadata must allow the compiler to resolve it to a single method at compile time. + +A new metadata reader syntax `^[tag ...]` attaches `:param-tags` metadata to member symbols, just as `^tag` attaches `:tag` metadata to a symbol. + +See: [CLJ-2805](https://clojure.atlassian.net/browse/CLJ-2805) + +### 2.7 Array class syntax + +Clojure supports symbols naming classes both as a value (for class object) and as a type hint, but has not provided syntax for array classes other than strings. + +Developers can now refer to an array class using a symbol of the form `ComponentClass/#dimensions`, eg `String/2` refers to the class of a 2 dimensional array of Strings. Component classes can be fully-qualified classes, imported classes, or primitives. Array class syntax can be used as both type hints and values. + +Examples: `String/1`, `java.lang.String/1`, `long/2`. + +See: [CLJ-2807](https://clojure.atlassian.net/browse/CLJ-2807) + +### 2.8 Functional interfaces + +Java programs define "functions" with Java functional interfaces (marked with the [@FunctionalInterface](https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html) annotation), which have a single method. + +Clojure developers can now invoke Java methods taking functional interfaces by passing functions with matching arity. The Clojure compiler implicitly converts Clojure functions to the required functional interface by constructing a lambda adapter. You can explicitly coerce a Clojure function to a functional interface by hinting the binding name in a `let` binding, e.g. to avoid repeated adapter construction in a loop, e.g. `(let [^java.util.function.Predicate p even?] ...)`. + +See: [CLJ-2799](https://clojure.atlassian.net/browse/CLJ-2799), [CLJ-2858](https://clojure.atlassian.net/browse/CLJ-2858), [CLJ-2856](https://clojure.atlassian.net/browse/CLJ-2856) + +### 2.9 Java Supplier interop + +Calling methods that take a [Supplier](https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html) (a method that supplies a value) had required writing an adapter with reify. Clojure has a "value supplier" interface with semantic support already - `IDeref`. All `IDeref` impls (`delay`, `future`, `atom`, etc) now implement the `Supplier` interface directly. + +See: [CLJ-2792](https://clojure.atlassian.net/browse/CLJ-2792), [CLJ-2841](https://clojure.atlassian.net/browse/CLJ-2841) + +### 2.10 Streams with seq, into, reduce, and transduce support + +Java APIs increasingly return [Stream](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html)s and are hard to consume because they do not implement interfaces that Clojure already supports, and hard to interop with because Clojure doesn't directly implement Java functional interfaces. + +In addition to functional interface support, Clojure now provides these functions to interoperate with streams in an idiomatic manner, all functions behave analogously to their Clojure counterparts: + +* `(stream-seq! stream) => seq` +* `(stream-reduce! f [init-val] stream) => val` +* `(stream-transduce! xf f [init-val] stream) => val` +* `(stream-into! to-coll [xf] stream) => to-coll` + +All of these operations are terminal stream operations (they consume the stream). + +See: [CLJ-2775](https://clojure.atlassian.net/browse/CLJ-2775) + +### 2.11 PersistentVector implements Spliterable + +Java collections implement streams via ["spliterators"](https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html), iterators that can be split for faster parallel traversal. `PersistentVector` now provides a custom spliterator that supports parallelism, with greatly improved performance. + +See: [CLJ-2791](https://clojure.atlassian.net/browse/CLJ-2791) + +### 2.12 Efficient drop and partition for persistent or algorithmic collections + +Partitioning of a collection uses a series of takes (to build a partition) and drops (to skip past that partition). [CLJ-2713](https://clojure.atlassian.net/browse/CLJ-2713) adds a new internal interface (IDrop) indicating that a collection can drop more efficiently than sequential traversal, and implements that for persistent collections and algorithmic collections like `range` and `repeat`. These optimizations are used in `drop`, `nthrest`, and `nthnext`. + +Additionally, there are new functions `partitionv`, `partitionv-all`, and `splitv-at` that are more efficient than their existing counterparts and produce vector partitions instead of realized seq partitions. + +See: [CLJ-2713](https://clojure.atlassian.net/browse/CLJ-2713), [CLJ-2742](https://clojure.atlassian.net/browse/CLJ-2742), [CLJ-2740](https://clojure.atlassian.net/browse/CLJ-2740), [CLJ-2715](https://clojure.atlassian.net/browse/CLJ-2715), [CLJ-2718](https://clojure.atlassian.net/browse/CLJ-2718), [CLJ-2772](https://clojure.atlassian.net/browse/CLJ-2772), [CLJ-2741](https://clojure.atlassian.net/browse/CLJ-2741) + +### 2.13 Var interning policy + +[Interning](https://clojure.org/reference/vars#interning) a var in a namespace (vs aliasing) must create a stable reference that is never displaced, so that all references to an interned var get the same object. There were some cases where interned vars could get displaced and those have been tightened up in 1.12.0-alpha1. If you encounter this situation, you'll see a warning like "REJECTED: attempt to replace interned var #'some-ns/foo with #'other-ns/foo in some-ns, you must ns-unmap first". + +This addresses the root cause of an issue encountered with Clojure 1.11.0, which added new functions to clojure.core (particularly `abs`). Compiled code from an earlier version of Clojure with var names that matched the newly added functions in clojure.core would be unbound when loaded in a 1.11.0 runtime. In addition to [CLJ-2711](https://clojure.atlassian.net/browse/CLJ-2711), we rolled back a previous fix in this area ([CLJ-1604](https://clojure.atlassian.net/browse/CLJ-1604)). + +See: [CLJ-2711](https://clojure.atlassian.net/browse/CLJ-2711) + +## 3 Fixes and enhancements + +### 3.1 Reader and Compiler + +* [CLJ-2726](https://clojure.atlassian.net/browse/CLJ-2726) `#uuid` data reader - Fix exception on invalid input so it flows through reader +* [CLJ-2813](https://clojure.atlassian.net/browse/CLJ-2813) anonymous function arg reader - no longer accepts invalid arg symbols +* [CLJ-2843](https://clojure.atlassian.net/browse/CLJ-2843) Reflective calls to Java methods that take primitive long or double now work when passed a narrower boxed number at runtime (Integer, Short, Byte, Float). Previously, these methods were not matched during reflection and an error was thrown. + +### 3.2 Core + +* [CLJ-2739](https://clojure.atlassian.net/browse/CLJ-2739) ArityException - Fix message when function incorrectly called with >20 args +* [CLJ-2709](https://clojure.atlassian.net/browse/CLJ-2709) `range` - Use optimized range for int args +* [CLJ-2721](https://clojure.atlassian.net/browse/CLJ-2721) `range` - Fix invalid arg order when adding meta to non-optimized range +* [CLJ-2683](https://clojure.atlassian.net/browse/CLJ-2683) `with-open` - Fix to not qualify `.close` method on expansion +* [CLJ-2724](https://clojure.atlassian.net/browse/CLJ-2724) `clojure.java.io/do-copy` - Fix incorrect type hint +* [CLJ-2640](https://clojure.atlassian.net/browse/CLJ-2640) `ex-info` - now handles nil data map +* [CLJ-2717](https://clojure.atlassian.net/browse/CLJ-2717) `nthrest` now returns rest output on n=0 or past end of seq +* [CLJ-1872](https://clojure.atlassian.net/browse/CLJ-1872) `empty?` - adds support for `counted?` collections +* [CLJ-2694](https://clojure.atlassian.net/browse/CLJ-2694) Fix ratio invariants violated when using Long/MIN_VALUE +* [CLJ-2568](https://clojure.atlassian.net/browse/CLJ-2568) `clojure.walk/walk` - preserve metadata on lists and seqs +* [CLJ-2686](https://clojure.atlassian.net/browse/CLJ-2686) `clojure.core.server/parse-props` - Fix exception if system properties concurrently modified during initialization +* [CLJ-2645](https://clojure.atlassian.net/browse/CLJ-2645) `PrintWriter-on` should support auto-flush, and prepl should use it for the err stream +* [CLJ-2698](https://clojure.atlassian.net/browse/CLJ-2698) `defprotocol` - ignore unused primitive return type hints +* [CLJ-2783](https://clojure.atlassian.net/browse/CLJ-2783) replace calls to deprecated URL constructor + +### 3.3 Docstrings + +* [CLJ-2225](https://clojure.atlassian.net/browse/CLJ-2225) `assert` and `\*assert*` - improve docstrings to add context +* [CLJ-2290](https://clojure.atlassian.net/browse/CLJ-2290) `into` - add 0- and 1-arity to docstring +* [CLJ-2552](https://clojure.atlassian.net/browse/CLJ-2552) `reify` - improve docstring and fix example +* [CLJ-1385](https://clojure.atlassian.net/browse/CLJ-1385) `transient` - include usage model from reference docs + # Changes to Clojure in Version 1.11.3 * [CLJ-2843](https://clojure.atlassian.net/browse/CLJ-2843) - Reflective calls to Java methods that take primitive long or double now work when passed a narrower boxed number at runtime (Integer, Short, Byte, Float). Previously, these methods were not matched during reflection and an error was thrown. From 2d1097cd5a9dcf354009cc0094c3e8d28c9538c3 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 12 Jun 2024 10:16:28 -0500 Subject: [PATCH 227/285] CLJ-2863 When doing reflective FI adapting, use RT.baseLoader() for proxy Classloader --- src/jvm/clojure/lang/Reflector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/Reflector.java b/src/jvm/clojure/lang/Reflector.java index f252bf2eb7..133cb588f8 100644 --- a/src/jvm/clojure/lang/Reflector.java +++ b/src/jvm/clojure/lang/Reflector.java @@ -594,7 +594,7 @@ private static Object coerceAdapterReturn(Object ret, Class targetType) { static Object boxArg(Class paramType, Object arg){ if(arg instanceof IFn && Compiler.FISupport.maybeFIMethod(paramType) != null) // Adapt IFn obj to targetType using dynamic proxy - return Proxy.newProxyInstance((ClassLoader) Compiler.LOADER.get(), + return Proxy.newProxyInstance(RT.baseLoader(), new Class[]{paramType}, (proxy, method, methodArgs) -> { Object ret = ((IFn) arg).applyTo(RT.seq(methodArgs)); From aeaac641c9d2cbac04b0eafe096c63907bdd422c Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 14 Jun 2024 13:07:15 -0500 Subject: [PATCH 228/285] CLJ-2864 Remove truthy logic return FI invokers --- codegen/gen_fn_adapter_tests.clj | 4 +- codegen/gen_fn_invokers.clj | 14 +-- src/jvm/clojure/lang/Compiler.java | 6 +- src/jvm/clojure/lang/FnInvokers.java | 86 -------------- .../generated_all_fi_adapters_in_let.clj | 63 ----------- .../generated_functional_adapters_in_def.clj | 42 ------- ...l_adapters_in_def_requiring_reflection.clj | 42 ------- test/clojure/test_clojure/java_interop.clj | 9 +- test/java/clojure/test/AdapterExerciser.java | 105 ------------------ 9 files changed, 8 insertions(+), 363 deletions(-) diff --git a/codegen/gen_fn_adapter_tests.clj b/codegen/gen_fn_adapter_tests.clj index 7ebf39b1f4..423ee77fc6 100644 --- a/codegen/gen_fn_adapter_tests.clj +++ b/codegen/gen_fn_adapter_tests.clj @@ -44,11 +44,11 @@ public class AdapterExerciser {") (reduce fun-sig-reducer [] return-types))) (defn gen-sigs [] - (let [small-rets ["L" "I" "S" "B" "D" "F" "Z" "O"] + (let [small-rets ["L" "I" "S" "B" "D" "F" "O"] zero-arity (sigs [""] small-rets) single-arity (sigs ["L" "D" "O"] small-rets) two-arity (sigs ["LL" "LO" "OL" "DD" "LD" "DL" "OO" "OD" "DO"] small-rets) - big-rets ["Z" "O"] + big-rets ["O"] three-arity (sigs ["OOO"] big-rets) four-arity (sigs ["OOOO"] big-rets) five-arity (sigs ["OOOOO"] big-rets) diff --git a/codegen/gen_fn_invokers.clj b/codegen/gen_fn_invokers.clj index f69c3ae58e..3d2a8a73ca 100644 --- a/codegen/gen_fn_invokers.clj +++ b/codegen/gen_fn_invokers.clj @@ -35,8 +35,6 @@ public class FnInvokers { return 'B'; } else if(Float.TYPE.equals(c)) { return 'F'; - } else if(Boolean.TYPE.equals(c)) { - return 'Z'; } else { return 'O'; } @@ -61,11 +59,6 @@ public class FnInvokers { } }") -(def invokeZ-format - " public static boolean invoke%sZ(IFn f0%s) { - return RT.booleanCast(f0.invoke(%s)); - }") - (def invokeD-format " public static double invoke%sD(IFn f0%s) { if(f0 instanceof IFn.%sD) { @@ -142,8 +135,7 @@ public class FnInvokers { "S" (format invokeS-format arg-str fn-vars arg-str arg-str fn-vars-sans-type fn-vars-sans-type) "B" (format invokeB-format arg-str fn-vars arg-str arg-str fn-vars-sans-type fn-vars-sans-type) "D" (format invokeD-format arg-str fn-vars arg-str arg-str fn-vars-sans-type fn-vars-sans-type) - "F" (format invokeF-format arg-str fn-vars arg-str arg-str fn-vars-sans-type fn-vars-sans-type) - "Z" (format invokeZ-format arg-str fn-vars fn-vars-sans-type)))) + "F" (format invokeF-format arg-str fn-vars arg-str arg-str fn-vars-sans-type fn-vars-sans-type)))) (defn sigs [args return-types] (let [fun-sig-reducer (fn [res ret] @@ -152,11 +144,11 @@ public class FnInvokers { (reduce fun-sig-reducer [] return-types))) (defn gen-sigs [] - (let [small-rets ["L" "I" "S" "B" "D" "F" "Z" "O"] + (let [small-rets ["L" "I" "S" "B" "D" "F" "O"] zero-arity (sigs [""] small-rets) single-arity (sigs ["L" "D" "O"] small-rets) two-arity (sigs ["LL" "LO" "OL" "DD" "LD" "DL" "OO" "OD" "DO"] small-rets) - big-rets ["Z" "O"] + big-rets ["O"] three-arity (sigs ["OOO"] big-rets) four-arity (sigs ["OOOO"] big-rets) five-arity (sigs ["OOOOO"] big-rets) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index d711d67b03..9a4c901546 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1672,11 +1672,9 @@ static boolean maybeEmitFIAdapter(ObjExpr objx, GeneratorAdapter gen, Expr expr, invokerParams[i + 1] = paramCount <= 2 ? toInvokerParamType(targetMethod.getParameterTypes()[i]) : Object.class; invokeMethodBuilder.append(FnInvokers.encodeInvokerType(invokerParams[i + 1])); } - // FnInvokers has prim returns for <= 2 params, only boolean or Object for higher + // FnInvokers has prim returns for <= 2 params, only Object for higher Class retType = targetMethod.getReturnType(); - char invokerReturnCode = FnInvokers.encodeInvokerType( - paramCount <= 2 ? retType : - (Boolean.TYPE.equals(retType) ? retType : Object.class)); + char invokerReturnCode = FnInvokers.encodeInvokerType(paramCount <= 2 ? retType : Object.class); invokeMethodBuilder.append(invokerReturnCode); String invokerMethodName = invokeMethodBuilder.toString(); diff --git a/src/jvm/clojure/lang/FnInvokers.java b/src/jvm/clojure/lang/FnInvokers.java index be79a90273..34cbaa548b 100644 --- a/src/jvm/clojure/lang/FnInvokers.java +++ b/src/jvm/clojure/lang/FnInvokers.java @@ -26,8 +26,6 @@ static char encodeInvokerType(Class c) { return 'B'; } else if(Float.TYPE.equals(c)) { return 'F'; - } else if(Boolean.TYPE.equals(c)) { - return 'Z'; } else { return 'O'; } @@ -81,10 +79,6 @@ public static float invokeF(IFn f0) { } } - public static boolean invokeZ(IFn f0) { - return RT.booleanCast(f0.invoke()); - } - public static Object invokeO(IFn f0) { return f0.invoke(); } @@ -233,18 +227,6 @@ public static float invokeOF(IFn f0, Object a) { } } - public static boolean invokeLZ(IFn f0, long a) { - return RT.booleanCast(f0.invoke(a)); - } - - public static boolean invokeDZ(IFn f0, double a) { - return RT.booleanCast(f0.invoke(a)); - } - - public static boolean invokeOZ(IFn f0, Object a) { - return RT.booleanCast(f0.invoke(a)); - } - public static Object invokeLO(IFn f0, long a) { if(f0 instanceof IFn.LO) { return ((IFn.LO)f0).invokePrim(a); @@ -697,42 +679,6 @@ public static float invokeDOF(IFn f0, double a, Object b) { } } - public static boolean invokeLLZ(IFn f0, long a, long b) { - return RT.booleanCast(f0.invoke(a, b)); - } - - public static boolean invokeLOZ(IFn f0, long a, Object b) { - return RT.booleanCast(f0.invoke(a, b)); - } - - public static boolean invokeOLZ(IFn f0, Object a, long b) { - return RT.booleanCast(f0.invoke(a, b)); - } - - public static boolean invokeDDZ(IFn f0, double a, double b) { - return RT.booleanCast(f0.invoke(a, b)); - } - - public static boolean invokeLDZ(IFn f0, long a, double b) { - return RT.booleanCast(f0.invoke(a, b)); - } - - public static boolean invokeDLZ(IFn f0, double a, long b) { - return RT.booleanCast(f0.invoke(a, b)); - } - - public static boolean invokeOOZ(IFn f0, Object a, Object b) { - return RT.booleanCast(f0.invoke(a, b)); - } - - public static boolean invokeODZ(IFn f0, Object a, double b) { - return RT.booleanCast(f0.invoke(a, b)); - } - - public static boolean invokeDOZ(IFn f0, double a, Object b) { - return RT.booleanCast(f0.invoke(a, b)); - } - public static Object invokeLLO(IFn f0, long a, long b) { if(f0 instanceof IFn.LLO) { return ((IFn.LLO)f0).invokePrim(a, b); @@ -801,66 +747,34 @@ public static Object invokeDOO(IFn f0, double a, Object b) { } } - public static boolean invokeOOOZ(IFn f0, Object a, Object b, Object c) { - return RT.booleanCast(f0.invoke(a, b, c)); - } - public static Object invokeOOOO(IFn f0, Object a, Object b, Object c) { return f0.invoke(a, b, c); } - public static boolean invokeOOOOZ(IFn f0, Object a, Object b, Object c, Object d) { - return RT.booleanCast(f0.invoke(a, b, c, d)); - } - public static Object invokeOOOOO(IFn f0, Object a, Object b, Object c, Object d) { return f0.invoke(a, b, c, d); } - public static boolean invokeOOOOOZ(IFn f0, Object a, Object b, Object c, Object d, Object e) { - return RT.booleanCast(f0.invoke(a, b, c, d, e)); - } - public static Object invokeOOOOOO(IFn f0, Object a, Object b, Object c, Object d, Object e) { return f0.invoke(a, b, c, d, e); } - public static boolean invokeOOOOOOZ(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f) { - return RT.booleanCast(f0.invoke(a, b, c, d, e, f)); - } - public static Object invokeOOOOOOO(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f) { return f0.invoke(a, b, c, d, e, f); } - public static boolean invokeOOOOOOOZ(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g) { - return RT.booleanCast(f0.invoke(a, b, c, d, e, f, g)); - } - public static Object invokeOOOOOOOO(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g) { return f0.invoke(a, b, c, d, e, f, g); } - public static boolean invokeOOOOOOOOZ(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h) { - return RT.booleanCast(f0.invoke(a, b, c, d, e, f, g, h)); - } - public static Object invokeOOOOOOOOO(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h) { return f0.invoke(a, b, c, d, e, f, g, h); } - public static boolean invokeOOOOOOOOOZ(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h, Object i) { - return RT.booleanCast(f0.invoke(a, b, c, d, e, f, g, h, i)); - } - public static Object invokeOOOOOOOOOO(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h, Object i) { return f0.invoke(a, b, c, d, e, f, g, h, i); } - public static boolean invokeOOOOOOOOOOZ(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h, Object i, Object j) { - return RT.booleanCast(f0.invoke(a, b, c, d, e, f, g, h, i, j)); - } - public static Object invokeOOOOOOOOOOO(IFn f0, Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h, Object i, Object j) { return f0.invoke(a, b, c, d, e, f, g, h, i, j); } diff --git a/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj b/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj index a84144cee7..4bac4914b9 100644 --- a/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj +++ b/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj @@ -8,7 +8,6 @@ AdapterExerciser$S AdapterExerciser$B AdapterExerciser$D AdapterExerciser$F -AdapterExerciser$Z AdapterExerciser$O AdapterExerciser$LL AdapterExerciser$DL @@ -28,9 +27,6 @@ AdapterExerciser$OD AdapterExerciser$LF AdapterExerciser$DF AdapterExerciser$OF -AdapterExerciser$LZ -AdapterExerciser$DZ -AdapterExerciser$OZ AdapterExerciser$LO AdapterExerciser$DO AdapterExerciser$OO @@ -88,15 +84,6 @@ AdapterExerciser$DLF AdapterExerciser$OOF AdapterExerciser$ODF AdapterExerciser$DOF -AdapterExerciser$LLZ -AdapterExerciser$LOZ -AdapterExerciser$OLZ -AdapterExerciser$DDZ -AdapterExerciser$LDZ -AdapterExerciser$DLZ -AdapterExerciser$OOZ -AdapterExerciser$ODZ -AdapterExerciser$DOZ AdapterExerciser$LLO AdapterExerciser$LOO AdapterExerciser$OLO @@ -106,21 +93,13 @@ AdapterExerciser$DLO AdapterExerciser$OOO AdapterExerciser$ODO AdapterExerciser$DOO -AdapterExerciser$OOOZ AdapterExerciser$OOOO -AdapterExerciser$OOOOZ AdapterExerciser$OOOOO -AdapterExerciser$OOOOOZ AdapterExerciser$OOOOOO -AdapterExerciser$OOOOOOZ AdapterExerciser$OOOOOOO -AdapterExerciser$OOOOOOOZ AdapterExerciser$OOOOOOOO -AdapterExerciser$OOOOOOOOZ AdapterExerciser$OOOOOOOOO -AdapterExerciser$OOOOOOOOOZ AdapterExerciser$OOOOOOOOOO -AdapterExerciser$OOOOOOOOOOZ AdapterExerciser$OOOOOOOOOOO ))) @@ -132,7 +111,6 @@ AdapterExerciser$OOOOOOOOOOO ^AdapterExerciser$B Badapter (fn [] (byte 1)) ^AdapterExerciser$D Dadapter (fn [] (double 1)) ^AdapterExerciser$F Fadapter (fn [] (float 1)) - ^AdapterExerciser$Z Zadapter (fn [] false) ^AdapterExerciser$O Oadapter (fn [] exerciser) ^AdapterExerciser$LL LLadapter (fn [^long a] (long 1)) ^AdapterExerciser$DL DLadapter (fn [^double a] (long 1)) @@ -152,9 +130,6 @@ AdapterExerciser$OOOOOOOOOOO ^AdapterExerciser$LF LFadapter (fn [^long a] (float 1)) ^AdapterExerciser$DF DFadapter (fn [^double a] (float 1)) ^AdapterExerciser$OF OFadapter (fn [^AdapterExerciser a] (float 1)) - ^AdapterExerciser$LZ LZadapter (fn [^long a] false) - ^AdapterExerciser$DZ DZadapter (fn [^double a] false) - ^AdapterExerciser$OZ OZadapter (fn [^AdapterExerciser a] false) ^AdapterExerciser$LO LOadapter (fn [^long a] exerciser) ^AdapterExerciser$DO DOadapter (fn [^double a] exerciser) ^AdapterExerciser$OO OOadapter (fn [^AdapterExerciser a] exerciser) @@ -212,15 +187,6 @@ AdapterExerciser$OOOOOOOOOOO ^AdapterExerciser$OOF OOFadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (float 1)) ^AdapterExerciser$ODF ODFadapter (fn [^AdapterExerciser a ^double b] (float 1)) ^AdapterExerciser$DOF DOFadapter (fn [^double a ^AdapterExerciser b] (float 1)) - ^AdapterExerciser$LLZ LLZadapter (fn [^long a ^long b] false) - ^AdapterExerciser$LOZ LOZadapter (fn [^long a ^AdapterExerciser b] false) - ^AdapterExerciser$OLZ OLZadapter (fn [^AdapterExerciser a ^long b] false) - ^AdapterExerciser$DDZ DDZadapter (fn [^double a ^double b] false) - ^AdapterExerciser$LDZ LDZadapter (fn [^long a ^double b] false) - ^AdapterExerciser$DLZ DLZadapter (fn [^double a ^long b] false) - ^AdapterExerciser$OOZ OOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b] false) - ^AdapterExerciser$ODZ ODZadapter (fn [^AdapterExerciser a ^double b] false) - ^AdapterExerciser$DOZ DOZadapter (fn [^double a ^AdapterExerciser b] false) ^AdapterExerciser$LLO LLOadapter (fn [^long a ^long b] exerciser) ^AdapterExerciser$LOO LOOadapter (fn [^long a ^AdapterExerciser b] exerciser) ^AdapterExerciser$OLO OLOadapter (fn [^AdapterExerciser a ^long b] exerciser) @@ -230,21 +196,13 @@ AdapterExerciser$OOOOOOOOOOO ^AdapterExerciser$OOO OOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b] exerciser) ^AdapterExerciser$ODO ODOadapter (fn [^AdapterExerciser a ^double b] exerciser) ^AdapterExerciser$DOO DOOadapter (fn [^double a ^AdapterExerciser b] exerciser) - ^AdapterExerciser$OOOZ OOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] false) ^AdapterExerciser$OOOO OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser) - ^AdapterExerciser$OOOOZ OOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] false) ^AdapterExerciser$OOOOO OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser) - ^AdapterExerciser$OOOOOZ OOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] false) ^AdapterExerciser$OOOOOO OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser) - ^AdapterExerciser$OOOOOOZ OOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] false) ^AdapterExerciser$OOOOOOO OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser) - ^AdapterExerciser$OOOOOOOZ OOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] false) ^AdapterExerciser$OOOOOOOO OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser) - ^AdapterExerciser$OOOOOOOOZ OOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] false) ^AdapterExerciser$OOOOOOOOO OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser) - ^AdapterExerciser$OOOOOOOOOZ OOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] false) ^AdapterExerciser$OOOOOOOOOO OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser) - ^AdapterExerciser$OOOOOOOOOOZ OOOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] false) ^AdapterExerciser$OOOOOOOOOOO OOOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] exerciser)] (is (= (.takesRetL Ladapter ) (long 1))) (is (= (.takesRetI Iadapter ) 1)) @@ -252,7 +210,6 @@ AdapterExerciser$OOOOOOOOOOO (is (= (.takesRetB Badapter ) (byte 1))) (is (= (.takesRetD Dadapter ) (double 1))) (is (= (.takesRetF Fadapter ) (float 1))) - (is (= (.takesRetZ Zadapter ) false)) (is (= (.takesRetO Oadapter ) exerciser)) (is (= (.takesLRetL LLadapter (long 1)) (long 1))) (is (= (.takesDRetL DLadapter (double 1)) (long 1))) @@ -272,9 +229,6 @@ AdapterExerciser$OOOOOOOOOOO (is (= (.takesLRetF LFadapter (long 1)) (float 1))) (is (= (.takesDRetF DFadapter (double 1)) (float 1))) (is (= (.takesORetF OFadapter exerciser) (float 1))) - (is (= (.takesLRetZ LZadapter (long 1)) false)) - (is (= (.takesDRetZ DZadapter (double 1)) false)) - (is (= (.takesORetZ OZadapter exerciser) false)) (is (= (.takesLRetO LOadapter (long 1)) exerciser)) (is (= (.takesDRetO DOadapter (double 1)) exerciser)) (is (= (.takesORetO OOadapter exerciser) exerciser)) @@ -332,15 +286,6 @@ AdapterExerciser$OOOOOOOOOOO (is (= (.takesOORetF OOFadapter exerciser exerciser) (float 1))) (is (= (.takesODRetF ODFadapter exerciser (double 1)) (float 1))) (is (= (.takesDORetF DOFadapter (double 1) exerciser) (float 1))) - (is (= (.takesLLRetZ LLZadapter (long 1) (long 1)) false)) - (is (= (.takesLORetZ LOZadapter (long 1) exerciser) false)) - (is (= (.takesOLRetZ OLZadapter exerciser (long 1)) false)) - (is (= (.takesDDRetZ DDZadapter (double 1) (double 1)) false)) - (is (= (.takesLDRetZ LDZadapter (long 1) (double 1)) false)) - (is (= (.takesDLRetZ DLZadapter (double 1) (long 1)) false)) - (is (= (.takesOORetZ OOZadapter exerciser exerciser) false)) - (is (= (.takesODRetZ ODZadapter exerciser (double 1)) false)) - (is (= (.takesDORetZ DOZadapter (double 1) exerciser) false)) (is (= (.takesLLRetO LLOadapter (long 1) (long 1)) exerciser)) (is (= (.takesLORetO LOOadapter (long 1) exerciser) exerciser)) (is (= (.takesOLRetO OLOadapter exerciser (long 1)) exerciser)) @@ -350,19 +295,11 @@ AdapterExerciser$OOOOOOOOOOO (is (= (.takesOORetO OOOadapter exerciser exerciser) exerciser)) (is (= (.takesODRetO ODOadapter exerciser (double 1)) exerciser)) (is (= (.takesDORetO DOOadapter (double 1) exerciser) exerciser)) - (is (= (.takesOOORetZ OOOZadapter exerciser exerciser exerciser) false)) (is (= (.takesOOORetO OOOOadapter exerciser exerciser exerciser) exerciser)) - (is (= (.takesOOOORetZ OOOOZadapter exerciser exerciser exerciser exerciser) false)) (is (= (.takesOOOORetO OOOOOadapter exerciser exerciser exerciser exerciser) exerciser)) - (is (= (.takesOOOOORetZ OOOOOZadapter exerciser exerciser exerciser exerciser exerciser) false)) (is (= (.takesOOOOORetO OOOOOOadapter exerciser exerciser exerciser exerciser exerciser) exerciser)) - (is (= (.takesOOOOOORetZ OOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser) false)) (is (= (.takesOOOOOORetO OOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) - (is (= (.takesOOOOOOORetZ OOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) (is (= (.takesOOOOOOORetO OOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) - (is (= (.takesOOOOOOOORetZ OOOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) (is (= (.takesOOOOOOOORetO OOOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) - (is (= (.takesOOOOOOOOORetZ OOOOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) (is (= (.takesOOOOOOOOORetO OOOOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)) - (is (= (.takesOOOOOOOOOORetZ OOOOOOOOOOZadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) false)) (is (= (.takesOOOOOOOOOORetO OOOOOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser)))) \ No newline at end of file diff --git a/test/clojure/test_clojure/generated_functional_adapters_in_def.clj b/test/clojure/test_clojure/generated_functional_adapters_in_def.clj index 12e9c4e043..ba62daa7c7 100644 --- a/test/clojure/test_clojure/generated_functional_adapters_in_def.clj +++ b/test/clojure/test_clojure/generated_functional_adapters_in_def.clj @@ -18,8 +18,6 @@ (is (= (.methodD ^AdapterExerciser exerciser Dadapter) "D")) (def Fadapter (fn [] (float 1))) (is (= (.methodF ^AdapterExerciser exerciser Fadapter) "F")) - (def Zadapter (fn [] false)) - (is (= (.methodZ ^AdapterExerciser exerciser Zadapter) "Z")) (def Oadapter (fn [] exerciser)) (is (= (.methodO ^AdapterExerciser exerciser Oadapter) "O")) (def LLadapter (fn [^long a] (long 1))) @@ -58,12 +56,6 @@ (is (= (.methodDF ^AdapterExerciser exerciser DFadapter) "DF")) (def OFadapter (fn [^AdapterExerciser a] (float 1))) (is (= (.methodOF ^AdapterExerciser exerciser OFadapter) "OF")) - (def LZadapter (fn [^long a] false)) - (is (= (.methodLZ ^AdapterExerciser exerciser LZadapter) "LZ")) - (def DZadapter (fn [^double a] false)) - (is (= (.methodDZ ^AdapterExerciser exerciser DZadapter) "DZ")) - (def OZadapter (fn [^AdapterExerciser a] false)) - (is (= (.methodOZ ^AdapterExerciser exerciser OZadapter) "OZ")) (def LOadapter (fn [^long a] exerciser)) (is (= (.methodLO ^AdapterExerciser exerciser LOadapter) "LO")) (def DOadapter (fn [^double a] exerciser)) @@ -178,24 +170,6 @@ (is (= (.methodODF ^AdapterExerciser exerciser ODFadapter) "ODF")) (def DOFadapter (fn [^double a ^AdapterExerciser b] (float 1))) (is (= (.methodDOF ^AdapterExerciser exerciser DOFadapter) "DOF")) - (def LLZadapter (fn [^long a ^long b] false)) - (is (= (.methodLLZ ^AdapterExerciser exerciser LLZadapter) "LLZ")) - (def LOZadapter (fn [^long a ^AdapterExerciser b] false)) - (is (= (.methodLOZ ^AdapterExerciser exerciser LOZadapter) "LOZ")) - (def OLZadapter (fn [^AdapterExerciser a ^long b] false)) - (is (= (.methodOLZ ^AdapterExerciser exerciser OLZadapter) "OLZ")) - (def DDZadapter (fn [^double a ^double b] false)) - (is (= (.methodDDZ ^AdapterExerciser exerciser DDZadapter) "DDZ")) - (def LDZadapter (fn [^long a ^double b] false)) - (is (= (.methodLDZ ^AdapterExerciser exerciser LDZadapter) "LDZ")) - (def DLZadapter (fn [^double a ^long b] false)) - (is (= (.methodDLZ ^AdapterExerciser exerciser DLZadapter) "DLZ")) - (def OOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b] false)) - (is (= (.methodOOZ ^AdapterExerciser exerciser OOZadapter) "OOZ")) - (def ODZadapter (fn [^AdapterExerciser a ^double b] false)) - (is (= (.methodODZ ^AdapterExerciser exerciser ODZadapter) "ODZ")) - (def DOZadapter (fn [^double a ^AdapterExerciser b] false)) - (is (= (.methodDOZ ^AdapterExerciser exerciser DOZadapter) "DOZ")) (def LLOadapter (fn [^long a ^long b] exerciser)) (is (= (.methodLLO ^AdapterExerciser exerciser LLOadapter) "LLO")) (def LOOadapter (fn [^long a ^AdapterExerciser b] exerciser)) @@ -214,35 +188,19 @@ (is (= (.methodODO ^AdapterExerciser exerciser ODOadapter) "ODO")) (def DOOadapter (fn [^double a ^AdapterExerciser b] exerciser)) (is (= (.methodDOO ^AdapterExerciser exerciser DOOadapter) "DOO")) - (def OOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] false)) - (is (= (.methodOOOZ ^AdapterExerciser exerciser OOOZadapter) "OOOZ")) (def OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser)) (is (= (.methodOOOO ^AdapterExerciser exerciser OOOOadapter) "OOOO")) - (def OOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] false)) - (is (= (.methodOOOOZ ^AdapterExerciser exerciser OOOOZadapter) "OOOOZ")) (def OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser)) (is (= (.methodOOOOO ^AdapterExerciser exerciser OOOOOadapter) "OOOOO")) - (def OOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] false)) - (is (= (.methodOOOOOZ ^AdapterExerciser exerciser OOOOOZadapter) "OOOOOZ")) (def OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser)) (is (= (.methodOOOOOO ^AdapterExerciser exerciser OOOOOOadapter) "OOOOOO")) - (def OOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] false)) - (is (= (.methodOOOOOOZ ^AdapterExerciser exerciser OOOOOOZadapter) "OOOOOOZ")) (def OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser)) (is (= (.methodOOOOOOO ^AdapterExerciser exerciser OOOOOOOadapter) "OOOOOOO")) - (def OOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] false)) - (is (= (.methodOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOZadapter) "OOOOOOOZ")) (def OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser)) (is (= (.methodOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOadapter) "OOOOOOOO")) - (def OOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] false)) - (is (= (.methodOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOZadapter) "OOOOOOOOZ")) (def OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser)) (is (= (.methodOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOadapter) "OOOOOOOOO")) - (def OOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] false)) - (is (= (.methodOOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOOZadapter) "OOOOOOOOOZ")) (def OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser)) (is (= (.methodOOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOOadapter) "OOOOOOOOOO")) - (def OOOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] false)) - (is (= (.methodOOOOOOOOOOZ ^AdapterExerciser exerciser OOOOOOOOOOZadapter) "OOOOOOOOOOZ")) (def OOOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] exerciser)) (is (= (.methodOOOOOOOOOOO ^AdapterExerciser exerciser OOOOOOOOOOOadapter) "OOOOOOOOOOO"))) \ No newline at end of file diff --git a/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj b/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj index 5ddf78f542..7e6212c3ab 100644 --- a/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj +++ b/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj @@ -18,8 +18,6 @@ (is (= (.methodD exerciser Dadapter) "D")) (def Fadapter (fn [] (float 1))) (is (= (.methodF exerciser Fadapter) "F")) - (def Zadapter (fn [] false)) - (is (= (.methodZ exerciser Zadapter) "Z")) (def Oadapter (fn [] exerciser)) (is (= (.methodO exerciser Oadapter) "O")) (def LLadapter (fn [^long a] (long 1))) @@ -58,12 +56,6 @@ (is (= (.methodDF exerciser DFadapter) "DF")) (def OFadapter (fn [^AdapterExerciser a] (float 1))) (is (= (.methodOF exerciser OFadapter) "OF")) - (def LZadapter (fn [^long a] false)) - (is (= (.methodLZ exerciser LZadapter) "LZ")) - (def DZadapter (fn [^double a] false)) - (is (= (.methodDZ exerciser DZadapter) "DZ")) - (def OZadapter (fn [^AdapterExerciser a] false)) - (is (= (.methodOZ exerciser OZadapter) "OZ")) (def LOadapter (fn [^long a] exerciser)) (is (= (.methodLO exerciser LOadapter) "LO")) (def DOadapter (fn [^double a] exerciser)) @@ -178,24 +170,6 @@ (is (= (.methodODF exerciser ODFadapter) "ODF")) (def DOFadapter (fn [^double a ^AdapterExerciser b] (float 1))) (is (= (.methodDOF exerciser DOFadapter) "DOF")) - (def LLZadapter (fn [^long a ^long b] false)) - (is (= (.methodLLZ exerciser LLZadapter) "LLZ")) - (def LOZadapter (fn [^long a ^AdapterExerciser b] false)) - (is (= (.methodLOZ exerciser LOZadapter) "LOZ")) - (def OLZadapter (fn [^AdapterExerciser a ^long b] false)) - (is (= (.methodOLZ exerciser OLZadapter) "OLZ")) - (def DDZadapter (fn [^double a ^double b] false)) - (is (= (.methodDDZ exerciser DDZadapter) "DDZ")) - (def LDZadapter (fn [^long a ^double b] false)) - (is (= (.methodLDZ exerciser LDZadapter) "LDZ")) - (def DLZadapter (fn [^double a ^long b] false)) - (is (= (.methodDLZ exerciser DLZadapter) "DLZ")) - (def OOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b] false)) - (is (= (.methodOOZ exerciser OOZadapter) "OOZ")) - (def ODZadapter (fn [^AdapterExerciser a ^double b] false)) - (is (= (.methodODZ exerciser ODZadapter) "ODZ")) - (def DOZadapter (fn [^double a ^AdapterExerciser b] false)) - (is (= (.methodDOZ exerciser DOZadapter) "DOZ")) (def LLOadapter (fn [^long a ^long b] exerciser)) (is (= (.methodLLO exerciser LLOadapter) "LLO")) (def LOOadapter (fn [^long a ^AdapterExerciser b] exerciser)) @@ -214,35 +188,19 @@ (is (= (.methodODO exerciser ODOadapter) "ODO")) (def DOOadapter (fn [^double a ^AdapterExerciser b] exerciser)) (is (= (.methodDOO exerciser DOOadapter) "DOO")) - (def OOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] false)) - (is (= (.methodOOOZ exerciser OOOZadapter) "OOOZ")) (def OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser)) (is (= (.methodOOOO exerciser OOOOadapter) "OOOO")) - (def OOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] false)) - (is (= (.methodOOOOZ exerciser OOOOZadapter) "OOOOZ")) (def OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser)) (is (= (.methodOOOOO exerciser OOOOOadapter) "OOOOO")) - (def OOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] false)) - (is (= (.methodOOOOOZ exerciser OOOOOZadapter) "OOOOOZ")) (def OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser)) (is (= (.methodOOOOOO exerciser OOOOOOadapter) "OOOOOO")) - (def OOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] false)) - (is (= (.methodOOOOOOZ exerciser OOOOOOZadapter) "OOOOOOZ")) (def OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser)) (is (= (.methodOOOOOOO exerciser OOOOOOOadapter) "OOOOOOO")) - (def OOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] false)) - (is (= (.methodOOOOOOOZ exerciser OOOOOOOZadapter) "OOOOOOOZ")) (def OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser)) (is (= (.methodOOOOOOOO exerciser OOOOOOOOadapter) "OOOOOOOO")) - (def OOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] false)) - (is (= (.methodOOOOOOOOZ exerciser OOOOOOOOZadapter) "OOOOOOOOZ")) (def OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser)) (is (= (.methodOOOOOOOOO exerciser OOOOOOOOOadapter) "OOOOOOOOO")) - (def OOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] false)) - (is (= (.methodOOOOOOOOOZ exerciser OOOOOOOOOZadapter) "OOOOOOOOOZ")) (def OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser)) (is (= (.methodOOOOOOOOOO exerciser OOOOOOOOOOadapter) "OOOOOOOOOO")) - (def OOOOOOOOOOZadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] false)) - (is (= (.methodOOOOOOOOOOZ exerciser OOOOOOOOOOZadapter) "OOOOOOOOOOZ")) (def OOOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i ^AdapterExerciser j] exerciser)) (is (= (.methodOOOOOOOOOOO exerciser OOOOOOOOOOOadapter) "OOOOOOOOOOO"))) \ No newline at end of file diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj index 888a0d7efc..4a50388417 100644 --- a/test/clojure/test_clojure/java_interop.clj +++ b/test/clojure/test_clojure/java_interop.clj @@ -681,13 +681,7 @@ (let [coll (java.util.ArrayList. [1 2 3 4 5])] (is (true? (.removeIf coll even?))) (is (= coll [1 3 5]))) - - ;; pass Clojure set as Java predicate - function return - ;; should use Clojure semantics to return logical true - (let [coll (java.util.ArrayList. [1 2 3 4 5])] - (is (true? (.removeIf coll #{1 2}))) - (is (= coll [3 4 5]))) - + ;; binding type hint triggers coercion (is (instance? FileFilter (let [^FileFilter ff (fn [f] true)] ff))) @@ -845,7 +839,6 @@ (is (= "LLL" (AdapterExerciser/.methodLLL (AdapterExerciser.) (fn ^long [^long a ^long b])))) (is (= "OOOO" (AdapterExerciser/.methodOOOO (AdapterExerciser.) (fn ^long [^long a ^long b ^long c])))) - (is (= "OOOZ" (AdapterExerciser/.methodOOOZ (AdapterExerciser.) (fn [^long a ^long b ^long c])))) ) (deftest test-null-reify diff --git a/test/java/clojure/test/AdapterExerciser.java b/test/java/clojure/test/AdapterExerciser.java index e6d7e5e424..5e2758b1d7 100644 --- a/test/java/clojure/test/AdapterExerciser.java +++ b/test/java/clojure/test/AdapterExerciser.java @@ -27,10 +27,6 @@ public interface F { public float takesRetF(); } @FunctionalInterface - public interface Z { - public boolean takesRetZ(); - } - @FunctionalInterface public interface O { public AdapterExerciser takesRetO(); } @@ -107,18 +103,6 @@ public interface OF { public float takesORetF(AdapterExerciser a); } @FunctionalInterface - public interface LZ { - public boolean takesLRetZ(long a); - } - @FunctionalInterface - public interface DZ { - public boolean takesDRetZ(double a); - } - @FunctionalInterface - public interface OZ { - public boolean takesORetZ(AdapterExerciser a); - } - @FunctionalInterface public interface LO { public AdapterExerciser takesLRetO(long a); } @@ -347,42 +331,6 @@ public interface DOF { public float takesDORetF(double a, AdapterExerciser b); } @FunctionalInterface - public interface LLZ { - public boolean takesLLRetZ(long a, long b); - } - @FunctionalInterface - public interface LOZ { - public boolean takesLORetZ(long a, AdapterExerciser b); - } - @FunctionalInterface - public interface OLZ { - public boolean takesOLRetZ(AdapterExerciser a, long b); - } - @FunctionalInterface - public interface DDZ { - public boolean takesDDRetZ(double a, double b); - } - @FunctionalInterface - public interface LDZ { - public boolean takesLDRetZ(long a, double b); - } - @FunctionalInterface - public interface DLZ { - public boolean takesDLRetZ(double a, long b); - } - @FunctionalInterface - public interface OOZ { - public boolean takesOORetZ(AdapterExerciser a, AdapterExerciser b); - } - @FunctionalInterface - public interface ODZ { - public boolean takesODRetZ(AdapterExerciser a, double b); - } - @FunctionalInterface - public interface DOZ { - public boolean takesDORetZ(double a, AdapterExerciser b); - } - @FunctionalInterface public interface LLO { public AdapterExerciser takesLLRetO(long a, long b); } @@ -419,66 +367,34 @@ public interface DOO { public AdapterExerciser takesDORetO(double a, AdapterExerciser b); } @FunctionalInterface - public interface OOOZ { - public boolean takesOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c); - } - @FunctionalInterface public interface OOOO { public AdapterExerciser takesOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c); } @FunctionalInterface - public interface OOOOZ { - public boolean takesOOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d); - } - @FunctionalInterface public interface OOOOO { public AdapterExerciser takesOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d); } @FunctionalInterface - public interface OOOOOZ { - public boolean takesOOOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e); - } - @FunctionalInterface public interface OOOOOO { public AdapterExerciser takesOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e); } @FunctionalInterface - public interface OOOOOOZ { - public boolean takesOOOOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f); - } - @FunctionalInterface public interface OOOOOOO { public AdapterExerciser takesOOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f); } @FunctionalInterface - public interface OOOOOOOZ { - public boolean takesOOOOOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g); - } - @FunctionalInterface public interface OOOOOOOO { public AdapterExerciser takesOOOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g); } @FunctionalInterface - public interface OOOOOOOOZ { - public boolean takesOOOOOOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g, AdapterExerciser h); - } - @FunctionalInterface public interface OOOOOOOOO { public AdapterExerciser takesOOOOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g, AdapterExerciser h); } @FunctionalInterface - public interface OOOOOOOOOZ { - public boolean takesOOOOOOOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g, AdapterExerciser h, AdapterExerciser i); - } - @FunctionalInterface public interface OOOOOOOOOO { public AdapterExerciser takesOOOOOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g, AdapterExerciser h, AdapterExerciser i); } @FunctionalInterface - public interface OOOOOOOOOOZ { - public boolean takesOOOOOOOOOORetZ(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g, AdapterExerciser h, AdapterExerciser i, AdapterExerciser j); - } - @FunctionalInterface public interface OOOOOOOOOOO { public AdapterExerciser takesOOOOOOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g, AdapterExerciser h, AdapterExerciser i, AdapterExerciser j); } @@ -488,7 +404,6 @@ public interface OOOOOOOOOOO { public String methodB(B a) { return "B"; } public String methodD(D a) { return "D"; } public String methodF(F a) { return "F"; } - public String methodZ(Z a) { return "Z"; } public String methodO(O a) { return "O"; } public String methodLL(LL a) { return "LL"; } public String methodDL(DL a) { return "DL"; } @@ -508,9 +423,6 @@ public interface OOOOOOOOOOO { public String methodLF(LF a) { return "LF"; } public String methodDF(DF a) { return "DF"; } public String methodOF(OF a) { return "OF"; } - public String methodLZ(LZ a) { return "LZ"; } - public String methodDZ(DZ a) { return "DZ"; } - public String methodOZ(OZ a) { return "OZ"; } public String methodLO(LO a) { return "LO"; } public String methodDO(DO a) { return "DO"; } public String methodOO(OO a) { return "OO"; } @@ -568,15 +480,6 @@ public interface OOOOOOOOOOO { public String methodOOF(OOF a) { return "OOF"; } public String methodODF(ODF a) { return "ODF"; } public String methodDOF(DOF a) { return "DOF"; } - public String methodLLZ(LLZ a) { return "LLZ"; } - public String methodLOZ(LOZ a) { return "LOZ"; } - public String methodOLZ(OLZ a) { return "OLZ"; } - public String methodDDZ(DDZ a) { return "DDZ"; } - public String methodLDZ(LDZ a) { return "LDZ"; } - public String methodDLZ(DLZ a) { return "DLZ"; } - public String methodOOZ(OOZ a) { return "OOZ"; } - public String methodODZ(ODZ a) { return "ODZ"; } - public String methodDOZ(DOZ a) { return "DOZ"; } public String methodLLO(LLO a) { return "LLO"; } public String methodLOO(LOO a) { return "LOO"; } public String methodOLO(OLO a) { return "OLO"; } @@ -586,19 +489,11 @@ public interface OOOOOOOOOOO { public String methodOOO(OOO a) { return "OOO"; } public String methodODO(ODO a) { return "ODO"; } public String methodDOO(DOO a) { return "DOO"; } - public String methodOOOZ(OOOZ a) { return "OOOZ"; } public String methodOOOO(OOOO a) { return "OOOO"; } - public String methodOOOOZ(OOOOZ a) { return "OOOOZ"; } public String methodOOOOO(OOOOO a) { return "OOOOO"; } - public String methodOOOOOZ(OOOOOZ a) { return "OOOOOZ"; } public String methodOOOOOO(OOOOOO a) { return "OOOOOO"; } - public String methodOOOOOOZ(OOOOOOZ a) { return "OOOOOOZ"; } public String methodOOOOOOO(OOOOOOO a) { return "OOOOOOO"; } - public String methodOOOOOOOZ(OOOOOOOZ a) { return "OOOOOOOZ"; } public String methodOOOOOOOO(OOOOOOOO a) { return "OOOOOOOO"; } - public String methodOOOOOOOOZ(OOOOOOOOZ a) { return "OOOOOOOOZ"; } public String methodOOOOOOOOO(OOOOOOOOO a) { return "OOOOOOOOO"; } - public String methodOOOOOOOOOZ(OOOOOOOOOZ a) { return "OOOOOOOOOZ"; } public String methodOOOOOOOOOO(OOOOOOOOOO a) { return "OOOOOOOOOO"; } - public String methodOOOOOOOOOOZ(OOOOOOOOOOZ a) { return "OOOOOOOOOOZ"; } public String methodOOOOOOOOOOO(OOOOOOOOOOO a) { return "OOOOOOOOOOO"; }} \ No newline at end of file From 1692ac469f6279939a33cc40e395753eb3a86152 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Sat, 15 Jun 2024 14:50:06 +0000 Subject: [PATCH 229/285] [maven-release-plugin] prepare release clojure-1.12.0-beta1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index df07f56549..b10577ec08 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0-beta1 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0-beta1 From ee28f7f06d469b8e4f4eb48521ba51692146e774 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Sat, 15 Jun 2024 14:50:06 +0000 Subject: [PATCH 230/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b10577ec08..df07f56549 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-beta1 + 1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0-beta1 + HEAD From 8c8e4f6ef21f3d0f59deb60cdc7e1b584f596d59 Mon Sep 17 00:00:00 2001 From: Fogus Date: Tue, 2 Jul 2024 12:52:18 -0400 Subject: [PATCH 231/285] CLJ-2867: Convey tag on QME whenever it's present. --- src/jvm/clojure/lang/Compiler.java | 4 +++- test/clojure/test_clojure/method_thunks.clj | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 9a4c901546..0f89972c28 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1164,6 +1164,7 @@ static class QualifiedMethodExpr implements Expr { private final Symbol methodSymbol; private final String methodName; private final MethodKind kind; + private final Class tagClass; private enum MethodKind { CTOR, INSTANCE, STATIC @@ -1172,6 +1173,7 @@ private enum MethodKind { public QualifiedMethodExpr(Class methodClass, Symbol sym){ c = methodClass; methodSymbol = sym; + tagClass = tagOf(sym) != null ? HostExpr.tagToClass(tagOf(sym)) : AFn.class; hintedSig = tagsToClasses(paramTagsOf(sym)); if(sym.name.startsWith(".")) { kind = MethodKind.INSTANCE; @@ -1208,7 +1210,7 @@ public boolean hasJavaClass() { @Override public Class getJavaClass() { - return AFn.class; + return tagClass; } // TBD: caching/reuse of thunks diff --git a/test/clojure/test_clojure/method_thunks.clj b/test/clojure/test_clojure/method_thunks.clj index c70d833962..b999e539a4 100644 --- a/test/clojure/test_clojure/method_thunks.clj +++ b/test/clojure/test_clojure/method_thunks.clj @@ -9,8 +9,10 @@ (ns clojure.test-clojure.method-thunks (:use clojure.test) + (:require [clojure.java.io :as jio]) (:import (clojure.lang Compiler Tuple) (java.util Arrays UUID Locale) + (java.io File FileFilter) clojure.lang.IFn$LL)) (set! *warn-on-reflection* true) @@ -52,3 +54,9 @@ ((:fromString mts) "00000000-0000-0001-0000-000000000002"))) (is (= [1] (mt 1))) (is (= 97 (first (seq (gbs "a")))))) + +(deftest hinted-method-values + (is (thrown? Exception (eval '(.listFiles (jio/file ".") #(File/.isDirectory %))))) + (is (seq (.listFiles (jio/file ".") ^FileFilter File/.isDirectory))) + (is (seq (File/.listFiles (jio/file ".") ^FileFilter File/.isDirectory))) + (is (seq (^[FileFilter] File/.listFiles (jio/file ".") ^FileFilter File/.isDirectory)))) From 38958061a4cf3631c7e12e76251e49b0415f1810 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Sun, 28 Jul 2024 18:09:36 -0500 Subject: [PATCH 232/285] CLJ-2865 Correctly implement IBlockingDeref in process and simplify start to just return the Process --- src/clj/clojure/java/process.clj | 91 +++++++++++----------- src/clj/clojure/tools/deps/interop.clj | 6 +- test/clojure/test_clojure/java/process.clj | 5 +- 3 files changed, 56 insertions(+), 46 deletions(-) diff --git a/src/clj/clojure/java/process.clj b/src/clj/clojure/java/process.clj index 4355e5ec65..1a4d3b88bc 100644 --- a/src/clj/clojure/java/process.clj +++ b/src/clj/clojure/java/process.clj @@ -9,19 +9,15 @@ (ns clojure.java.process "A process invocation API wrapping the Java process API. - The primary function here is 'start' which starts a process and handles the - streams as directed. It returns a map that contains keys to access the streams - (if available) and the Java Process object. It is also deref-able to wait for - process exit. - - Use ‘slurp' to capture the output of a process stream, and 'ok?’ to wait for a - non-error exit. The 'exec' function handles the common case of `start'ing a - process, waiting for process exit, slurp, and return stdout." + The primary function is 'start' which starts a process and handles the + streams as directed. It returns the Process object. Use 'exit-ref' to wait + for completion and receive the exit value, and ‘stdout', 'stderr', 'stdin' + to access the process streams. The 'exec' function handles the common case + to 'start' a process, wait for process exit, and return stdout." (:require - [clojure.java.io :as jio] - [clojure.string :as str]) + [clojure.java.io :as jio]) (:import - [java.io StringWriter File] + [java.io File InputStream OutputStream] [java.lang ProcessBuilder ProcessBuilder$Redirect Process] [java.util List] [clojure.lang IDeref IBlockingDeref] @@ -67,11 +63,9 @@ :clear-env - if true, remove all inherited parent env vars :env - {env-var value} of environment variables to set (all strings) - Returns an ILookup containing the java.lang.Process in :process and the - streams :in :out :err. The map is also an IDeref that waits for process exit - and returns the exit code." + Returns the java.lang.Process." {:added "1.12"} - [& opts+args] + ^Process [& opts+args] (let [[opts command] (if (map? (first opts+args)) [(first opts+args) (rest opts+args)] [{} opts+args]) @@ -97,28 +91,36 @@ (when env (let [pb-env (.environment pb)] (run! (fn [[k v]] (.put pb-env k v)) env))) - (let [proc (.start pb) - m {:process proc - :in (.getOutputStream proc) - :out (.getInputStream proc) - :err (.getErrorStream proc)}] - (reify - clojure.lang.ILookup - (valAt [_ key] (get m key)) - (valAt [_ key not-found] (get m key not-found)) - - IDeref - (deref [_] (.waitFor proc)) - - IBlockingDeref - (deref [_ timeout unit] (.waitFor proc timeout unit)))))) - -(defn ok? - "Given the map returned from 'start', wait for the process to exit - and then return true on success" - {:added "1.12"} - [process-map] - (zero? (.waitFor ^Process (:process process-map)))) + (.start pb))) + +(defn stdin + "Given a process, return the stdin of the external process (an OutputStream)" + ^OutputStream [^Process process] + (.getOutputStream process)) + +(defn stdout + "Given a process, return the stdout of the external process (an InputStream)" + ^InputStream [^Process process] + (.getInputStream process)) + +(defn stderr + "Given a process, return the stderr of the external process (an InputStream)" + ^InputStream [^Process process] + (.getErrorStream process)) + +(defn exit-ref + "Given a Process (the output of 'start'), return a reference that can be + used to wait for process completion then returns the exit value." + [^Process process] + (reify + IDeref + (deref [_] (long (.waitFor process))) + + IBlockingDeref + (deref [_ timeout-ms timeout-val] + (if (.waitFor process timeout-ms java.util.concurrent.TimeUnit/MILLISECONDS) + (long (.exitValue process)) + timeout-val)))) ;; A thread factory for daemon threads (defonce ^:private io-thread-factory @@ -164,25 +166,26 @@ [(first opts+args) (rest opts+args)] [{} opts+args]) opts (merge {:err :inherit} opts)] - (let [state (apply start opts command) - captured (io-task #(slurp (:out state)))] - (if (ok? state) + (let [proc (apply start opts command) + captured (io-task #(slurp (stdout proc))) + exit (deref (exit-ref proc))] + (if (zero? exit) @captured - (throw (RuntimeException. (str "Process failed with exit=" (.exitValue ^Process (:process state))))))))) + (throw (RuntimeException. (str "Process failed with exit=" exit))))))) (comment ;; shell out and inherit the i/o (start {:out :inherit, :err :stdout} "ls" "-l") ;; write out and err to files, wait for process to exit, return exit code - @(start {:out (to-file "out") :err (to-file "err")} "ls" "-l") + @(exit-ref (start {:out (to-file "out") :err (to-file "err")} "ls" "-l")) ;; capture output to string - (-> (start "ls" "-l") :out slurp) + (-> (start "ls" "-l") stdout slurp) ;; with exec (exec "ls" "-l") ;; read input from file - (exec {:in (from-file "deps.edn")} "wc" "-l") + (-> (exec {:in (from-file "deps.edn")} "wc" "-l") clojure.string/trim parse-long) ) diff --git a/src/clj/clojure/tools/deps/interop.clj b/src/clj/clojure/tools/deps/interop.clj index 148ca80240..1602397f65 100644 --- a/src/clj/clojure/tools/deps/interop.clj +++ b/src/clj/clojure/tools/deps/interop.clj @@ -12,6 +12,8 @@ [clojure.edn :as edn] [clojure.java.io :as jio])) +(set! *warn-on-reflection* true) + (defn ^:dynamic invoke-tool "Invoke tool using Clojure CLI. Args (one of :tool-alias or :tool-name, and :fn are required): @@ -32,7 +34,9 @@ _ (when (:debug opts) (println "args" args)) command-strs ["clojure" (str "-T" (or tool-alias tool-name)) "-"] _ (when (:debug opts) (apply println "Invoking: " command-strs)) - {:keys [in out]} (apply proc/start command-strs)] + proc (apply proc/start command-strs) + in (proc/stdin proc) + out (proc/stdout proc)] (binding [*print-length* nil *print-level* nil *print-namespace-maps* false] diff --git a/test/clojure/test_clojure/java/process.clj b/test/clojure/test_clojure/java/process.clj index a36f211681..3e187d58ec 100644 --- a/test/clojure/test_clojure/java/process.clj +++ b/test/clojure/test_clojure/java/process.clj @@ -22,4 +22,7 @@ ;; redirect, then capture to string (is (not (str/blank? (p/exec {:err :stdout} "bash" "-c" "ls >&2"))))) - +(deftest test-process-deref + (is (zero? @(p/exit-ref (p/start "sleep" "1")))) + (is (zero? (deref (p/exit-ref (p/start "sleep" "1")) 2500 :timeout))) + (is (= :timeout (deref (p/exit-ref (p/start "sleep" "1")) 1 :timeout)))) From d1de868e66a8d46cae164202a0e9ca9e670df204 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 29 Jul 2024 13:25:51 -0500 Subject: [PATCH 233/285] CLJ-2819 invoke-tool - improved error handling --- src/clj/clojure/tools/deps/interop.clj | 41 ++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/clj/clojure/tools/deps/interop.clj b/src/clj/clojure/tools/deps/interop.clj index 1602397f65..0b6106801c 100644 --- a/src/clj/clojure/tools/deps/interop.clj +++ b/src/clj/clojure/tools/deps/interop.clj @@ -10,10 +10,34 @@ (:require [clojure.java.process :as proc] [clojure.edn :as edn] - [clojure.java.io :as jio])) + [clojure.java.io :as jio] + [clojure.string :as str])) (set! *warn-on-reflection* true) +(def ^:private build (atom nil)) + +(defn- cli-build + "Return CLI build number (a long) or nil if it can't be determined. + The build number is cached if found and subsequently read from cache." + [] + (or @build + (let [result (try + (proc/exec "clojure" "--version") + (catch Exception e "")) + ;; Version string: "Clojure CLI version 1.11.3.1463" + ;; Match MAJOR.MINOR.PATCH.BUILD and take a capture group just for the last BUILD part + version (-> (re-find #"[0-9]+\.[0-9]+\.[0-9]+\.([0-9]+)" result) (nth 1))] + (when version + (reset! build (parse-long version)))))) + +(defn- validate-version + [version] + (if version + (when (< version 1347) + (throw (RuntimeException. "Clojure CLI version is older than minimum required version, 1.11.1.1347. Please update to latest version."))) + (throw (ex-info "Clojure CLI version unknown, please install the latest version." {})))) + (defn ^:dynamic invoke-tool "Invoke tool using Clojure CLI. Args (one of :tool-alias or :tool-name, and :fn are required): @@ -29,14 +53,16 @@ :or {preserve-envelope false} :as opts}] (when-not (or tool-name tool-alias) (throw (ex-info "Either :tool-alias or :tool-name must be provided" (or opts {})))) - (when-not (symbol? fn) (throw (ex-info (str "fn should be a symbol " fn) (or opts {})))) + (when-not (symbol? fn) (throw (ex-info (str ":fn should be a symbol " fn) (or opts {})))) + (validate-version (cli-build)) (let [args (conj [fn] (assoc args :clojure.exec/invoke :fn)) _ (when (:debug opts) (println "args" args)) command-strs ["clojure" (str "-T" (or tool-alias tool-name)) "-"] _ (when (:debug opts) (apply println "Invoking: " command-strs)) proc (apply proc/start command-strs) in (proc/stdin proc) - out (proc/stdout proc)] + out (proc/stdout proc) + err (proc/stderr proc)] (binding [*print-length* nil *print-level* nil *print-namespace-maps* false] @@ -45,14 +71,19 @@ (doseq [a args] (.write w (pr-str a)) (.write w " "))))) - (let [envelope (edn/read-string (slurp out))] + (if-let [envelope (edn/read-string (slurp out))] (if preserve-envelope envelope (let [{:keys [tag val]} envelope parsed-val (edn/read-string val)] (if (= :ret tag) parsed-val - (throw (ex-info (:cause parsed-val) (or parsed-val {}))))))))) + (throw (ex-info (:cause parsed-val) (or parsed-val {})))))) + (let [err-str (slurp err) + err-msg (if (= "" err-str) "Unknown error invoking Clojure CLI" err-str)] + (throw (ex-info err-msg + {:command (str/join " " command-strs) + :in (str/join " " args)})))))) (comment ;; regular invocation, should return {:hi :there} From 38f59ccf82644a48f7cb3ba3192bc35f219a090a Mon Sep 17 00:00:00 2001 From: clojure-build Date: Mon, 29 Jul 2024 18:50:01 +0000 Subject: [PATCH 234/285] [maven-release-plugin] prepare release clojure-1.12.0-beta2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index df07f56549..c0e31673b9 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0-beta2 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0-beta2 From 7f236064d496235d0e00d2a7161ae5d9a28da5b9 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Mon, 29 Jul 2024 18:50:01 +0000 Subject: [PATCH 235/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c0e31673b9..df07f56549 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-beta2 + 1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0-beta2 + HEAD From 37b6f5a755f3d82295134a5419c7f3123013ef49 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 2 Aug 2024 07:26:18 -0500 Subject: [PATCH 236/285] CLJ-2145 Fix clearing of closed overs in ^:once fns, recur to head of :once fn cancels once --- src/jvm/clojure/lang/Compiler.java | 19 +++-- test/clojure/test_clojure/clearing.clj | 111 +++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 6 deletions(-) create mode 100644 test/clojure/test_clojure/clearing.clj diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 0f89972c28..fdb6f360bf 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -5860,9 +5860,8 @@ static FnMethod parse(ObjExpr objx, ISeq form, Object rettag) { method.line = lineDeref(); method.column = columnDeref(); //register as the current method and set up a new env frame - PathNode pnode = (PathNode) CLEAR_PATH.get(); - if(pnode == null) - pnode = new PathNode(PATHTYPE.PATH,null); + PathNode pnode = new PathNode(PATHTYPE.PATH,null); + method.clearRoot = pnode; Var.pushThreadBindings( RT.mapUniqueKeys( METHOD, method, @@ -6306,6 +6305,7 @@ abstract public static class ObjMethod{ boolean usesThis = false; PersistentHashSet localsUsedInCatchFinally = PersistentHashSet.EMPTY; protected IPersistentMap methodMeta; + PathNode clearRoot; public final IPersistentMap locals(){ @@ -6560,7 +6560,9 @@ public LocalBindingExpr(LocalBinding b, Symbol tag) } } - if(clearRoot == b.clearPathRoot) + ObjMethod method = ((ObjMethod) METHOD.deref()); + boolean closedOver = method.objx.closes.containsKey(b); + if(clearRoot == b.clearPathRoot || (closedOver && clearRoot == method.clearRoot)) { this.shouldClear = true; sites = RT.conj(sites,this); @@ -7181,6 +7183,11 @@ public Expr parse(C context, Object frm) { int column = columnDeref(); String source = (String) SOURCE.deref(); + // In :once fn, recur to head invalidates :once + ObjMethod method = (ObjMethod)METHOD.deref(); + if(method.objx.onceOnly && method.clearRoot == CLEAR_ROOT.deref()) + method.objx.onceOnly = false; + ISeq form = (ISeq) frm; IPersistentVector loopLocals = (IPersistentVector) LOOP_LOCALS.deref(); if(context != C.RETURN || loopLocals == null) @@ -8062,7 +8069,6 @@ static void closeOver(LocalBinding b, ObjMethod method){ } } - static LocalBinding referenceLocal(Symbol sym) { if(!LOCAL_ENV.isBound()) return null; @@ -8967,7 +8973,8 @@ static NewInstanceMethod parse(ObjExpr objx, ISeq form, Symbol thistag, method.line = lineDeref(); method.column = columnDeref(); //register as the current method and set up a new env frame - PathNode pnode = new PathNode(PATHTYPE.PATH, (PathNode) CLEAR_PATH.get()); + PathNode pnode = new PathNode(PATHTYPE.PATH, null); + method.clearRoot = pnode; Var.pushThreadBindings( RT.mapUniqueKeys( METHOD, method, diff --git a/test/clojure/test_clojure/clearing.clj b/test/clojure/test_clojure/clearing.clj new file mode 100644 index 0000000000..04e187a74c --- /dev/null +++ b/test/clojure/test_clojure/clearing.clj @@ -0,0 +1,111 @@ +; Copyright (c) Rich Hickey. All rights reserved. +; The use and distribution terms for this software are covered by the +; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) +; which can be found in the file epl-v10.html at the root of this distribution. +; By using this software in any fashion, you are agreeing to be bound by +; the terms of this license. +; You must not remove this notice, or any other, from this software. + +(ns clojure.test-clojure.clearing + (:import + [java.lang.reflect Field]) + (:require + [clojure.string :as str] + [clojure.test :refer :all])) + +(set! *warn-on-reflection* true) + +(defn fields + [o] + (.getDeclaredFields (class o))) + +(defn primitive? + [^Field field] + (.isPrimitive (.getType field))) + +(defn special-fn-field? + [^String field-name] + (or (= field-name "__meta") + (str/starts-with? field-name "__cached_class__") + (str/starts-with? field-name "const__") + (str/ends-with? field-name "__"))) + +(defn clearable-closed-overs + [fobj] + (->> (fields fobj) + (remove primitive?) ;; can't clear primitives + (remove #(special-fn-field? (.getName ^Field %))))) + +(defn private-field-value [^Object obj ^Field field] + (. field (setAccessible true)) + (. field (get obj))) + +;; Check whether all non-primitive closed-overs in a function are nil +(defn cleared? + [fobj] + (every? #(nil? (private-field-value fobj %)) (clearable-closed-overs fobj))) + +;; --- + +;; After invocation, check all closed-over non-primitive fields in a :once fn + +(defn check-clear + [f] + (is (not (cleared? f))) + (f) + (cleared? f)) + +(deftest test-clearing + (let [x :a] + ;; base case + (is (check-clear (^{:once true} fn* [] x))) + + ;; conditional above fn + (when true + (is (check-clear (^{:once true} fn* [] x)))) + (case x + :a (is (check-clear (^{:once true} fn* [] x)))) + + ;; loop above fn + (loop [] + (is (check-clear (^{:once true} fn* [] x)))) + + ;; conditional below fn + (is (check-clear (^{:once true} fn* [] (when true x)))) + + ;; loop below fn + (is (not (check-clear (^{:once true} fn* [] (loop [] x))))) + (is (not (check-clear (^{:once true} fn* [] (loop [] x) nil)))) + + ;; recur in :once below fn + (is (not (check-clear (^{:once true} fn* [] (if false (recur) x))))) + )) + +(deftest test-nested + (let [x :a] + ;; nested fns + (let [inner (^{:once true} fn* [] x) + outer (fn* [] inner)] + (is (not (check-clear outer))) ;; outer not :once + (is (check-clear inner))) + + (let [inner (^{:once true} fn* [] x) + outer (^{:once true} fn* [] inner)] + (is (check-clear outer)) + (is (check-clear inner))) + + (let [inner (^{:once true} fn* [] x) + middle (^{:once true} fn* [] inner) + outer (^{:once true} fn* [] middle)] + (is (check-clear outer)) + (is (check-clear middle)) + (is (check-clear inner))))) + +;; Repro from CLJ-2145 +(defn consume [x] (doseq [_ x] _)) +(defn call-and-keep [f] (f) f) +(defn repro [x] + (if true (call-and-keep (^:once fn* [] (consume x))))) +(deftest CLJ-2145-repro + (let [f (repro (range 100))] ;; 1e9 to exhaust + (is (cleared? f)))) \ No newline at end of file From 9a13d44a5b79bf50ba8c64392354e89652c30fcb Mon Sep 17 00:00:00 2001 From: clojure-build Date: Sat, 3 Aug 2024 17:09:48 +0000 Subject: [PATCH 237/285] [maven-release-plugin] prepare release clojure-1.12.0-rc1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index df07f56549..b74076217d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0-rc1 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0-rc1 From faeda7a552dcb8fe5faf8059ec5ab6421121bd51 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Sat, 3 Aug 2024 17:09:48 +0000 Subject: [PATCH 238/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b74076217d..df07f56549 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-rc1 + 1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0-rc1 + HEAD From 48b1fe5b50d48603f2c1fbd38223a7284520d1ed Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Sat, 3 Aug 2024 12:40:29 -0500 Subject: [PATCH 239/285] Update changelog for 1.12.0-rc1 --- changes.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/changes.md b/changes.md index 98dd69c5bd..d192386ef8 100644 --- a/changes.md +++ b/changes.md @@ -67,7 +67,7 @@ Clojure now includes [clojure.tools.deps.interop/invoke-tool](https://clojure.gi `add-lib` functionality is built using `invoke-tool` but you can also use it to build or invoke your own tools for interactive use. Find more about the function execution protocol on the [CLI reference](https://clojure.org/reference/clojure_cli#function_protocol). -See: [CLJ-2760](https://clojure.atlassian.net/browse/CLJ-2760) +See: [CLJ-2760](https://clojure.atlassian.net/browse/CLJ-2760), [CLJ-2819](https://clojure.atlassian.net/browse/CLJ-2819) ### 2.3 Start and control external processes @@ -76,7 +76,7 @@ For a long time, we've had the `clojure.java.shell` namespace, but over time Jav * [start](https://clojure.github.io/clojure/branch-master/clojure.java.process-api.html#clojure.java.process/start) - full control over streams with access to the underlying Java objects for advanced usage * [exec](https://clojure.github.io/clojure/branch-master/clojure.java.process-api.html#clojure.java.process/exec) - covers the common case of executing an external process and returning its stdout on completion -See: [CLJ-2759](https://clojure.atlassian.net/browse/CLJ-2759), [CLJ-2777](https://clojure.atlassian.net/browse/CLJ-2777), [CLJ-2828](https://clojure.atlassian.net/browse/CLJ-2828), [CLJ-2773](https://clojure.atlassian.net/browse/CLJ-2773), [CLJ-2776](https://clojure.atlassian.net/browse/CLJ-2776), [CLJ-2774](https://clojure.atlassian.net/browse/CLJ-2774), [CLJ-2778](https://clojure.atlassian.net/browse/CLJ-2778), [CLJ-2779](https://clojure.atlassian.net/browse/CLJ-2779) +See: [CLJ-2759](https://clojure.atlassian.net/browse/CLJ-2759), [CLJ-2777](https://clojure.atlassian.net/browse/CLJ-2777), [CLJ-2828](https://clojure.atlassian.net/browse/CLJ-2828), [CLJ-2773](https://clojure.atlassian.net/browse/CLJ-2773), [CLJ-2776](https://clojure.atlassian.net/browse/CLJ-2776), [CLJ-2774](https://clojure.atlassian.net/browse/CLJ-2774), [CLJ-2778](https://clojure.atlassian.net/browse/CLJ-2778), [CLJ-2779](https://clojure.atlassian.net/browse/CLJ-2779), [CLJ-2865](https://clojure.atlassian.net/browse/CLJ-2865) ### 2.4 Method values @@ -102,7 +102,7 @@ Qualified method invocations with [param-tags](#26-param-tags-metadata) use only Note: Static fields are values and should be referenced without parens unless they are intended as function calls, e.g `(System/out)` should be `System/out`. Future Clojure releases will treat the field's value as something invokable and invoke it. -See: [CLJ-2844](https://clojure.atlassian.net/browse/CLJ-2844), [CLJ-2848](https://clojure.atlassian.net/browse/CLJ-2848), [CLJ-2847](https://clojure.atlassian.net/browse/CLJ-2847), [CLJ-2853](https://clojure.atlassian.net/browse/CLJ-2853) +See: [CLJ-2844](https://clojure.atlassian.net/browse/CLJ-2844), [CLJ-2848](https://clojure.atlassian.net/browse/CLJ-2848), [CLJ-2847](https://clojure.atlassian.net/browse/CLJ-2847), [CLJ-2853](https://clojure.atlassian.net/browse/CLJ-2853), [CLJ-2867](https://clojure.atlassian.net/browse/CLJ-2867) ### 2.6 :param-tags metadata @@ -130,7 +130,7 @@ Java programs define "functions" with Java functional interfaces (marked with th Clojure developers can now invoke Java methods taking functional interfaces by passing functions with matching arity. The Clojure compiler implicitly converts Clojure functions to the required functional interface by constructing a lambda adapter. You can explicitly coerce a Clojure function to a functional interface by hinting the binding name in a `let` binding, e.g. to avoid repeated adapter construction in a loop, e.g. `(let [^java.util.function.Predicate p even?] ...)`. -See: [CLJ-2799](https://clojure.atlassian.net/browse/CLJ-2799), [CLJ-2858](https://clojure.atlassian.net/browse/CLJ-2858), [CLJ-2856](https://clojure.atlassian.net/browse/CLJ-2856) +See: [CLJ-2799](https://clojure.atlassian.net/browse/CLJ-2799), [CLJ-2858](https://clojure.atlassian.net/browse/CLJ-2858), [CLJ-2856](https://clojure.atlassian.net/browse/CLJ-2856), [CLJ-2863](https://clojure.atlassian.net/browse/CLJ-2863), [CLJ-2864](https://clojure.atlassian.net/browse/CLJ-2864) ### 2.9 Java Supplier interop @@ -182,6 +182,8 @@ See: [CLJ-2711](https://clojure.atlassian.net/browse/CLJ-2711) * [CLJ-2726](https://clojure.atlassian.net/browse/CLJ-2726) `#uuid` data reader - Fix exception on invalid input so it flows through reader * [CLJ-2813](https://clojure.atlassian.net/browse/CLJ-2813) anonymous function arg reader - no longer accepts invalid arg symbols * [CLJ-2843](https://clojure.atlassian.net/browse/CLJ-2843) Reflective calls to Java methods that take primitive long or double now work when passed a narrower boxed number at runtime (Integer, Short, Byte, Float). Previously, these methods were not matched during reflection and an error was thrown. +* [CLJ-2145](https://clojure.atlassian.net/browse/CLJ-2145) - Fix clearing of closed overs in `^:once` fns +* [CLJ-2317](https://clojure.atlassian.net/browse/CLJ-2317) - `recur` to head of `:once` fn cancels once ### 3.2 Core @@ -207,6 +209,11 @@ See: [CLJ-2711](https://clojure.atlassian.net/browse/CLJ-2711) * [CLJ-2552](https://clojure.atlassian.net/browse/CLJ-2552) `reify` - improve docstring and fix example * [CLJ-1385](https://clojure.atlassian.net/browse/CLJ-1385) `transient` - include usage model from reference docs +# Changes to Clojure in Version 1.11.4 + +* [CLJ-2145](https://clojure.atlassian.net/browse/CLJ-2145) - Fix clearing of closed overs in `^:once` fns +* [CLJ-2317](https://clojure.atlassian.net/browse/CLJ-2317) - `recur` to head of `:once` fn cancels once + # Changes to Clojure in Version 1.11.3 * [CLJ-2843](https://clojure.atlassian.net/browse/CLJ-2843) - Reflective calls to Java methods that take primitive long or double now work when passed a narrower boxed number at runtime (Integer, Short, Byte, Float). Previously, these methods were not matched during reflection and an error was thrown. From 5ae95872738b3e0aacfa5d38069d528b590a5059 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 26 Aug 2024 11:13:07 -0500 Subject: [PATCH 240/285] CLJ-2873 add-libs - reload *data-readers* if new libs were added --- src/clj/clojure/repl/deps.clj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/clj/clojure/repl/deps.clj b/src/clj/clojure/repl/deps.clj index dfd3137fcd..521e0f758f 100644 --- a/src/clj/clojure/repl/deps.clj +++ b/src/clj/clojure/repl/deps.clj @@ -51,6 +51,8 @@ urls (->> paths (map jio/file) (map #(RT/toUrl ^File %)))] (run! add-loader-url urls) (basis-impl/update-basis! update :libs merge added) + ;; reload root *data-readers* from classpath + (set! *data-readers* (merge (#'clojure.core/load-data-readers) *data-readers*)) (let [ret (-> added keys sort vec)] (when (seq ret) ret)))))) From ad54fecd0bdff38bde8ae057887ad8b724fdd661 Mon Sep 17 00:00:00 2001 From: Fogus Date: Wed, 28 Aug 2024 13:41:06 -0400 Subject: [PATCH 241/285] CLJ-2881: Making asm-type function array class symbol aware. --- src/clj/clojure/genclass.clj | 17 +++++++++-------- src/jvm/clojure/lang/Compiler.java | 2 +- test/clojure/test_clojure/array_symbols.clj | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/clj/clojure/genclass.clj b/src/clj/clojure/genclass.clj index a4fa0ec5fb..710e58a1a3 100644 --- a/src/clj/clojure/genclass.clj +++ b/src/clj/clojure/genclass.clj @@ -646,14 +646,15 @@ fully-qualified class name given as a string or symbol (such as 'java.lang.String)" [c] - (if (or (instance? Class c) (prim->class c)) - (Type/getType (the-class c)) - (let [strx (str c)] - (Type/getObjectType - (.replace (if (some #{\. \[} strx) - strx - (str "java.lang." strx)) - "." "/"))))) + (let [c (or (and (symbol? c) (clojure.lang.Compiler$HostExpr/maybeArrayClass c)) c)] + (if (or (instance? Class c) (prim->class c)) + (Type/getType (the-class c)) + (let [strx (str c)] + (Type/getObjectType + (.replace (if (some #{\. \[} strx) + strx + (str "java.lang." strx)) + "." "/")))))) (defn- generate-interface [{:keys [name extends methods]}] diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index fdb6f360bf..6324456fa1 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1124,7 +1124,7 @@ static Class tagToClass(Object tag) { throw new IllegalArgumentException("Unable to resolve classname: " + tag); } - static Class maybeArrayClass(Symbol sym) { + public static Class maybeArrayClass(Symbol sym) { if(sym.ns == null || !Util.isPosDigit(sym.name)) return null; diff --git a/test/clojure/test_clojure/array_symbols.clj b/test/clojure/test_clojure/array_symbols.clj index c9f94da309..7fb98743e3 100644 --- a/test/clojure/test_clojure/array_symbols.clj +++ b/test/clojure/test_clojure/array_symbols.clj @@ -65,3 +65,17 @@ (is (thrown? Exception (read-string "String/0"))) (is (thrown? Exception (read-string "String/42"))) (is (thrown? Exception (eval '(deftype Foo/2 [a])))))) + +(definterface ArrayClassSymbolFoo (^String/1 bar [])) +(definterface ArrayClassSymbolFooAsHint (^ArrayClassSymbolFoo/1 baz [])) + +(deftest test-definterface-acs + (testing "definterface" + (let [obj (reify ArrayClassSymbolFoo (bar [this] (into-array String ["a"])))] + (is (= ["a"] (seq (.bar obj))))) + (let [obj (reify ArrayClassSymbolFooAsHint + (baz [this] + (into-array ArrayClassSymbolFoo [(reify ArrayClassSymbolFoo + (bar [this] (into-array String ["a"])))])))] + (is (= ["a"] (let [^ArrayClassSymbolFoo acsf (first (.baz obj))] + (seq (.bar acsf)))))))) From b3bd4cdd325878ad9cec3410afb95041c0a61303 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Wed, 28 Aug 2024 18:18:06 +0000 Subject: [PATCH 242/285] [maven-release-plugin] prepare release clojure-1.12.0-rc2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index df07f56549..e6fa97d691 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0-rc2 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0-rc2 From 90e7dd03afa7740efe269fad41ceea220d31143d Mon Sep 17 00:00:00 2001 From: clojure-build Date: Wed, 28 Aug 2024 18:18:06 +0000 Subject: [PATCH 243/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e6fa97d691..df07f56549 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-rc2 + 1.12.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0-rc2 + HEAD From 23d0f989803d4312a6bacb8f9166ce7cb8a5cac6 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 28 Aug 2024 14:22:24 -0500 Subject: [PATCH 244/285] fix link in changelog --- changes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changes.md b/changes.md index d192386ef8..74de8277d9 100644 --- a/changes.md +++ b/changes.md @@ -61,7 +61,7 @@ See: [CLJ-2761](https://clojure.atlassian.net/browse/CLJ-2761), [CLJ-2757](https ### 2.2 Invoke tool functions out of process -There are many useful tools you can use at development time, but which are not part of your project's actual dependencies. The Clojure CLI provides explicit support for [tools](https://clojure.org/reference/clojure_cli#tool_install) with their own classpath, but there was not previously a way to invoke these interactively. +There are many useful tools you can use at development time, but which are not part of your project's actual dependencies. The Clojure CLI provides explicit support for [tools](https://clojure.org/reference/clojure_cli#tools) with their own classpath, but there was not previously a way to invoke these interactively. Clojure now includes [clojure.tools.deps.interop/invoke-tool](https://clojure.github.io/clojure/branch-master/clojure.tools.deps.interop-api.html#clojure.tools.deps.interop/invoke-tool) to invoke a tool function out of process. The classpath for the tool is defined in deps.edn and you do not need to add the tool's dependencies to your project classpath. From d4bb93f0d1ab2004f89c6ead1b32449fd7ed1a6d Mon Sep 17 00:00:00 2001 From: clojure-build Date: Thu, 5 Sep 2024 19:03:31 +0000 Subject: [PATCH 245/285] [maven-release-plugin] prepare release clojure-1.12.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index df07f56549..ccb0db1c40 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0-master-SNAPSHOT + 1.12.0 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.0 From 13a2f67b91ab81cd109ea3152fce1ae76d212453 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Thu, 5 Sep 2024 19:03:31 +0000 Subject: [PATCH 246/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ccb0db1c40..c587c770a7 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.0 + 1.13.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.0 + HEAD From 2bb190f790aa23fedaa53a6737c1f1dab473e52a Mon Sep 17 00:00:00 2001 From: Fogus Date: Mon, 2 Dec 2024 16:56:31 -0500 Subject: [PATCH 247/285] CLJ-2888: WiP --- src/clj/clojure/genclass.clj | 22 +++++++++++++++++++++- src/jvm/clojure/lang/Util.java | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/genclass.clj b/src/clj/clojure/genclass.clj index 710e58a1a3..df0b6befcd 100644 --- a/src/clj/clojure/genclass.clj +++ b/src/clj/clojure/genclass.clj @@ -101,7 +101,27 @@ 'char Character/TYPE 'chars (Class/forName "[C")}) -(defn- ^Class the-class [x] +(defn- maybe-array-descriptor [x] + (if-let [dim (and (symbol? x) + (namespace x) + (clojure.lang.Util/isPosDigit (name x)) + (-> x name (.charAt 0) int (- (int \0))))] + (let [cn (namespace x) + classname (if (some #{\.} cn) cn (str "java.lang." cn))] + (str (String/join "" ^Iterable (repeat dim "[")) "L" classname ";")) + (str x))) + +(defn- ^Class the-class [x] + (cond + (class? x) x + (contains? prim->class x) (prim->class x) + :else (let [strx (maybe-array-descriptor x)] + (clojure.lang.RT/classForName + (if (some #{\. \[} strx) + strx + (str "java.lang." strx)))))) + +#_(defn- ^Class the-class [x] (cond (class? x) x (contains? prim->class x) (prim->class x) diff --git a/src/jvm/clojure/lang/Util.java b/src/jvm/clojure/lang/Util.java index 11647f800c..a5ca27ec46 100644 --- a/src/jvm/clojure/lang/Util.java +++ b/src/jvm/clojure/lang/Util.java @@ -256,7 +256,7 @@ static public Object loadWithClass(String scriptbase, Class loadFrom) throws } } -static boolean isPosDigit(String s) { +public static boolean isPosDigit(String s) { if(s.length() != 1) return false; char ch = s.charAt(0); From 58d0225dc33e7e61837c63fd581f63b2f42a3886 Mon Sep 17 00:00:00 2001 From: Fogus Date: Mon, 2 Dec 2024 16:57:23 -0500 Subject: [PATCH 248/285] Revert "CLJ-2890: WiP" This reverts commit 2bb190f790aa23fedaa53a6737c1f1dab473e52a. --- src/clj/clojure/genclass.clj | 22 +--------------------- src/jvm/clojure/lang/Util.java | 2 +- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/src/clj/clojure/genclass.clj b/src/clj/clojure/genclass.clj index df0b6befcd..710e58a1a3 100644 --- a/src/clj/clojure/genclass.clj +++ b/src/clj/clojure/genclass.clj @@ -101,27 +101,7 @@ 'char Character/TYPE 'chars (Class/forName "[C")}) -(defn- maybe-array-descriptor [x] - (if-let [dim (and (symbol? x) - (namespace x) - (clojure.lang.Util/isPosDigit (name x)) - (-> x name (.charAt 0) int (- (int \0))))] - (let [cn (namespace x) - classname (if (some #{\.} cn) cn (str "java.lang." cn))] - (str (String/join "" ^Iterable (repeat dim "[")) "L" classname ";")) - (str x))) - -(defn- ^Class the-class [x] - (cond - (class? x) x - (contains? prim->class x) (prim->class x) - :else (let [strx (maybe-array-descriptor x)] - (clojure.lang.RT/classForName - (if (some #{\. \[} strx) - strx - (str "java.lang." strx)))))) - -#_(defn- ^Class the-class [x] +(defn- ^Class the-class [x] (cond (class? x) x (contains? prim->class x) (prim->class x) diff --git a/src/jvm/clojure/lang/Util.java b/src/jvm/clojure/lang/Util.java index a5ca27ec46..11647f800c 100644 --- a/src/jvm/clojure/lang/Util.java +++ b/src/jvm/clojure/lang/Util.java @@ -256,7 +256,7 @@ static public Object loadWithClass(String scriptbase, Class loadFrom) throws } } -public static boolean isPosDigit(String s) { +static boolean isPosDigit(String s) { if(s.length() != 1) return false; char ch = s.charAt(0); From fb22fd778a272b034684a4ee94509552b46ee8a9 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 10 Dec 2024 13:57:29 -0600 Subject: [PATCH 249/285] Use latest actions in CI doc-build workflow --- .github/workflows/doc-build.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 819cba1268..957f0059f2 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -15,18 +15,18 @@ jobs: steps: - name: Set up Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 8 distribution: 'temurin' - name: Set up Clojure - uses: DeLaGuardo/setup-clojure@11.0 + uses: DeLaGuardo/setup-clojure@13.1 with: cli: 'latest' - name: Cache clojure dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.m2/repository @@ -35,20 +35,20 @@ jobs: restore-keys: cljdeps- - name: Clone clojure api doc repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: clojure/clojure-api-doc path: clojure-api-doc fetch-depth: 0 - name: Clone clojure source code repo into clojure-api-doc - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: clojure-api-doc/repo fetch-depth: 0 - name: Clone clojure gh-pages branch into clojure-api-doc - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: clojure/clojure path: clojure-api-doc/repo-docs From ac32af4b55c3642e1c6e62c8b34695dd259c21c4 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Fri, 30 May 2025 15:59:08 -0500 Subject: [PATCH 250/285] update to new Maven Central publishing --- pom.xml | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index c587c770a7..1701a9dbf7 100644 --- a/pom.xml +++ b/pom.xml @@ -81,10 +81,13 @@ + + central + https://central.sonatype.com + - - sonatype-nexus-staging - https://oss.sonatype.org/content/repositories/snapshots + central-snapshot + https://central.sonatype.com/repository/maven-snapshots/ @@ -142,6 +145,7 @@ + org.codehaus.mojo build-helper-maven-plugin @@ -223,17 +227,15 @@ - + - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.13 + org.sonatype.central + central-publishing-maven-plugin + 0.7.0 true - - sonatype-nexus-staging - https://oss.sonatype.org/ - true + central + true From 9b0be8374c73a59278d8fafa6a301910e7f7ce29 Mon Sep 17 00:00:00 2001 From: Fogus Date: Tue, 20 May 2025 12:07:22 -0400 Subject: [PATCH 251/285] CLJ-2899: Defer the classification of a value-position qualified method call to catch the case where a static field shadows a method name. Additionally, reproduce the pre-1.12 error where non-overloaded field was used in invoke-position. --- src/jvm/clojure/lang/Compiler.java | 79 +++++++++++++++++------- test/clojure/test_clojure/param_tags.clj | 24 +++++++ test/java/clojure/test/SwissArmy.java | 8 ++- 3 files changed, 88 insertions(+), 23 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 6324456fa1..0bae0f6d54 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1165,12 +1165,17 @@ static class QualifiedMethodExpr implements Expr { private final String methodName; private final MethodKind kind; private final Class tagClass; + private final StaticFieldExpr fieldOverload; private enum MethodKind { CTOR, INSTANCE, STATIC } - public QualifiedMethodExpr(Class methodClass, Symbol sym){ + public QualifiedMethodExpr(Class methodClass, Symbol sym) { + this(methodClass, sym, null); + } + + public QualifiedMethodExpr(Class methodClass, Symbol sym, StaticFieldExpr fieldOL) { c = methodClass; methodSymbol = sym; tagClass = tagOf(sym) != null ? HostExpr.tagToClass(tagOf(sym)) : AFn.class; @@ -1187,18 +1192,29 @@ else if(sym.name.equals("new")) { kind = MethodKind.STATIC; methodName = sym.name; } + fieldOverload = fieldOL; + } + + private boolean preferOverloadedField() { + return fieldOverload != null && paramTagsOf(methodSymbol) == null; } // Expr impl - invocation, convert to fn expr @Override public Object eval() { - return buildThunk(C.EVAL, this).eval(); + if(preferOverloadedField()) + return fieldOverload.eval(); + else + return buildThunk(C.EVAL, this).eval(); } @Override public void emit(C context, ObjExpr objx, GeneratorAdapter gen) { - buildThunk(context, this).emit(context, objx, gen); + if(preferOverloadedField()) + fieldOverload.emit(context, objx, gen); + else + buildThunk(context, this).emit(context, objx, gen); } // Expr impl - method value, always an AFn @@ -1258,18 +1274,9 @@ private static Set aritySet(Class c, String methodName, MethodKind kind) { return res; } - // Returns a list of methods or ctors matching the name and kind given. - // Otherwise, will throw if the information provided results in no matches - private static List methodsWithName(Class c, String methodName, MethodKind kind) { - if (kind == MethodKind.CTOR) { - List ctors = Arrays.asList(c.getConstructors()); - if(ctors.isEmpty()) - throw noMethodWithNameException(c, methodName, kind); - return ctors; - } - + public static List methodOverloads(Class c, String methodName, MethodKind kind) { final Executable[] methods = c.getMethods(); - List res = Arrays.stream(methods) + return Arrays.stream(methods) .filter(m -> m.getName().equals(methodName)) .filter(m -> { switch(kind) { @@ -1279,6 +1286,19 @@ private static List methodsWithName(Class c, String methodName, Meth } }) .collect(Collectors.toList()); + } + + // Returns a list of methods or ctors matching the name and kind given. + // Otherwise, will throw if the information provided results in no matches + private static List methodsWithName(Class c, String methodName, MethodKind kind) { + if (kind == MethodKind.CTOR) { + List ctors = Arrays.asList(c.getConstructors()); + if(ctors.isEmpty()) + throw noMethodWithNameException(c, methodName, kind); + return ctors; + } + + List res = methodOverloads(c, methodName, kind); if(res.isEmpty()) throw noMethodWithNameException(c, methodName, kind); @@ -4115,7 +4135,7 @@ static Object sigTag(int argcount, Var v){ return tagOf(sig); } return null; - } + } public InvokeExpr(String source, int line, int column, Symbol tag, Expr fexpr, IPersistentVector args, boolean tailPosition) { this.source = source; @@ -4359,18 +4379,26 @@ static public Expr parse(C context, ISeq form) { (KeywordExpr) fexpr, target); } - // Preserving the existing static field bug that replaces a reference in parens with - // the field itself rather than trying to invoke the value in the field. This is - // an exception to the uniform Class/member qualification per CLJ-2806 ticket. - if(fexpr instanceof StaticFieldExpr) - return fexpr; - PersistentVector args = PersistentVector.EMPTY; for(ISeq s = RT.seq(form.next()); s != null; s = s.next()) { args = args.cons(analyze(context, s.first())); } + // Preserving the existing static field syntax that replaces a reference in parens with + // the field itself rather than trying to invoke the value in the field. This is + // an exception to the uniform Class/member qualification per CLJ-2806 ticket. + if(fexpr instanceof StaticFieldExpr) + { + if(RT.count(args) == 0) + return fexpr; + else + throw new IllegalArgumentException("No matching method " + + ((StaticFieldExpr) fexpr).fieldName + + " found taking " + RT.count(args) + " args for " + + ((StaticFieldExpr) fexpr).c); + } + if(fexpr instanceof QualifiedMethodExpr) return toHostExpr((QualifiedMethodExpr)fexpr, (String) SOURCE.deref(), lineDeref(), columnDeref(), tagOf(form), tailPosition, args); @@ -7830,7 +7858,14 @@ private static Expr analyzeSymbol(Symbol sym) { if(c != null) { if(Reflector.getField(c, sym.name, true) != null) - return new StaticFieldExpr(lineDeref(), columnDeref(), c, sym.name, tag); + { + List maybeOverloads = QualifiedMethodExpr.methodOverloads(c, sym.name, QualifiedMethodExpr.MethodKind.STATIC); + + if(maybeOverloads.isEmpty()) + return new StaticFieldExpr(lineDeref(), columnDeref(), c, sym.name, tag); + else + return new QualifiedMethodExpr(c, sym, new StaticFieldExpr(lineDeref(), columnDeref(), c, sym.name, tag)); + } else return new QualifiedMethodExpr(c, sym); } diff --git a/test/clojure/test_clojure/param_tags.clj b/test/clojure/test_clojure/param_tags.clj index fee2d1c53e..bccd3ef127 100644 --- a/test/clojure/test_clojure/param_tags.clj +++ b/test/clojure/test_clojure/param_tags.clj @@ -170,6 +170,30 @@ :instance (let [{:keys [expected actual]} (exercise-instance-method m)] (is (= expected actual)))))) +(deftest field-overloads-method-CLJ-2899-regression + (testing "overloaded in value position" + (is (= "static-field" clojure.test.SwissArmy/doppelganger))) + + (testing "overloaded in value position, w/paramtags" + (is (= "" (apply ^[] clojure.test.SwissArmy/doppelganger [])))) + + (testing "overloaded, invoke no args" + (is (= "" (clojure.test.SwissArmy/doppelganger)))) + + (testing "overloaded, invoke w/args" + (is (= "int-int-long" (clojure.test.SwissArmy/doppelganger (int 1) (int 2) (long 42))))) + + (testing "non-overloaded, field holds IFn, invoke w/args fails" + (is (thrown? Exception (eval '(clojure.test.SwissArmy/idFn 42)))) + (is (= #'clojure.core/identity clojure.test.SwissArmy/idFn))) + + (testing "non-overloaded, field holds IFn, invoke no args" + (is (= #'clojure.core/identity (clojure.test.SwissArmy/idFn)))) + + (testing "instance method overloads" + (is (= "int-int" (clojure.test.SwissArmy/.doppelganger (clojure.test.SwissArmy/new) (int 1) (int 2)))) + (is (= "int-int" (apply clojure.test.SwissArmy/.doppelganger (clojure.test.SwissArmy/new) (int 1) (int 2) []))))) + (defmacro arg-tags-called-in-macro [a-type b-type a b] `(^[~a-type ~b-type] SwissArmy/staticArityOverloadMethod ~a ~b)) diff --git a/test/java/clojure/test/SwissArmy.java b/test/java/clojure/test/SwissArmy.java index 339c3723c4..f38e2d44f5 100644 --- a/test/java/clojure/test/SwissArmy.java +++ b/test/java/clojure/test/SwissArmy.java @@ -1,7 +1,12 @@ package clojure.test; +import clojure.java.api.Clojure; +import clojure.lang.IFn; + public class SwissArmy { + public static String doppelganger = "static-field"; public String ctorId; + public static IFn idFn = Clojure.var("clojure.core", "identity"); public SwissArmy() {this.ctorId = "1";} public SwissArmy(int a, long b) {this.ctorId = "2";} @@ -36,4 +41,5 @@ public class SwissArmy { public static String staticArityOverloadMethod(int a, int b) {return "int-int";} public static String staticArityOverloadMethod(int a, int b, int c) {return "int-int-int";} public static String doppelganger(int a, int b, long c) {return "int-int-long";} -} \ No newline at end of file + public static String doppelganger() {return "";} +} From 6a3e0f02c6a96fcef2789e5da0bb80cd65405c03 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 4 Mar 2025 11:11:15 -0600 Subject: [PATCH 252/285] CLJ-2898 Add additional check to prevent FI conversion if object is both IFn and FI --- src/jvm/clojure/lang/Compiler.java | 11 ++++++---- src/jvm/clojure/lang/Reflector.java | 2 +- test/clojure/test_clojure/java_interop.clj | 25 ++++++++++++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 0bae0f6d54..04de5106b3 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1671,7 +1671,7 @@ private static Class toInvokerParamType(Class c) { * If targetClass is FI and has an adaptable functional method * Find fn invoker method matching adaptable method of FI * Emit bytecode for (expr is emitted): - * if(expr instanceof IFn) + * if(expr instanceof IFn && !(expr instanceof FI)) * invokeDynamic(targetMethod, fnInvokerImplMethod) * Else emit nothing */ @@ -1706,15 +1706,18 @@ static boolean maybeEmitFIAdapter(ObjExpr objx, GeneratorAdapter gen, Expr expr, try { java.lang.reflect.Method fnInvokerMethod = FnInvokers.class.getMethod(invokerMethodName, invokerParams); - // if(exp instanceof IFn) { emitInvokeDynamic(targetMethod, fnInvokerMethod) } + // if not (expr instanceof IFn), go to end label expr.emit(C.EXPRESSION, objx, gen); gen.dup(); gen.instanceOf(ifnType); - - // if not instanceof IFn, go to end Label endLabel = gen.newLabel(); gen.ifZCmp(Opcodes.IFEQ, endLabel); + // if (expr instanceof FI), go to end label + gen.dup(); + gen.instanceOf(samType); + gen.ifZCmp(Opcodes.IFNE, endLabel); + // else adapt fn invoker method as impl for target method emitInvokeDynamicAdapter(gen, targetClass, targetMethod, FnInvokers.class, fnInvokerMethod); diff --git a/src/jvm/clojure/lang/Reflector.java b/src/jvm/clojure/lang/Reflector.java index 133cb588f8..14cef154b9 100644 --- a/src/jvm/clojure/lang/Reflector.java +++ b/src/jvm/clojure/lang/Reflector.java @@ -592,7 +592,7 @@ private static Object coerceAdapterReturn(Object ret, Class targetType) { } static Object boxArg(Class paramType, Object arg){ - if(arg instanceof IFn && Compiler.FISupport.maybeFIMethod(paramType) != null) + if(arg instanceof IFn && Compiler.FISupport.maybeFIMethod(paramType) != null && !(paramType.isInstance(arg))) // Adapt IFn obj to targetType using dynamic proxy return Proxy.newProxyInstance(RT.baseLoader(), new Class[]{paramType}, diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj index 4a50388417..db471566e3 100644 --- a/test/clojure/test_clojure/java_interop.clj +++ b/test/clojure/test_clojure/java_interop.clj @@ -859,3 +859,28 @@ (testing "Static method accepting FI arg, provided overloaded static class FI" (is (= \S (FunctionalTester/staticMethodWithFIArg "Static" 0 FunctionalTester/getChar))))) + +;; call is reflective and one overload takes an FI (Supplier) +(definterface TakesFIOverloaded + (call [^java.util.function.Supplier s]) + (call [^String s])) + +(deftest CLJ-2898-reified-objs-both-IFn-and-FI + ;; f is both IFn and FI (Supplier) + (let [f (reify + java.util.function.Supplier + (get [_] 100) + + clojure.lang.IFn + (applyTo [_ _] 201) + (invoke [_] 200))] + + ;; should not be adapted. use Supplier.get() impl on tl + (is (= 100 (.get (ThreadLocal/withInitial f)))) + + (let [tfio (reify TakesFIOverloaded + (call [_ ^java.util.function.Supplier o] (.get o)) + (call [_ ^String s] "string"))] + ;; reflective call to TakesFIOverloaded.call() + ;; as above, should not be adapted and use Supplier.get() + (is (= 100 (.call tfio (identity f))))))) \ No newline at end of file From 641933ea85ea83d475aaeaa2303779bd29223fa1 Mon Sep 17 00:00:00 2001 From: Fogus Date: Mon, 13 Jan 2025 09:09:09 -0500 Subject: [PATCH 253/285] CLJ-2888: Adding support for array symbols to gen-class. Retains existing gen-class constraints around unqualified symbols defaulting to java.lang package qualification. --- src/clj/clojure/genclass.clj | 29 ++++++++++++++++++-------- src/jvm/clojure/lang/Compiler.java | 20 ++++++++++++------ test/clojure/test_clojure/genclass.clj | 10 +++++++++ 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/clj/clojure/genclass.clj b/src/clj/clojure/genclass.clj index 710e58a1a3..afef85c8ef 100644 --- a/src/clj/clojure/genclass.clj +++ b/src/clj/clojure/genclass.clj @@ -101,15 +101,26 @@ 'char Character/TYPE 'chars (Class/forName "[C")}) -(defn- ^Class the-class [x] - (cond - (class? x) x - (contains? prim->class x) (prim->class x) - :else (let [strx (str x)] - (clojure.lang.RT/classForName - (if (some #{\. \[} strx) - strx - (str "java.lang." strx)))))) +(defn- the-array-class [sym] + (clojure.lang.RT/classForName + (let [cn (namespace sym)] + (clojure.lang.Compiler$HostExpr/buildArrayClassDescriptor + (if (or (clojure.lang.Compiler/primClass (symbol cn)) (some #{\.} cn)) + sym + (symbol (str "java.lang." cn) (name sym))))))) + +(defn- ^Class the-class [x] + (cond + (class? x) x + (symbol? x) (cond (contains? prim->class x) (prim->class x) + (clojure.lang.Compiler$HostExpr/looksLikeArrayClass x) + (the-array-class x) + :else (let [strx (str x)] + (clojure.lang.RT/classForName + (if (some #{\. \[} strx) + strx + (str "java.lang." strx))))) + :else (clojure.lang.RT/classForName x))) ;; someday this can be made codepoint aware (defn- valid-java-method-name diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 04de5106b3..82efa822ef 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1124,10 +1124,11 @@ static Class tagToClass(Object tag) { throw new IllegalArgumentException("Unable to resolve classname: " + tag); } - public static Class maybeArrayClass(Symbol sym) { - if(sym.ns == null || !Util.isPosDigit(sym.name)) - return null; + public static boolean looksLikeArrayClass(Symbol sym) { + return sym.ns != null && Util.isPosDigit(sym.name); + } + public static String buildArrayClassDescriptor(Symbol sym) { int dim = sym.name.charAt(0) - '0'; Symbol componentClassName = Symbol.intern(null, sym.ns); Class componentClass = primClass(componentClassName); @@ -1137,7 +1138,7 @@ public static Class maybeArrayClass(Symbol sym) { if(componentClass == null) throw Util.sneakyThrow(new ClassNotFoundException("Unable to resolve component classname: " - + componentClassName)); + + componentClassName)); StringBuilder arrayDescriptor = new StringBuilder(); @@ -1149,7 +1150,14 @@ public static Class maybeArrayClass(Symbol sym) { : "L" + componentClass.getName() + ";"; arrayDescriptor.append(ccDescr); - return maybeClass(arrayDescriptor.toString(), true); + return arrayDescriptor.toString(); + } + + public static Class maybeArrayClass(Symbol sym) { + if(!looksLikeArrayClass(sym)) + return null; + + return maybeClass(buildArrayClassDescriptor(sym), true); } } @@ -9222,7 +9230,7 @@ static Class retType(Class tc, Class ret){ return tc; } - static Class primClass(Symbol sym){ + public static Class primClass(Symbol sym){ if(sym == null) return null; Class c = null; diff --git a/test/clojure/test_clojure/genclass.clj b/test/clojure/test_clojure/genclass.clj index 18e808dc11..48ad866365 100644 --- a/test/clojure/test_clojure/genclass.clj +++ b/test/clojure/test_clojure/genclass.clj @@ -149,3 +149,13 @@ (visitSource [source debug] (.append sourceFile source)))] (.accept classReader sourceVisitor 0) (is (= "examples.clj" (str sourceFile))))) + +(deftest array-descriptors->class + (are [descr c] (= (#'clojure.core/the-class descr) c) + "[Ljava.util.UUID;" java.util.UUID/1 + 'String java.lang.String + 'String/1 java.lang.String/1 + 'java.util.UUID java.util.UUID + 'java.util.UUID/2 java.util.UUID/2 + 'int/1 int/1 + 'boolean/9 boolean/9)) From afbd2098bf741234ec9efaa25480d02b14863e8c Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 14 Apr 2025 15:32:48 -0500 Subject: [PATCH 254/285] CLJ-2906 Add missing :metadata to new functions in 1.12 --- src/clj/clojure/java/process.clj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/clj/clojure/java/process.clj b/src/clj/clojure/java/process.clj index 1a4d3b88bc..734e125797 100644 --- a/src/clj/clojure/java/process.clj +++ b/src/clj/clojure/java/process.clj @@ -95,22 +95,26 @@ (defn stdin "Given a process, return the stdin of the external process (an OutputStream)" + {:added "1.12"} ^OutputStream [^Process process] (.getOutputStream process)) (defn stdout "Given a process, return the stdout of the external process (an InputStream)" + {:added "1.12"} ^InputStream [^Process process] (.getInputStream process)) (defn stderr "Given a process, return the stderr of the external process (an InputStream)" + {:added "1.12"} ^InputStream [^Process process] (.getErrorStream process)) (defn exit-ref "Given a Process (the output of 'start'), return a reference that can be used to wait for process completion then returns the exit value." + {:added "1.12"} [^Process process] (reify IDeref From be32516234961396581685b485ed8a88f8fe17e6 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 20 May 2025 13:59:02 -0500 Subject: [PATCH 255/285] CLJ-2886 add-libs not correctly removing non-procurer keys in tool call --- src/clj/clojure/repl/deps.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clj/clojure/repl/deps.clj b/src/clj/clojure/repl/deps.clj index 521e0f758f..64b22c713d 100644 --- a/src/clj/clojure/repl/deps.clj +++ b/src/clj/clojure/repl/deps.clj @@ -43,7 +43,7 @@ lib-coords (reduce-kv #(if (contains? current-libs %2) %1 (assoc %1 %2 %3)) {} lib-coords)] (when-not (empty? lib-coords) - (let [procurer (dissoc basis [:basis-config :paths :deps :aliases :argmap :classpath :classpath-roots]) + (let [procurer (reduce-kv (fn [m k v] (if (contains? #{"mvn" "git" "local"} (namespace k)) (assoc m k v) m)) {} basis) tool-args {:existing libs, :add lib-coords, :procurer procurer} {:keys [added] :as _res} (tool/invoke-tool {:tool-alias :deps, :fn 'clojure.tools.deps/resolve-added-libs, :args tool-args}) ;_ (clojure.pprint/pprint _res) From a5a61b6ffc465a401214a050fa776f09363dc1e7 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 2 Jun 2025 07:55:34 -0500 Subject: [PATCH 256/285] Update changelog for 1.12.1 --- changes.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/changes.md b/changes.md index 74de8277d9..cd0ec6a5eb 100644 --- a/changes.md +++ b/changes.md @@ -1,5 +1,13 @@ +# Changes to Clojure in Version 1.12.1 + +* [CLJ-2899](https://clojure.atlassian.net/browse/CLJ-2899) - Revert change in semantics of qualified symbol in invocation position if field and method of same name +* [CLJ-2898](https://clojure.atlassian.net/browse/CLJ-2898) - Objects that are both IFn and FunctionalInterface unnecessarily get converted to FI +* [CLJ-2888](https://clojure.atlassian.net/browse/CLJ-2888) - `gen-class` - did not support new array class symbol syntax +* [CLJ-2886](https://clojure.atlassian.net/browse/CLJ-2886) - `add-libs` - send only procurer keys to tool invocation +* [CLJ-2906](https://clojure.atlassian.net/browse/CLJ-2906) - Add missing :added metadata to 1.12 functions + # Changes to Clojure in Version 1.12.0 ## 1 Compatibility From ac2d2943a73c3e1821c8d1add7976a3f3b8d795d Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 2 Jun 2025 09:07:29 -0500 Subject: [PATCH 257/285] Update pom to create and attach javadoc jar --- pom.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pom.xml b/pom.xml index 1701a9dbf7..3f8637f5bf 100644 --- a/pom.xml +++ b/pom.xml @@ -227,6 +227,24 @@ + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.11.2 + + + attach-javadocs + + jar + + + + + none + + + org.sonatype.central From d129746598258bc8e264e1f78f8d000021c36d35 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Mon, 2 Jun 2025 14:10:11 +0000 Subject: [PATCH 258/285] [maven-release-plugin] prepare release clojure-1.12.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3f8637f5bf..910378aa82 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.13.0-master-SNAPSHOT + 1.12.1 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.1 From 251459b13852247cc48fbd19efbd53a02539b812 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Mon, 2 Jun 2025 14:10:11 +0000 Subject: [PATCH 259/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 910378aa82..3f8637f5bf 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.1 + 1.13.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.1 + HEAD From da1c748123c80fa3e82e24fc8e24a950a3ebccd9 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 4 Jun 2025 10:59:45 -0500 Subject: [PATCH 260/285] remove Ant build instructions from readme --- readme.txt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/readme.txt b/readme.txt index f91653f8b5..12fa75dea8 100644 --- a/readme.txt +++ b/readme.txt @@ -11,14 +11,11 @@ Docs: https://clojure.org Feedback: https://ask.clojure.org Getting Started: https://clojure.org/guides/getting_started -To build and run locally with Ant: - - One-time setup: ./antsetup.sh - To build: ant local - To run: java -jar clojure.jar - To build locally with Maven: + To test: + mvn test + To build (output JARs in target/): mvn package From 3296c3c0de6f32525fff1a5fab258a1e6a1d80ff Mon Sep 17 00:00:00 2001 From: Noah Bogart Date: Mon, 30 Jun 2025 11:22:22 -0400 Subject: [PATCH 261/285] CLJ-2914: Throw if QualifiedMethodExpr given no target --- src/jvm/clojure/lang/Compiler.java | 14 +++++++++++++- test/clojure/test_clojure/java_interop.clj | 7 ++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 82efa822ef..28d3ab9e8f 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1342,6 +1342,13 @@ static IllegalArgumentException paramTagsDontResolveException(Class c, String me + " insufficient to resolve " + methodDescription(c, methodName)); } + + public static IllegalArgumentException instanceNoTargetException(QualifiedMethodExpr qmexpr) { + return new IllegalArgumentException( + "Malformed method expression, expecting (" + + qmexpr.c.getName() + "/." + qmexpr.methodName + + " target ...)"); + } } final static Symbol PARAM_TAG_ANY = Symbol.intern(null, "_"); @@ -4411,7 +4418,12 @@ static public Expr parse(C context, ISeq form) { } if(fexpr instanceof QualifiedMethodExpr) - return toHostExpr((QualifiedMethodExpr)fexpr, (String) SOURCE.deref(), lineDeref(), columnDeref(), tagOf(form), tailPosition, args); + { + QualifiedMethodExpr qmexpr = (QualifiedMethodExpr)fexpr; + if (qmexpr.kind == QualifiedMethodExpr.MethodKind.INSTANCE && RT.count(args) == 0) + throw QualifiedMethodExpr.instanceNoTargetException(qmexpr); + return toHostExpr(qmexpr, (String) SOURCE.deref(), lineDeref(), columnDeref(), tagOf(form), tailPosition, args); + } // if(args.count() > MAX_POSITIONAL_ARITY) // throw new IllegalArgumentException( diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj index db471566e3..3b28cafadc 100644 --- a/test/clojure/test_clojure/java_interop.clj +++ b/test/clojure/test_clojure/java_interop.clj @@ -883,4 +883,9 @@ (call [_ ^String s] "string"))] ;; reflective call to TakesFIOverloaded.call() ;; as above, should not be adapted and use Supplier.get() - (is (= 100 (.call tfio (identity f))))))) \ No newline at end of file + (is (= 100 (.call tfio (identity f))))))) + +(deftest CLJ-2914-Qualified-Method-Expr-NPE + (is (fails-with-cause? IllegalArgumentException + #"Malformed method expression.*String/\.length" + (eval '(fn [] (java.lang.String/.length)))))) From d433ceb701a0a4a141567514ec698e5286c9dc3b Mon Sep 17 00:00:00 2001 From: dennis zhuang Date: Thu, 13 Aug 2015 14:00:37 +0800 Subject: [PATCH 262/285] Set retryex to be static in LockingTransaction. --- src/jvm/clojure/lang/LockingTransaction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jvm/clojure/lang/LockingTransaction.java b/src/jvm/clojure/lang/LockingTransaction.java index c28d2b2c9d..e76e90418d 100644 --- a/src/jvm/clojure/lang/LockingTransaction.java +++ b/src/jvm/clojure/lang/LockingTransaction.java @@ -102,7 +102,7 @@ void stop(int status){ long readPoint; long startPoint; long startTime; -final RetryEx retryex = new RetryEx(); +static final RetryEx retryex = new RetryEx(); final ArrayList actions = new ArrayList(); final HashMap vals = new HashMap(); final HashSet sets = new HashSet(); From 25e8f4eba2a127dc2cd64c7782f3f0ace83f08b9 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 17 Jul 2025 16:45:10 -0500 Subject: [PATCH 263/285] CLJ-2916 LazySeq - realize before serializing and do not serialize IFn --- src/jvm/clojure/lang/LazySeq.java | 14 ++++++++++++-- test/clojure/test_clojure/serialization.clj | 4 ++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/jvm/clojure/lang/LazySeq.java b/src/jvm/clojure/lang/LazySeq.java index 5c243c1ebb..26ad7be198 100644 --- a/src/jvm/clojure/lang/LazySeq.java +++ b/src/jvm/clojure/lang/LazySeq.java @@ -20,9 +20,9 @@ public final class LazySeq extends Obj implements ISeq, Sequential, List, IPending, IHashEq{ -private static final long serialVersionUID = -7345643944998411680L; +private static final long serialVersionUID = -7531333024710395876L; -private IFn fn; +private transient IFn fn; private Object sv; private ISeq s; private Lock lock; @@ -300,5 +300,15 @@ public boolean isRealized(){ } return true; } + +// custom Serializable implementation - ensure seq is fully-realized before writing +private void writeObject(java.io.ObjectOutputStream out) throws IOException { + ISeq s = this; + while(s != null) { + s = s.next(); + } + out.defaultWriteObject(); +} + } diff --git a/test/clojure/test_clojure/serialization.clj b/test/clojure/test_clojure/serialization.clj index c9befc49cd..bce7013675 100644 --- a/test/clojure/test_clojure/serialization.clj +++ b/test/clojure/test_clojure/serialization.clj @@ -92,6 +92,7 @@ ; lazy seqs (lazy-seq nil) (lazy-seq (list* (range 50))) + (iterator-seq (.iterator (range 50))) ; transient / persistent! round-trip (build-via-transient []) @@ -182,8 +183,7 @@ (agent nil) ;; stateful seqs - (enumeration-seq (java.util.Collections/enumeration (range 50))) - (iterator-seq (.iterator (range 50))))) + (enumeration-seq (java.util.Collections/enumeration (range 50))))) ;; necessary for CVE-2024-22871 (deftest CLJ-2839 From 99819d670ab03d9b7314abf35456b305044f14ab Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 23 Jul 2025 12:09:11 -0500 Subject: [PATCH 264/285] CLJ-2917 Iterate - throw when serializing or deserializing --- src/jvm/clojure/lang/Iterate.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/jvm/clojure/lang/Iterate.java b/src/jvm/clojure/lang/Iterate.java index 9cffa92080..a0562bce49 100644 --- a/src/jvm/clojure/lang/Iterate.java +++ b/src/jvm/clojure/lang/Iterate.java @@ -12,6 +12,8 @@ /* Alex Miller, Dec 5, 2014 */ +import java.io.IOException; + public class Iterate extends ASeq implements IReduce, IPending { private static final long serialVersionUID = -78221705247226450L; @@ -94,4 +96,15 @@ public int hashCode(){ public int hasheq(){ throw new UnsupportedOperationException(); } + +// serialization not supported +private void writeObject(java.io.ObjectOutputStream out) throws IOException { + throw new UnsupportedOperationException(); +} + +// deserialization not supported +private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + throw new UnsupportedOperationException(); +} + } From 89376e44936c75f6f2f782438818a6e3f478b1dd Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Mon, 25 Aug 2025 14:18:11 -0500 Subject: [PATCH 265/285] update changelog for 1.12.2 --- changes.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/changes.md b/changes.md index cd0ec6a5eb..671d320ecf 100644 --- a/changes.md +++ b/changes.md @@ -1,5 +1,12 @@ +# Changes to Clojure in Version 1.12.2 + +* [CLJ-2914](https://clojure.atlassian.net/browse/CLJ-2914) - Compiler - syntax error if qualified instance method expression is missing instance +* [CLJ-1798](https://clojure.atlassian.net/browse/CLJ-1798) - Refs - avoid creating RetryEx in LockingTransaction on every transaction +* [CLJ-2916](https://clojure.atlassian.net/browse/CLJ-2916) - LazySeq - realize before serializing and do not serialize IFn +* [CLJ-2917](https://clojure.atlassian.net/browse/CLJ-2917) - Iterate - de/serialization no longer supported, throw + # Changes to Clojure in Version 1.12.1 * [CLJ-2899](https://clojure.atlassian.net/browse/CLJ-2899) - Revert change in semantics of qualified symbol in invocation position if field and method of same name From b76edf6a81914bab6a81b8283cabd3e34603e752 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Mon, 25 Aug 2025 21:36:57 +0000 Subject: [PATCH 266/285] [maven-release-plugin] prepare release clojure-1.12.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3f8637f5bf..043fdea2dc 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.13.0-master-SNAPSHOT + 1.12.2 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.2 From b775c8a289339b4a8fb3f1800a017147c53b0b42 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Mon, 25 Aug 2025 21:36:57 +0000 Subject: [PATCH 267/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 043fdea2dc..3f8637f5bf 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.2 + 1.13.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.2 + HEAD From 07d289c1c684e7efb904ec9d68304d29f1ae1559 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 17 Sep 2025 14:49:26 -0500 Subject: [PATCH 268/285] CLJ-2919 Compiler - in callsite optimization, use null instead of bound-ness as condition for registering, and push null on compile() to reset state for nested compilation --- src/jvm/clojure/lang/Compiler.java | 61 ++++++++++++++++-------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 28d3ab9e8f..00718598fe 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -211,13 +211,13 @@ public class Compiler implements Opcodes{ static final public Var CONSTANT_IDS = Var.create().setDynamic(); //vector -static final public Var KEYWORD_CALLSITES = Var.create().setDynamic(); +static final public Var KEYWORD_CALLSITES = Var.create(null).setDynamic(); //vector -static final public Var PROTOCOL_CALLSITES = Var.create().setDynamic(); +static final public Var PROTOCOL_CALLSITES = Var.create(null).setDynamic(); //set -static final public Var VAR_CALLSITES = Var.create().setDynamic(); +//static final public Var VAR_CALLSITES = Var.create(null).setDynamic(); //keyword->constid static final public Var KEYWORDS = Var.create().setDynamic(); @@ -4155,6 +4155,12 @@ static Object sigTag(int argcount, Var v){ return null; } + // Callsites are only registered in a function context + // In KEYWORD/PROTOCOL_CALLSITES, null indicates "do not register" + static boolean shouldRegisterCallsites(Var callSiteVar) { + return callSiteVar.deref() != null; + } + public InvokeExpr(String source, int line, int column, Symbol tag, Expr fexpr, IPersistentVector args, boolean tailPosition) { this.source = source; this.fexpr = fexpr; @@ -4167,7 +4173,7 @@ public InvokeExpr(String source, int line, int column, Symbol tag, Expr fexpr, I { Var fvar = ((VarExpr)fexpr).var; Var pvar = (Var)RT.get(fvar.meta(), protocolKey); - if(pvar != null && PROTOCOL_CALLSITES.isBound()) + if(pvar != null && shouldRegisterCallsites(PROTOCOL_CALLSITES)) { this.isProtocol = true; this.siteIndex = registerProtocolCallsite(((VarExpr)fexpr).var); @@ -4389,7 +4395,7 @@ static public Expr parse(C context, ISeq form) { } } - if(fexpr instanceof KeywordExpr && RT.count(form) == 2 && KEYWORD_CALLSITES.isBound()) + if(fexpr instanceof KeywordExpr && RT.count(form) == 2 && shouldRegisterCallsites(KEYWORD_CALLSITES)) { // fexpr = new ConstantExpr(new KeywordCallSite(((KeywordExpr)fexpr).k)); Expr target = analyze(context, RT.second(form)); @@ -4572,7 +4578,7 @@ CONSTANT_IDS, new IdentityHashMap(), VARS, PersistentHashMap.EMPTY, KEYWORD_CALLSITES, PersistentVector.EMPTY, PROTOCOL_CALLSITES, PersistentVector.EMPTY, - VAR_CALLSITES, emptyVarCallSites(), + //VAR_CALLSITES, emptyVarCallSites(), NO_RECUR, null )); @@ -4652,7 +4658,7 @@ else if(methodArray[f.reqParms.count()] == null) fn.constants = (PersistentVector) CONSTANTS.deref(); fn.keywordCallsites = (IPersistentVector) KEYWORD_CALLSITES.deref(); fn.protocolCallsites = (IPersistentVector) PROTOCOL_CALLSITES.deref(); - fn.varCallsites = (IPersistentSet) VAR_CALLSITES.deref(); + //fn.varCallsites = (IPersistentSet) VAR_CALLSITES.deref(); fn.constantsID = RT.nextID(); // DynamicClassLoader loader = (DynamicClassLoader) LOADER.get(); @@ -4757,7 +4763,7 @@ static public class ObjExpr implements Expr{ IPersistentVector keywordCallsites; IPersistentVector protocolCallsites; - IPersistentSet varCallsites; + //IPersistentSet varCallsites; boolean onceOnly = false; Object src; @@ -5801,9 +5807,9 @@ String cachedVarName(int n){ return "__cached_var__" + n; } - String varCallsiteName(int n){ - return "__var__callsite__" + n; - } + //String varCallsiteName(int n){ + // return "__var__callsite__" + n; + //} String thunkNameStatic(int n){ return thunkName(n) + "__"; @@ -7800,9 +7806,6 @@ private static KeywordExpr registerKeyword(Keyword keyword){ } private static int registerKeywordCallsite(Keyword keyword){ - if(!KEYWORD_CALLSITES.isBound()) - throw new IllegalAccessError("KEYWORD_CALLSITES is not bound"); - IPersistentVector keywordCallsites = (IPersistentVector) KEYWORD_CALLSITES.deref(); keywordCallsites = keywordCallsites.cons(keyword); @@ -7811,9 +7814,6 @@ private static int registerKeywordCallsite(Keyword keyword){ } private static int registerProtocolCallsite(Var v){ - if(!PROTOCOL_CALLSITES.isBound()) - throw new IllegalAccessError("PROTOCOL_CALLSITES is not bound"); - IPersistentVector protocolCallsites = (IPersistentVector) PROTOCOL_CALLSITES.deref(); protocolCallsites = protocolCallsites.cons(v); @@ -7821,16 +7821,16 @@ private static int registerProtocolCallsite(Var v){ return protocolCallsites.count()-1; } -private static void registerVarCallsite(Var v){ - if(!VAR_CALLSITES.isBound()) - throw new IllegalAccessError("VAR_CALLSITES is not bound"); - - IPersistentCollection varCallsites = (IPersistentCollection) VAR_CALLSITES.deref(); - - varCallsites = varCallsites.cons(v); - VAR_CALLSITES.set(varCallsites); -// return varCallsites.count()-1; -} +//private static void registerVarCallsite(Var v){ +// if(!VAR_CALLSITES.isBound()) +// throw new IllegalAccessError("VAR_CALLSITES is not bound"); +// +// IPersistentCollection varCallsites = (IPersistentCollection) VAR_CALLSITES.deref(); +// +// varCallsites = varCallsites.cons(v); +// VAR_CALLSITES.set(varCallsites); +//// return varCallsites.count()-1; +//} static ISeq fwdPath(PathNode p1){ ISeq ret = null; @@ -8348,6 +8348,9 @@ public static Object compile(Reader rdr, String sourcePath, String sourceName) t COLUMN_AFTER, pushbackReader.getColumnNumber(), CONSTANTS, PersistentVector.EMPTY, CONSTANT_IDS, new IdentityHashMap(), + KEYWORD_CALLSITES, null, + PROTOCOL_CALLSITES, null, + //VAR_CALLSITES, null, KEYWORDS, PersistentHashMap.EMPTY, VARS, PersistentHashMap.EMPTY ,RT.UNCHECKED_MATH, RT.UNCHECKED_MATH.deref() @@ -8625,7 +8628,7 @@ CONSTANT_IDS, new IdentityHashMap(), VARS, PersistentHashMap.EMPTY, KEYWORD_CALLSITES, PersistentVector.EMPTY, PROTOCOL_CALLSITES, PersistentVector.EMPTY, - VAR_CALLSITES, emptyVarCallSites(), + //VAR_CALLSITES, emptyVarCallSites(), NO_RECUR, null)); if(ret.isDeftype()) { @@ -8655,7 +8658,7 @@ VAR_CALLSITES, emptyVarCallSites(), ret.constantsID = RT.nextID(); ret.keywordCallsites = (IPersistentVector) KEYWORD_CALLSITES.deref(); ret.protocolCallsites = (IPersistentVector) PROTOCOL_CALLSITES.deref(); - ret.varCallsites = (IPersistentSet) VAR_CALLSITES.deref(); + //ret.varCallsites = (IPersistentSet) VAR_CALLSITES.deref(); } finally { From e6393a4063c42ddc0e0812f04464467764f0fd1e Mon Sep 17 00:00:00 2001 From: clojure-build Date: Thu, 25 Sep 2025 17:15:25 +0000 Subject: [PATCH 269/285] [maven-release-plugin] prepare release clojure-1.12.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3f8637f5bf..b03a1e83d8 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.13.0-master-SNAPSHOT + 1.12.3 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.3 From 03d289502fd6a1fc918c41b5387ed8911927b7b0 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Thu, 25 Sep 2025 17:15:25 +0000 Subject: [PATCH 270/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b03a1e83d8..3f8637f5bf 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.3 + 1.13.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.3 + HEAD From 6a4ba6aedc8575768b2fff6d9c9c7e6503a0a93a Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Thu, 25 Sep 2025 12:50:22 -0500 Subject: [PATCH 271/285] update changelog for 1.12.3 --- changes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changes.md b/changes.md index 671d320ecf..54d2251d75 100644 --- a/changes.md +++ b/changes.md @@ -1,5 +1,9 @@ +# Changes to Clojure in Version 1.12.3 + +* [CLJ-2919](https://clojure.atlassian.net/browse/CLJ-2919) - Compiler - fix nested compilation emitting for keyword and protocol call sites + # Changes to Clojure in Version 1.12.2 * [CLJ-2914](https://clojure.atlassian.net/browse/CLJ-2914) - Compiler - syntax error if qualified instance method expression is missing instance From 74db134e653e22607f1d4d00f1b06291e911a40b Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 9 Dec 2025 10:35:18 -0600 Subject: [PATCH 272/285] CLJ-2924 - LazySeq - fix visibility issues with non-volatile reads --- src/jvm/clojure/lang/LazySeq.java | 47 +++++++++++-------------------- 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/src/jvm/clojure/lang/LazySeq.java b/src/jvm/clojure/lang/LazySeq.java index 26ad7be198..cb8c617bfa 100644 --- a/src/jvm/clojure/lang/LazySeq.java +++ b/src/jvm/clojure/lang/LazySeq.java @@ -25,7 +25,7 @@ public final class LazySeq extends Obj implements ISeq, Sequential, List, IPendi private transient IFn fn; private Object sv; private ISeq s; -private Lock lock; +private volatile Lock lock; public LazySeq(IFn f){ fn = f; @@ -52,24 +52,22 @@ final private void force() { } } -final private void lockAndForce() { - Lock l = lock; - if(l != null) { - l.lock(); - try { - force(); - } finally { - l.unlock(); - } - } -} - final private Object sval() { - if(fn != null) - lockAndForce(); - if(sv != null) - return sv; - return s; + Lock l = lock; + if(l != null) { + l.lock(); + try { + //must re-examine under lock + if(lock != null) { //unrealized + force(); + return sv; + } + } finally { + l.unlock(); + } + } + // realized, read of lock above guarantees visibility of s + return s; } final private Object unwrap(Object ls){ @@ -287,18 +285,7 @@ public boolean addAll(int index, Collection c){ } public boolean isRealized(){ - if(lock != null) { - Lock l = lock; - if(l != null) { - l.lock(); - try { - return lock == null; - } finally { - l.unlock(); - } - } - } - return true; + return lock == null; } // custom Serializable implementation - ensure seq is fully-realized before writing From 049bccac6084c9ddfec75185b7b5ab31f658935e Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Wed, 10 Dec 2025 12:11:37 -0600 Subject: [PATCH 273/285] update changelog for 1.12.4 --- changes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changes.md b/changes.md index 54d2251d75..d938d03015 100644 --- a/changes.md +++ b/changes.md @@ -1,5 +1,9 @@ +# Changes to Clojure in Version 1.12.4 + +* [CLJ-2924](https://clojure.atlassian.net/browse/CLJ-2924) - LazySeq - fix visibility issues with non-volatile reads + # Changes to Clojure in Version 1.12.3 * [CLJ-2919](https://clojure.atlassian.net/browse/CLJ-2919) - Compiler - fix nested compilation emitting for keyword and protocol call sites From b4ea0f824b2eea039dfc06b796ed601e35cbeab6 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Wed, 10 Dec 2025 18:25:37 +0000 Subject: [PATCH 274/285] [maven-release-plugin] prepare release clojure-1.12.4 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3f8637f5bf..7e4d450bcf 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.13.0-master-SNAPSHOT + 1.12.4 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.4 From e43644847d03e6a27a28f99f1d7699da63f1069e Mon Sep 17 00:00:00 2001 From: clojure-build Date: Wed, 10 Dec 2025 18:25:37 +0000 Subject: [PATCH 275/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7e4d450bcf..3f8637f5bf 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.4 + 1.13.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.4 + HEAD From 35b68c58269133870be340f4b9a20ff79693707f Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 23 Dec 2025 10:02:55 -0600 Subject: [PATCH 276/285] Add Java 25 to testing matrix --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 42b11d66b9..3dfb4cafaa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] # macOS-latest, windows-latest] - java-version: ["8", "11", "17", "21"] + java-version: ["8", "11", "17", "21", "25"] distribution: ["temurin", "corretto"] profile: ["test-direct", "test-no-direct"] runs-on: ${{ matrix.os }} From a3fa897590f70207eea3573759739810f2b6ab6c Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 23 Dec 2025 12:43:16 -0600 Subject: [PATCH 277/285] Add permissions to github actions --- .github/workflows/doc-build.yml | 3 +++ .github/workflows/release.yml | 3 +++ .github/workflows/snapshot.yml | 3 +++ .github/workflows/test.yml | 3 +++ 4 files changed, 12 insertions(+) diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 957f0059f2..11ff789629 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -1,5 +1,8 @@ name: Build API Docs +permissions: + contents: write + on: workflow_dispatch: inputs: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e2718bd3ef..286cf956d5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,5 +1,8 @@ name: Release on demand +permissions: + contents: write + on: workflow_dispatch: inputs: diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 24729578c1..9fdad8c695 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -1,5 +1,8 @@ name: Snapshot on demand +permissions: + contents: read + on: [workflow_dispatch] jobs: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3dfb4cafaa..ebbb36eb2c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,5 +1,8 @@ name: Test +permissions: + contents: read + on: push: workflow_dispatch: From 53d6a059d82b2716800636a8e29a61e2ac89dbb1 Mon Sep 17 00:00:00 2001 From: Ghadi Shayban Date: Tue, 31 Mar 2026 15:49:32 -0400 Subject: [PATCH 278/285] CLJ-2945: do not propagate file/line info to runtime reify obj --- src/jvm/clojure/lang/Compiler.java | 8 +++++--- test/clojure/test_clojure/compilation.clj | 8 ++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 00718598fe..4d58fcfd09 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -8548,9 +8548,11 @@ public Expr parse(C context, Object frm) { ObjExpr ret = build(interfaces, null, null, classname, Symbol.intern(classname), null, rform, frm, null); - if(frm instanceof IObj && ((IObj) frm).meta() != null) - return new MetaExpr(ret, MapExpr - .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) frm).meta())); + IPersistentMap fmeta = RT.meta(frm); + if(fmeta != null) + fmeta = fmeta.without(RT.LINE_KEY).without(RT.COLUMN_KEY).without(RT.FILE_KEY); + if (RT.count(fmeta) > 0) + return new MetaExpr(ret, MapExpr.parse(context == C.EVAL ? context : C.EXPRESSION, fmeta)); else return ret; } diff --git a/test/clojure/test_clojure/compilation.clj b/test/clojure/test_clojure/compilation.clj index 999d33f91b..61c6905622 100644 --- a/test/clojure/test_clojure/compilation.clj +++ b/test/clojure/test_clojure/compilation.clj @@ -443,3 +443,11 @@ (testing "CLJ-2580 Correctly calculate exit branches of case" (is (zero? (let [d (case nil :x nil 0)] d))) (is (nil? (let [d (case nil :x 0 nil)] d))))) + +(deftest CLJ-2945 + (testing "CLJ-2945 Reify form and obj meta" + (are [m x] (= (set (keys m)) x) + (meta (reify clojure.lang.ILookup)) #{} + (meta ^:foo (reify clojure.lang.ILookup)) #{:foo} + (meta (macroexpand-1 '(reify clojure.lang.ILookup))) #{:line :column} + (meta (macroexpand-1 '^:foo (reify clojure.lang.ILookup))) #{:line :column :foo}))) From 9b850722ca5b1e6ca02488e90eba657280f278e7 Mon Sep 17 00:00:00 2001 From: Erik Assum Date: Tue, 26 Sep 2017 22:03:17 +0200 Subject: [PATCH 279/285] CLJ-2228 Improve performance of constantly - Unroll constantly to arity 2 - Add test for constantly with four args --- src/clj/clojure/core.clj | 6 +++++- test/clojure/test_clojure/other_functions.clj | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index be8e61c949..9694037b50 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -1460,7 +1460,11 @@ "Returns a function that takes any number of arguments and returns x." {:added "1.0" :static true} - [x] (fn [& args] x)) + [x] (fn + ([] x) + ([_] x) + ([_ _] x) + ([_ _ & args] x))) (defn identity "Returns its argument." diff --git a/test/clojure/test_clojure/other_functions.clj b/test/clojure/test_clojure/other_functions.clj index 517f633fcc..b7e3637925 100644 --- a/test/clojure/test_clojure/other_functions.clj +++ b/test/clojure/test_clojure/other_functions.clj @@ -102,6 +102,10 @@ (deftest test-constantly (let [c0 (constantly 10)] (are [x] (= 10 (c0 x)) + nil + 42 + "foo") + (are [x] (= 10 (c0 x :a :b :c)) nil 42 "foo"))) From 9ad0b9a99b3ae76a762799e0b52112cd7d411a21 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 7 Apr 2026 14:03:25 -0500 Subject: [PATCH 280/285] update changelog --- changes.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/changes.md b/changes.md index d938d03015..3244776da9 100644 --- a/changes.md +++ b/changes.md @@ -1,5 +1,10 @@ +# Changes to Clojure in Version 1.12.5 + +* [CLJ-2945](https://clojure.atlassian.net/browse/CLJ-2945) - reify - incorrectly transfers reader metadata to runtime object +* [CLJ-2228](https://clojure.atlassian.net/browse/CLJ-2228) - constantly - unroll to remove rest args allocation + # Changes to Clojure in Version 1.12.4 * [CLJ-2924](https://clojure.atlassian.net/browse/CLJ-2924) - LazySeq - fix visibility issues with non-volatile reads From 4a9957938c90a6558bc44d2eefcc23a76fad2466 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Tue, 7 Apr 2026 20:18:49 +0000 Subject: [PATCH 281/285] [maven-release-plugin] prepare release clojure-1.12.5-alpha1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3f8637f5bf..b3278e14e9 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.13.0-master-SNAPSHOT + 1.12.5-alpha1 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.5-alpha1 From 51df024a4a384e495b21e9b56a2cb81d3c5875b1 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Tue, 7 Apr 2026 20:18:49 +0000 Subject: [PATCH 282/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b3278e14e9..3f8637f5bf 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.5-alpha1 + 1.13.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.5-alpha1 + HEAD From 16d21525fa1f3cbd951b8df500796ce98650e5c3 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Mon, 20 Apr 2026 14:59:11 +0000 Subject: [PATCH 283/285] [maven-release-plugin] prepare release clojure-1.12.5-rc1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3f8637f5bf..083e4073a6 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.13.0-master-SNAPSHOT + 1.12.5-rc1 http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - HEAD + clojure-1.12.5-rc1 From 4dffbdb20d8038c399490dccbf975a3819d8d2d5 Mon Sep 17 00:00:00 2001 From: clojure-build Date: Mon, 20 Apr 2026 14:59:11 +0000 Subject: [PATCH 284/285] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 083e4073a6..3f8637f5bf 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ clojure clojure jar - 1.12.5-rc1 + 1.13.0-master-SNAPSHOT http://clojure.org/ Clojure core environment and runtime library. @@ -30,7 +30,7 @@ scm:git:git@github.com:clojure/clojure.git scm:git:git@github.com:clojure/clojure.git git@github.com:clojure/clojure.git - clojure-1.12.5-rc1 + HEAD From dd395eaa400767e5579ccd674627664c5c3d33da Mon Sep 17 00:00:00 2001 From: Rich Hickey Date: Wed, 22 Apr 2026 15:59:18 -0400 Subject: [PATCH 285/285] try sticking with ArrayMap for longer (to 64 entries) while keys are Keywords - the special case identity scan lookup for kws is faster than hashing/PHM. This should also make more usage sites monomorphic for the record-y map use case. TODO - something similar for transient version --- src/jvm/clojure/lang/PersistentArrayMap.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/jvm/clojure/lang/PersistentArrayMap.java b/src/jvm/clojure/lang/PersistentArrayMap.java index 18bbcaa7b3..ccd542d638 100644 --- a/src/jvm/clojure/lang/PersistentArrayMap.java +++ b/src/jvm/clojure/lang/PersistentArrayMap.java @@ -33,6 +33,7 @@ public class PersistentArrayMap extends APersistentMap implements IObj, IEditabl final Object[] array; static final int HASHTABLE_THRESHOLD = 16; +static final int KW_HASHTABLE_THRESHOLD = 128; public static final PersistentArrayMap EMPTY = new PersistentArrayMap(); private final IPersistentMap _meta; @@ -233,7 +234,9 @@ public IPersistentMap assocEx(Object key, Object val) { } else //didn't have key, grow { - if(array.length >= HASHTABLE_THRESHOLD) + boolean isKW = key instanceof Keyword; + if((isKW && array.length >= KW_HASHTABLE_THRESHOLD) + || (!isKW && array.length >= HASHTABLE_THRESHOLD)) return createHT(array).assocEx(key, val); newArray = new Object[array.length + 2]; if(array.length > 0) @@ -256,7 +259,9 @@ public IPersistentMap assoc(Object key, Object val){ } else //didn't have key, grow { - if(array.length >= HASHTABLE_THRESHOLD) + boolean isKW = key instanceof Keyword; + if((isKW && array.length >= KW_HASHTABLE_THRESHOLD) + || (!isKW && array.length >= HASHTABLE_THRESHOLD)) return createHT(array).assoc(key, val); newArray = new Object[array.length + 2]; if(array.length > 0)