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/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml
new file mode 100644
index 0000000000..11ff789629
--- /dev/null
+++ b/.github/workflows/doc-build.yml
@@ -0,0 +1,75 @@
+name: Build API Docs
+
+permissions:
+ contents: write
+
+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@v4
+ with:
+ java-version: 8
+ distribution: 'temurin'
+
+ - name: Set up Clojure
+ uses: DeLaGuardo/setup-clojure@13.1
+ with:
+ cli: 'latest'
+
+ - name: Cache clojure dependencies
+ uses: actions/cache@v4
+ with:
+ path: |
+ ~/.m2/repository
+ ~/.gitlibs
+ key: cljdeps-${{ hashFiles('deps.edn') }}
+ restore-keys: cljdeps-
+
+ - name: Clone clojure api doc repo
+ 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@v4
+ with:
+ path: clojure-api-doc/repo
+ fetch-depth: 0
+
+ - name: Clone clojure gh-pages branch into clojure-api-doc
+ uses: actions/checkout@v4
+ 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
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000000..286cf956d5
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,22 @@
+name: Release on demand
+
+permissions:
+ contents: write
+
+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..9fdad8c695
--- /dev/null
+++ b/.github/workflows/snapshot.yml
@@ -0,0 +1,11 @@
+name: Snapshot on demand
+
+permissions:
+ contents: read
+
+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..ebbb36eb2c
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,29 @@
+name: Test
+
+permissions:
+ contents: read
+
+on:
+ push:
+ workflow_dispatch:
+
+jobs:
+ test:
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest] # macOS-latest, windows-latest]
+ java-version: ["8", "11", "17", "21", "25"]
+ distribution: ["temurin", "corretto"]
+ profile: ["test-direct", "test-no-direct"]
+ runs-on: ${{ matrix.os }}
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Java
+ uses: actions/setup-java@v4
+ with:
+ java-version: ${{ matrix.java-version }}
+ distribution: ${{ matrix.distribution }}
+ cache: 'maven'
+ - name: Build with Maven
+ run: mvn -ntp -B -P${{ matrix.profile }} clean test
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 @@
- IFns can be passed to higher order functions, e.g. the
- * example below passes plus to read: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");
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 c9f15cdd3f..20c40918eb 100644
--- a/src/jvm/clojure/lang/APersistentVector.java
+++ b/src/jvm/clojure/lang/APersistentVector.java
@@ -14,11 +14,15 @@
import java.io.Serializable;
import java.util.*;
+import java.util.function.Consumer;
public abstract class APersistentVector extends AFn implements IPersistentVector, Iterable,
List,
RandomAccess, Comparable,
Serializable, IHashEq {
+
+private static final long serialVersionUID = 4667575149454420891L;
+
int _hash;
int _hasheq;
@@ -98,15 +102,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
{
@@ -270,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= end) || (i < 0))
throw new IndexOutOfBoundsException();
diff --git a/src/jvm/clojure/lang/ASeq.java b/src/jvm/clojure/lang/ASeq.java
index 325aa27c24..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;
@@ -37,6 +40,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/src/jvm/clojure/lang/ArityException.java b/src/jvm/clojure/lang/ArityException.java
index 49b7914b70..89d2c8f4fe 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;
@@ -24,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/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/ArraySeq.java b/src/jvm/clojure/lang/ArraySeq.java
index 597a5410de..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;
@@ -142,6 +145,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/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/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index abac2251a2..4d58fcfd09 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -15,15 +15,20 @@
//*
import clojure.asm.*;
+import clojure.asm.Type;
import clojure.asm.commons.GeneratorAdapter;
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;
//*/
/*
@@ -206,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();
@@ -387,7 +392,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);
@@ -410,7 +420,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 +428,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 +437,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 +482,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 +539,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 +587,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);
}
}
}
@@ -1021,7 +1014,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);
}
}
}
@@ -1117,10 +1110,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);
@@ -1128,6 +1123,297 @@ static Class tagToClass(Object tag) {
return c;
throw new IllegalArgumentException("Unable to resolve classname: " + tag);
}
+
+ 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);
+
+ 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 hintedSig;
+ private final Symbol methodSymbol;
+ 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) {
+ 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;
+ hintedSig = tagsToClasses(paramTagsOf(sym));
+ if(sym.name.startsWith(".")) {
+ kind = MethodKind.INSTANCE;
+ methodName = sym.name.substring(1);
+ }
+ else if(sym.name.equals("new")) {
+ kind = MethodKind.CTOR;
+ methodName = sym.name;
+ }
+ else {
+ 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() {
+ if(preferOverloadedField())
+ return fieldOverload.eval();
+ else
+ return buildThunk(C.EVAL, this).eval();
+ }
+
+ @Override
+ public void emit(C context, ObjExpr objx, GeneratorAdapter gen) {
+ if(preferOverloadedField())
+ fieldOverload.emit(context, objx, gen);
+ else
+ buildThunk(context, this).emit(context, objx, gen);
+ }
+
+ // Expr impl - method value, always an AFn
+
+ @Override
+ public boolean hasJavaClass() {
+ return true;
+ }
+
+ @Override
+ public Class getJavaClass() {
+ return tagClass;
+ }
+
+ // 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));
+ }
+
+ ISeq thunkForm = RT.listStar(Symbol.intern("fn"), Symbol.intern(thunkName), RT.seq(form));
+ return (FnExpr) analyzeSeq(context, thunkForm, thunkName);
+ }
+
+ 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;
+ }
+
+ public static List methodOverloads(Class c, String methodName, MethodKind kind) {
+ 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());
+ }
+
+ // 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);
+ return res;
+ }
+
+ static Executable resolveHintedMethod(Class c, String methodName, MethodKind kind, List hintedSig) {
+ List methods = methodsWithName(c, methodName, kind);
+ 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);
+ }
+
+ 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) {
+ IPersistentVector paramTags = PersistentVector.create(hintedSig.stream()
+ .map(tag -> tag == null ? PARAM_TAG_ANY : tag)
+ .collect(Collectors.toList()));
+ return new IllegalArgumentException("Error - param-tags " + paramTags
+ + " 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, "_");
+
+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 "
+ + 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{
@@ -1364,6 +1650,161 @@ 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) {
+ 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 && !(expr instanceof FI))
+ * 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]));
+ }
+ // FnInvokers has prim returns for <= 2 params, only Object for higher
+ Class retType = targetMethod.getReturnType();
+ char invokerReturnCode = FnInvokers.encodeInvokerType(paramCount <= 2 ? retType : Object.class);
+ 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 not (expr instanceof IFn), go to end label
+ expr.emit(C.EXPRESSION, objx, gen);
+ gen.dup();
+ gen.instanceOf(ifnType);
+ 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);
+
+ // 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
@@ -1375,6 +1816,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)
@@ -1441,7 +1884,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]);
@@ -1466,14 +1909,34 @@ 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,
+ Class qualifyingClass, String methodName, java.lang.reflect.Method resolvedMethod,
+ IPersistentVector args, boolean tailPosition)
+ {
+ checkMethodArity(resolvedMethod, 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 = 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;
@@ -1483,9 +1946,12 @@ public InstanceMethodExpr(String source, int line, int column, Symbol tag, Expr
this.target = target;
this.tag = tag;
this.tailPosition = tailPosition;
- if(target.hasJavaClass() && target.getJavaClass() != null)
+ this.qualifyingClass = qualifyingClass;
+ 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;
@@ -1493,7 +1959,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
@@ -1523,7 +1989,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));
}
}
}
@@ -1552,7 +2018,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)
{
@@ -1610,12 +2079,22 @@ 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
{
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());
@@ -1624,10 +2103,13 @@ public void emit(C context, ObjExpr objx, GeneratorAdapter gen){
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();
}
- if(context == C.STATEMENT)
- gen.pop();
}
public boolean hasJavaClass(){
@@ -1659,6 +2141,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)
{
@@ -2020,7 +2525,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);
@@ -2568,6 +3075,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;
@@ -3639,7 +4153,13 @@ static Object sigTag(int argcount, Var v){
return tagOf(sig);
}
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;
@@ -3653,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);
@@ -3875,24 +4395,78 @@ 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));
return new KeywordInvokeExpr((String) SOURCE.deref(), lineDeref(), columnDeref(), tagOf(form),
(KeywordExpr) fexpr, target);
}
+
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)
+ {
+ 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(
// 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(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);
+ }
+ }
+ }
}
static class SourceDebugExtensionAttribute extends Attribute{
@@ -4004,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
));
@@ -4084,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();
@@ -4189,7 +4763,7 @@ static public class ObjExpr implements Expr{
IPersistentVector keywordCallsites;
IPersistentVector protocolCallsites;
- IPersistentSet varCallsites;
+ //IPersistentSet varCallsites;
boolean onceOnly = false;
Object src;
@@ -4993,7 +5567,7 @@ public Object eval() {
return null;
try
{
- return getCompiledClass().newInstance();
+ return getCompiledClass().getDeclaredConstructor().newInstance();
}
catch(Exception e)
{
@@ -5233,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) + "__";
@@ -5343,9 +5917,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,
@@ -5789,6 +6362,7 @@ abstract public static class ObjMethod{
boolean usesThis = false;
PersistentHashSet localsUsedInCatchFinally = PersistentHashSet.EMPTY;
protected IPersistentMap methodMeta;
+ PathNode clearRoot;
public final IPersistentMap locals(){
@@ -6012,9 +6586,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();
@@ -6038,7 +6617,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);
@@ -6487,7 +7068,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
@@ -6656,6 +7240,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)
@@ -7026,7 +7615,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(
@@ -7039,16 +7629,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)
@@ -7226,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);
@@ -7237,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);
@@ -7247,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;
@@ -7300,16 +7874,25 @@ private static Expr analyzeSymbol(Symbol sym) {
}
else
{
- if(namespaceFor(sym) == null)
+ if(namespaceFor(sym) == null && !Util.isPosDigit(sym.name))
{
Symbol nsSym = Symbol.intern(sym.ns);
Class c = HostExpr.maybeClass(nsSym, false);
if(c != null)
{
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);
+ {
+ 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);
}
+
}
}
//Var v = lookupVar(sym, false);
@@ -7381,7 +7964,12 @@ static public Object resolveIn(Namespace n, Symbol sym, boolean allowPrivate) {
{
Namespace ns = namespaceFor(n, sym);
if(ns == null)
+ {
+ Class ac = HostExpr.maybeArrayClass(sym);
+ if(ac != null)
+ return ac;
throw Util.runtimeException("No such namespace: " + sym.ns);
+ }
Var v = ns.findInternedVar(Symbol.intern(sym.name));
if(v == null)
@@ -7425,7 +8013,7 @@ static public Object maybeResolveIn(Namespace n, Symbol sym) {
{
Namespace ns = namespaceFor(n, sym);
if(ns == null)
- return null;
+ return HostExpr.maybeArrayClass(sym);
Var v = ns.findInternedVar(Symbol.intern(sym.name));
if(v == null)
return null;
@@ -7539,7 +8127,6 @@ static void closeOver(LocalBinding b, ObjMethod method){
}
}
-
static LocalBinding referenceLocal(Symbol sym) {
if(!LOCAL_ENV.isBound())
return null;
@@ -7645,7 +8232,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;
}
@@ -7761,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()
@@ -7958,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;
}
@@ -8038,7 +8630,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())
{
@@ -8068,7 +8660,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
{
@@ -8444,7 +9036,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,
@@ -8654,7 +9247,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/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..293463090c 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
@@ -93,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/Delay.java b/src/jvm/clojure/lang/Delay.java
index 262c9c1a43..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;
}
-synchronized public boolean isRealized(){
- return fn == null;
+public boolean isRealized(){
+ return lock == null;
}
}
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..28f845b7c3 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) {
@@ -25,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/src/jvm/clojure/lang/FnInvokers.java b/src/jvm/clojure/lang/FnInvokers.java
new file mode 100644
index 0000000000..34cbaa548b
--- /dev/null
+++ b/src/jvm/clojure/lang/FnInvokers.java
@@ -0,0 +1,782 @@
+/**
+ * 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 {
+ return 'O';
+ }
+ }
+
+ 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 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);
+ } 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 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 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 Object invokeOOOO(IFn f0, Object a, Object b, Object c) {
+ return f0.invoke(a, b, c);
+ }
+
+ public static Object invokeOOOOO(IFn f0, Object a, Object b, Object c, Object d) {
+ return f0.invoke(a, b, c, d);
+ }
+
+ 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 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 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 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 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 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/FnLoaderThunk.java b/src/jvm/clojure/lang/FnLoaderThunk.java
index 337ba2558c..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;
@@ -51,7 +53,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)
{
diff --git a/src/jvm/clojure/lang/IDeref.java b/src/jvm/clojure/lang/IDeref.java
index 3a4746157b..0eeaaf329d 100644
--- a/src/jvm/clojure/lang/IDeref.java
+++ b/src/jvm/clojure/lang/IDeref.java
@@ -12,6 +12,38 @@
package clojure.lang;
-public interface IDeref{
+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, DoubleSupplier {
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());
+}
+
+@Override
+default double getAsDouble() {
+ return RT.doubleCast(deref());
+}
+
}
diff --git a/src/jvm/clojure/lang/IDrop.java b/src/jvm/clojure/lang/IDrop.java
new file mode 100644
index 0000000000..153ab0858f
--- /dev/null
+++ b/src/jvm/clojure/lang/IDrop.java
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ *
+ * @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/Iterate.java b/src/jvm/clojure/lang/Iterate.java
index aec0c14aa2..a0562bce49 100644
--- a/src/jvm/clojure/lang/Iterate.java
+++ b/src/jvm/clojure/lang/Iterate.java
@@ -12,8 +12,12 @@
/* Alex Miller, Dec 5, 2014 */
+import java.io.IOException;
+
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;
@@ -84,4 +88,23 @@ public Object reduce(IFn rf, Object start){
v = f.invoke(v);
}
}
+
+public int hashCode(){
+ throw new UnsupportedOperationException();
+}
+
+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();
+}
+
}
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/Keyword.java b/src/jvm/clojure/lang/Keyword.java
index 02d21326a2..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;
@@ -93,13 +95,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 +117,7 @@ public void run(){
}
public Object invoke() {
- return throwArity();
+ return throwArity(0);
}
public int compareTo(Object o){
@@ -146,98 +156,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 +255,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/src/jvm/clojure/lang/LazySeq.java b/src/jvm/clojure/lang/LazySeq.java
index 0ca4e46223..cb8c617bfa 100644
--- a/src/jvm/clojure/lang/LazySeq.java
+++ b/src/jvm/clojure/lang/LazySeq.java
@@ -12,22 +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 IFn fn;
+private static final long serialVersionUID = -7531333024710395876L;
+
+private transient IFn fn;
private Object sv;
private ISeq s;
+private volatile 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){
@@ -36,29 +44,64 @@ 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 Object sval() {
+ 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){
+ 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();
}
- 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);
- }
+public final ISeq seq(){
+ if(lock != null)
+ realize();
return s;
}
@@ -241,8 +284,18 @@ public boolean addAll(int index, Collection c){
throw new UnsupportedOperationException();
}
+public boolean isRealized(){
+ return lock == null;
+}
-synchronized public boolean isRealized(){
- return fn == null;
+// 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/src/jvm/clojure/lang/LispReader.java b/src/jvm/clojure/lang/LispReader.java
index 9fcb7b5aa9..8d7079cf5a 100644
--- a/src/jvm/clojure/lang/LispReader.java
+++ b/src/jvm/clojure/lang/LispReader.java
@@ -64,6 +64,7 @@ public class LispReader{
static IFn[] dispatchMacros = new IFn[256];
//static Pattern symbolPat = Pattern.compile("[:]?([\\D&&[^:/]][^:/]*/)?[\\D&&[^:/]][^:/]*");
static Pattern symbolPat = Pattern.compile("[:]?([\\D&&[^/]].*/)?(/|[\\D&&[^/]][^/]*)");
+static Pattern arraySymbolPat = Pattern.compile("([\\D&&[^/:]].*)/([1-9])");
//static Pattern varPat = Pattern.compile("([\\D&&[^:\\.]][^:\\.]*):([\\D&&[^:\\.]][^:\\.]*)");
//static Pattern intPat = Pattern.compile("[-+]?[0-9]+\\.?");
static Pattern intPat =
@@ -71,6 +72,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*)");
@@ -460,6 +462,12 @@ private static Object matchSymbol(String s, Resolver resolver){
return Keyword.intern(sym);
return sym;
}
+ else
+ {
+ Matcher am = arraySymbolPat.matcher(s);
+ if(am.matches())
+ return Symbol.intern(am.group(1), am.group(2));
+ }
return null;
}
@@ -920,23 +928,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)));
}
}
@@ -956,8 +957,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/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();
diff --git a/src/jvm/clojure/lang/LongRange.java b/src/jvm/clojure/lang/LongRange.java
index 348e362081..10381cc29b 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
-
-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);
- }
- };
-}
+final int count;
-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,51 +101,25 @@ 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();
}
+private static final int CHUNK_SIZE = 32;
+
public IChunk chunkedFirst() {
- forceChunk();
- return _chunk;
+ return new LongChunk(start, step, Math.min(count, CHUNK_SIZE));
}
public ISeq chunkedNext() {
@@ -158,82 +127,51 @@ public ISeq chunkedNext() {
}
public ISeq chunkedMore() {
- forceChunk();
- if(_chunkNext == null)
+ if(count <= CHUNK_SIZE) {
return PersistentList.EMPTY;
- return _chunkNext;
-}
-
-// 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;
- }
+ } else {
+ return LongRange.create(start + (step * CHUNK_SIZE), end, step);
}
- 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 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;
+ }
}
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 +181,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 +256,4 @@ public Object reduce(IFn f, Object init) {
}
}
-}
\ No newline at end of file
+}
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/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/src/jvm/clojure/lang/Namespace.java b/src/jvm/clojure/lang/Namespace.java
index 68cded632e..359815778c 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();
@@ -47,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;
@@ -63,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){
@@ -96,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)
@@ -107,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/src/jvm/clojure/lang/Numbers.java b/src/jvm/clojure/lang/Numbers.java
index fa13cba62c..661c051d36 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{
@@ -528,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);
@@ -619,6 +625,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 +716,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 +851,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 +954,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 +1077,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();
@@ -1888,10 +1919,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){
@@ -1902,10 +1930,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){
@@ -1916,9 +1941,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){
@@ -1928,9 +1951,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){
@@ -1940,9 +1961,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){
@@ -1953,12 +1972,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){
@@ -4068,11 +4082,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 +4176,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 +4227,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/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 27b860e5d5..ccd542d638 100644
--- a/src/jvm/clojure/lang/PersistentArrayMap.java
+++ b/src/jvm/clojure/lang/PersistentArrayMap.java
@@ -27,10 +27,13 @@
* 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{
+
+private static final long serialVersionUID = -2074065891090893601L;
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;
@@ -76,9 +79,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
@@ -179,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)
@@ -202,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)
@@ -296,11 +355,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;
@@ -329,16 +396,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/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 fcd9e46c26..2ac8b1c142 100644
--- a/src/jvm/clojure/lang/PersistentVector.java
+++ b/src/jvm/clojure/lang/PersistentVector.java
@@ -17,9 +17,13 @@
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.Spliterator;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
-public class PersistentVector extends APersistentVector implements IObj, IEditableCollection, IReduce, IKVReduce{
+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;
@@ -316,6 +320,77 @@ public void remove(){
public Iterator iterator(){return rangedIterator(0,count());}
+@Override
+Spliterator rangedSpliterator(final int start, final int end){
+ return new Spliterator(){
+ int i = start;
+ int base = i - (i%32);
+ Object[] array = (start < count())?arrayFor(i):null;
+
+ @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) {
+ if(i-base == 32){
+ array = arrayFor(i);
+ base += 32;
+ }
+ action.accept(array[i++ & 0x01f]);
+ 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) {
+ int x=i;
+ while(x 0)
@@ -363,7 +438,16 @@ 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 < 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 +512,72 @@ 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 0 && n <= m.groupCount())
return m.group(n);
return notFound;
}
@@ -1243,10 +1264,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/src/jvm/clojure/lang/Range.java b/src/jvm/clojure/lang/Range.java
index 4f638e9f97..1e4fbf6e01 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
@@ -99,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/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/Reflector.java b/src/jvm/clojure/lang/Reflector.java
index d5811cc59d..14cef154b9 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;
@@ -94,12 +95,19 @@ 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());
- return invokeMatchingMethod(methodName, methods, target, args);
+ .map(method -> toAccessibleSuperMethod(method, target))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ return invokeMatchingMethod(methodName, methods, c, 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) {
@@ -114,57 +122,78 @@ 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) {
+ 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 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 && !(paramType.isInstance(arg)))
+ // Adapt IFn obj to targetType using dynamic proxy
+ return Proxy.newProxyInstance(RT.baseLoader(),
+ 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);
@@ -592,6 +644,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
@@ -651,4 +705,5 @@ public static Object prepRet(Class c, Object x){
// return Double.valueOf(((Float) x).doubleValue());
return x;
}
+
}
diff --git a/src/jvm/clojure/lang/Repeat.java b/src/jvm/clojure/lang/Repeat.java
index 2ce4f2dab2..7e11808385 100644
--- a/src/jvm/clojure/lang/Repeat.java
+++ b/src/jvm/clojure/lang/Repeat.java
@@ -12,7 +12,9 @@
/* Alex Miller, Dec 5, 2014 */
-public class Repeat extends ASeq implements IReduce {
+public class Repeat extends ASeq implements IReduce, IDrop {
+
+private static final long serialVersionUID = -5140377547192202551L;
private static final long INFINITE = -1;
@@ -97,4 +99,31 @@ public Object reduce(IFn f, Object start){
}
}
+public Sequential drop(int n) {
+ if(count == INFINITE) {
+ return this;
+ } else {
+ long droppedCount = count-n;
+ if(droppedCount > 0) {
+ return new Repeat(droppedCount, val);
+ } else {
+ return null;
+ }
+ }
+}
+
+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/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 bcb269d5dc..dbad70810e 100644
--- a/src/jvm/clojure/lang/StringSeq.java
+++ b/src/jvm/clojure/lang/StringSeq.java
@@ -12,7 +12,13 @@
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{
+
+private static final long serialVersionUID = 7975525539139301753L;
+
public final CharSequence s;
public final int i;
@@ -51,4 +57,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(null, 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/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/Util.java b/src/jvm/clojure/lang/Util.java
index ff0e338331..11647f800c 100644
--- a/src/jvm/clojure/lang/Util.java
+++ b/src/jvm/clojure/lang/Util.java
@@ -256,5 +256,27 @@ static public Object loadWithClass(String scriptbase, Class> 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/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;
diff --git a/test/clojure/test_clojure/array_symbols.clj b/test/clojure/test_clojure/array_symbols.clj
new file mode 100644
index 0000000000..7fb98743e3
--- /dev/null
+++ b/test/clojure/test_clojure/array_symbols.clj
@@ -0,0 +1,81 @@
+; 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]))))))
+
+(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))))))))
diff --git a/test/clojure/test_clojure/atoms.clj b/test/clojure/test_clojure/atoms.clj
index f9ecadcc56..875f26d60f 100644
--- a/test/clojure/test_clojure/atoms.clj
+++ b/test/clojure/test_clojure/atoms.clj
@@ -42,3 +42,22 @@
(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)))
+
+ (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/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
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/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
diff --git a/test/clojure/test_clojure/compilation.clj b/test/clojure/test_clojure/compilation.clj
index 8a5fd84233..61c6905622 100644
--- a/test/clojure/test_clojure/compilation.clj
+++ b/test/clojure/test_clojure/compilation.clj
@@ -438,3 +438,16 @@
(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)))))
+
+(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})))
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"
diff --git a/test/clojure/test_clojure/data_structures.clj b/test/clojure/test_clojure/data_structures.clj
index 580e30b073..854560466b 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)))
@@ -1319,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)))))
diff --git a/test/clojure/test_clojure/delays.clj b/test/clojure/test_clojure/delays.clj
index 0a2a1c99ff..322feb6e49 100644
--- a/test/clojure/test_clojure/delays.clj
+++ b/test/clojure/test_clojure/delays.clj
@@ -66,3 +66,24 @@
(.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)))
+ (is (= 100.0 (.getAsDouble ^java.util.function.DoubleSupplier di)))))
\ No newline at end of file
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"})
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))
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..4bac4914b9
--- /dev/null
+++ b/test/clojure/test_clojure/generated_all_fi_adapters_in_let.clj
@@ -0,0 +1,305 @@
+
+(ns clojure.test-clojure.generated-all-fi-adapters-in-let
+ (:use clojure.test)
+ (:require [clojure.string :as str])
+ (:import (clojure.test AdapterExerciser AdapterExerciser$L
+AdapterExerciser$I
+AdapterExerciser$S
+AdapterExerciser$B
+AdapterExerciser$D
+AdapterExerciser$F
+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$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$LLO
+AdapterExerciser$LOO
+AdapterExerciser$OLO
+AdapterExerciser$DDO
+AdapterExerciser$LDO
+AdapterExerciser$DLO
+AdapterExerciser$OOO
+AdapterExerciser$ODO
+AdapterExerciser$DOO
+AdapterExerciser$OOOO
+AdapterExerciser$OOOOO
+AdapterExerciser$OOOOOO
+AdapterExerciser$OOOOOOO
+AdapterExerciser$OOOOOOOO
+AdapterExerciser$OOOOOOOOO
+AdapterExerciser$OOOOOOOOOO
+AdapterExerciser$OOOOOOOOOOO
+)))
+
+ (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$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$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$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$OOOO OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser)
+ ^AdapterExerciser$OOOOO OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser)
+ ^AdapterExerciser$OOOOOO OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser)
+ ^AdapterExerciser$OOOOOOO OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser)
+ ^AdapterExerciser$OOOOOOOO OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser)
+ ^AdapterExerciser$OOOOOOOOO OOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h] exerciser)
+ ^AdapterExerciser$OOOOOOOOOO OOOOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g ^AdapterExerciser h ^AdapterExerciser i] exerciser)
+ ^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 (= (.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 (= (.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 (= (.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 (= (.takesOOORetO OOOOadapter exerciser exerciser exerciser) exerciser))
+ (is (= (.takesOOOORetO OOOOOadapter exerciser exerciser exerciser exerciser) exerciser))
+ (is (= (.takesOOOOORetO OOOOOOadapter exerciser exerciser exerciser exerciser exerciser) exerciser))
+ (is (= (.takesOOOOOORetO OOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser) exerciser))
+ (is (= (.takesOOOOOOORetO OOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser))
+ (is (= (.takesOOOOOOOORetO OOOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser))
+ (is (= (.takesOOOOOOOOORetO OOOOOOOOOOadapter exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser exerciser) exerciser))
+ (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
new file mode 100644
index 0000000000..ba62daa7c7
--- /dev/null
+++ b/test/clojure/test_clojure/generated_functional_adapters_in_def.clj
@@ -0,0 +1,206 @@
+
+(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 Ladapter (fn [] (long 1)))
+ (is (= (.methodL ^AdapterExerciser exerciser Ladapter) "L"))
+ (def Iadapter (fn [] 1))
+ (is (= (.methodI ^AdapterExerciser exerciser Iadapter) "I"))
+ (def Sadapter (fn [] (short 1)))
+ (is (= (.methodS ^AdapterExerciser exerciser Sadapter) "S"))
+ (def Badapter (fn [] (byte 1)))
+ (is (= (.methodB ^AdapterExerciser exerciser Badapter) "B"))
+ (def Dadapter (fn [] (double 1)))
+ (is (= (.methodD ^AdapterExerciser exerciser Dadapter) "D"))
+ (def Fadapter (fn [] (float 1)))
+ (is (= (.methodF ^AdapterExerciser exerciser Fadapter) "F"))
+ (def Oadapter (fn [] exerciser))
+ (is (= (.methodO ^AdapterExerciser exerciser Oadapter) "O"))
+ (def LLadapter (fn [^long a] (long 1)))
+ (is (= (.methodLL ^AdapterExerciser exerciser LLadapter) "LL"))
+ (def DLadapter (fn [^double a] (long 1)))
+ (is (= (.methodDL ^AdapterExerciser exerciser DLadapter) "DL"))
+ (def OLadapter (fn [^AdapterExerciser a] (long 1)))
+ (is (= (.methodOL ^AdapterExerciser exerciser OLadapter) "OL"))
+ (def LIadapter (fn [^long a] 1))
+ (is (= (.methodLI ^AdapterExerciser exerciser LIadapter) "LI"))
+ (def DIadapter (fn [^double a] 1))
+ (is (= (.methodDI ^AdapterExerciser exerciser DIadapter) "DI"))
+ (def OIadapter (fn [^AdapterExerciser a] 1))
+ (is (= (.methodOI ^AdapterExerciser exerciser OIadapter) "OI"))
+ (def LSadapter (fn [^long a] (short 1)))
+ (is (= (.methodLS ^AdapterExerciser exerciser LSadapter) "LS"))
+ (def DSadapter (fn [^double a] (short 1)))
+ (is (= (.methodDS ^AdapterExerciser exerciser DSadapter) "DS"))
+ (def OSadapter (fn [^AdapterExerciser a] (short 1)))
+ (is (= (.methodOS ^AdapterExerciser exerciser OSadapter) "OS"))
+ (def LBadapter (fn [^long a] (byte 1)))
+ (is (= (.methodLB ^AdapterExerciser exerciser LBadapter) "LB"))
+ (def DBadapter (fn [^double a] (byte 1)))
+ (is (= (.methodDB ^AdapterExerciser exerciser DBadapter) "DB"))
+ (def OBadapter (fn [^AdapterExerciser a] (byte 1)))
+ (is (= (.methodOB ^AdapterExerciser exerciser OBadapter) "OB"))
+ (def LDadapter (fn [^long a] (double 1)))
+ (is (= (.methodLD ^AdapterExerciser exerciser LDadapter) "LD"))
+ (def DDadapter (fn [^double a] (double 1)))
+ (is (= (.methodDD ^AdapterExerciser exerciser DDadapter) "DD"))
+ (def ODadapter (fn [^AdapterExerciser a] (double 1)))
+ (is (= (.methodOD ^AdapterExerciser exerciser ODadapter) "OD"))
+ (def LFadapter (fn [^long a] (float 1)))
+ (is (= (.methodLF ^AdapterExerciser exerciser LFadapter) "LF"))
+ (def DFadapter (fn [^double a] (float 1)))
+ (is (= (.methodDF ^AdapterExerciser exerciser DFadapter) "DF"))
+ (def OFadapter (fn [^AdapterExerciser a] (float 1)))
+ (is (= (.methodOF ^AdapterExerciser exerciser OFadapter) "OF"))
+ (def LOadapter (fn [^long a] exerciser))
+ (is (= (.methodLO ^AdapterExerciser exerciser LOadapter) "LO"))
+ (def DOadapter (fn [^double a] exerciser))
+ (is (= (.methodDO ^AdapterExerciser exerciser DOadapter) "DO"))
+ (def OOadapter (fn [^AdapterExerciser a] exerciser))
+ (is (= (.methodOO ^AdapterExerciser exerciser OOadapter) "OO"))
+ (def LLLadapter (fn [^long a ^long b] (long 1)))
+ (is (= (.methodLLL ^AdapterExerciser exerciser LLLadapter) "LLL"))
+ (def LOLadapter (fn [^long a ^AdapterExerciser b] (long 1)))
+ (is (= (.methodLOL ^AdapterExerciser exerciser LOLadapter) "LOL"))
+ (def OLLadapter (fn [^AdapterExerciser a ^long b] (long 1)))
+ (is (= (.methodOLL ^AdapterExerciser exerciser OLLadapter) "OLL"))
+ (def DDLadapter (fn [^double a ^double b] (long 1)))
+ (is (= (.methodDDL ^AdapterExerciser exerciser DDLadapter) "DDL"))
+ (def LDLadapter (fn [^long a ^double b] (long 1)))
+ (is (= (.methodLDL ^AdapterExerciser exerciser LDLadapter) "LDL"))
+ (def DLLadapter (fn [^double a ^long b] (long 1)))
+ (is (= (.methodDLL ^AdapterExerciser exerciser DLLadapter) "DLL"))
+ (def OOLadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (long 1)))
+ (is (= (.methodOOL ^AdapterExerciser exerciser OOLadapter) "OOL"))
+ (def ODLadapter (fn [^AdapterExerciser a ^double b] (long 1)))
+ (is (= (.methodODL ^AdapterExerciser exerciser ODLadapter) "ODL"))
+ (def DOLadapter (fn [^double a ^AdapterExerciser b] (long 1)))
+ (is (= (.methodDOL ^AdapterExerciser exerciser DOLadapter) "DOL"))
+ (def LLIadapter (fn [^long a ^long b] 1))
+ (is (= (.methodLLI ^AdapterExerciser exerciser LLIadapter) "LLI"))
+ (def LOIadapter (fn [^long a ^AdapterExerciser b] 1))
+ (is (= (.methodLOI ^AdapterExerciser exerciser LOIadapter) "LOI"))
+ (def OLIadapter (fn [^AdapterExerciser a ^long b] 1))
+ (is (= (.methodOLI ^AdapterExerciser exerciser OLIadapter) "OLI"))
+ (def DDIadapter (fn [^double a ^double b] 1))
+ (is (= (.methodDDI ^AdapterExerciser exerciser DDIadapter) "DDI"))
+ (def LDIadapter (fn [^long a ^double b] 1))
+ (is (= (.methodLDI ^AdapterExerciser exerciser LDIadapter) "LDI"))
+ (def DLIadapter (fn [^double a ^long b] 1))
+ (is (= (.methodDLI ^AdapterExerciser exerciser DLIadapter) "DLI"))
+ (def OOIadapter (fn [^AdapterExerciser a ^AdapterExerciser b] 1))
+ (is (= (.methodOOI ^AdapterExerciser exerciser OOIadapter) "OOI"))
+ (def ODIadapter (fn [^AdapterExerciser a ^double b] 1))
+ (is (= (.methodODI ^AdapterExerciser exerciser ODIadapter) "ODI"))
+ (def DOIadapter (fn [^double a ^AdapterExerciser b] 1))
+ (is (= (.methodDOI ^AdapterExerciser exerciser DOIadapter) "DOI"))
+ (def LLSadapter (fn [^long a ^long b] (short 1)))
+ (is (= (.methodLLS ^AdapterExerciser exerciser LLSadapter) "LLS"))
+ (def LOSadapter (fn [^long a ^AdapterExerciser b] (short 1)))
+ (is (= (.methodLOS ^AdapterExerciser exerciser LOSadapter) "LOS"))
+ (def OLSadapter (fn [^AdapterExerciser a ^long b] (short 1)))
+ (is (= (.methodOLS ^AdapterExerciser exerciser OLSadapter) "OLS"))
+ (def DDSadapter (fn [^double a ^double b] (short 1)))
+ (is (= (.methodDDS ^AdapterExerciser exerciser DDSadapter) "DDS"))
+ (def LDSadapter (fn [^long a ^double b] (short 1)))
+ (is (= (.methodLDS ^AdapterExerciser exerciser LDSadapter) "LDS"))
+ (def DLSadapter (fn [^double a ^long b] (short 1)))
+ (is (= (.methodDLS ^AdapterExerciser exerciser DLSadapter) "DLS"))
+ (def OOSadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (short 1)))
+ (is (= (.methodOOS ^AdapterExerciser exerciser OOSadapter) "OOS"))
+ (def ODSadapter (fn [^AdapterExerciser a ^double b] (short 1)))
+ (is (= (.methodODS ^AdapterExerciser exerciser ODSadapter) "ODS"))
+ (def DOSadapter (fn [^double a ^AdapterExerciser b] (short 1)))
+ (is (= (.methodDOS ^AdapterExerciser exerciser DOSadapter) "DOS"))
+ (def LLBadapter (fn [^long a ^long b] (byte 1)))
+ (is (= (.methodLLB ^AdapterExerciser exerciser LLBadapter) "LLB"))
+ (def LOBadapter (fn [^long a ^AdapterExerciser b] (byte 1)))
+ (is (= (.methodLOB ^AdapterExerciser exerciser LOBadapter) "LOB"))
+ (def OLBadapter (fn [^AdapterExerciser a ^long b] (byte 1)))
+ (is (= (.methodOLB ^AdapterExerciser exerciser OLBadapter) "OLB"))
+ (def DDBadapter (fn [^double a ^double b] (byte 1)))
+ (is (= (.methodDDB ^AdapterExerciser exerciser DDBadapter) "DDB"))
+ (def LDBadapter (fn [^long a ^double b] (byte 1)))
+ (is (= (.methodLDB ^AdapterExerciser exerciser LDBadapter) "LDB"))
+ (def DLBadapter (fn [^double a ^long b] (byte 1)))
+ (is (= (.methodDLB ^AdapterExerciser exerciser DLBadapter) "DLB"))
+ (def OOBadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (byte 1)))
+ (is (= (.methodOOB ^AdapterExerciser exerciser OOBadapter) "OOB"))
+ (def ODBadapter (fn [^AdapterExerciser a ^double b] (byte 1)))
+ (is (= (.methodODB ^AdapterExerciser exerciser ODBadapter) "ODB"))
+ (def DOBadapter (fn [^double a ^AdapterExerciser b] (byte 1)))
+ (is (= (.methodDOB ^AdapterExerciser exerciser DOBadapter) "DOB"))
+ (def LLDadapter (fn [^long a ^long b] (double 1)))
+ (is (= (.methodLLD ^AdapterExerciser exerciser LLDadapter) "LLD"))
+ (def LODadapter (fn [^long a ^AdapterExerciser b] (double 1)))
+ (is (= (.methodLOD ^AdapterExerciser exerciser LODadapter) "LOD"))
+ (def OLDadapter (fn [^AdapterExerciser a ^long b] (double 1)))
+ (is (= (.methodOLD ^AdapterExerciser exerciser OLDadapter) "OLD"))
+ (def DDDadapter (fn [^double a ^double b] (double 1)))
+ (is (= (.methodDDD ^AdapterExerciser exerciser DDDadapter) "DDD"))
+ (def LDDadapter (fn [^long a ^double b] (double 1)))
+ (is (= (.methodLDD ^AdapterExerciser exerciser LDDadapter) "LDD"))
+ (def DLDadapter (fn [^double a ^long b] (double 1)))
+ (is (= (.methodDLD ^AdapterExerciser exerciser DLDadapter) "DLD"))
+ (def OODadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (double 1)))
+ (is (= (.methodOOD ^AdapterExerciser exerciser OODadapter) "OOD"))
+ (def ODDadapter (fn [^AdapterExerciser a ^double b] (double 1)))
+ (is (= (.methodODD ^AdapterExerciser exerciser ODDadapter) "ODD"))
+ (def DODadapter (fn [^double a ^AdapterExerciser b] (double 1)))
+ (is (= (.methodDOD ^AdapterExerciser exerciser DODadapter) "DOD"))
+ (def LLFadapter (fn [^long a ^long b] (float 1)))
+ (is (= (.methodLLF ^AdapterExerciser exerciser LLFadapter) "LLF"))
+ (def LOFadapter (fn [^long a ^AdapterExerciser b] (float 1)))
+ (is (= (.methodLOF ^AdapterExerciser exerciser LOFadapter) "LOF"))
+ (def OLFadapter (fn [^AdapterExerciser a ^long b] (float 1)))
+ (is (= (.methodOLF ^AdapterExerciser exerciser OLFadapter) "OLF"))
+ (def DDFadapter (fn [^double a ^double b] (float 1)))
+ (is (= (.methodDDF ^AdapterExerciser exerciser DDFadapter) "DDF"))
+ (def LDFadapter (fn [^long a ^double b] (float 1)))
+ (is (= (.methodLDF ^AdapterExerciser exerciser LDFadapter) "LDF"))
+ (def DLFadapter (fn [^double a ^long b] (float 1)))
+ (is (= (.methodDLF ^AdapterExerciser exerciser DLFadapter) "DLF"))
+ (def OOFadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (float 1)))
+ (is (= (.methodOOF ^AdapterExerciser exerciser OOFadapter) "OOF"))
+ (def ODFadapter (fn [^AdapterExerciser a ^double b] (float 1)))
+ (is (= (.methodODF ^AdapterExerciser exerciser ODFadapter) "ODF"))
+ (def DOFadapter (fn [^double a ^AdapterExerciser b] (float 1)))
+ (is (= (.methodDOF ^AdapterExerciser exerciser DOFadapter) "DOF"))
+ (def LLOadapter (fn [^long a ^long b] exerciser))
+ (is (= (.methodLLO ^AdapterExerciser exerciser LLOadapter) "LLO"))
+ (def LOOadapter (fn [^long a ^AdapterExerciser b] exerciser))
+ (is (= (.methodLOO ^AdapterExerciser exerciser LOOadapter) "LOO"))
+ (def OLOadapter (fn [^AdapterExerciser a ^long b] exerciser))
+ (is (= (.methodOLO ^AdapterExerciser exerciser OLOadapter) "OLO"))
+ (def DDOadapter (fn [^double a ^double b] exerciser))
+ (is (= (.methodDDO ^AdapterExerciser exerciser DDOadapter) "DDO"))
+ (def LDOadapter (fn [^long a ^double b] exerciser))
+ (is (= (.methodLDO ^AdapterExerciser exerciser LDOadapter) "LDO"))
+ (def DLOadapter (fn [^double a ^long b] exerciser))
+ (is (= (.methodDLO ^AdapterExerciser exerciser DLOadapter) "DLO"))
+ (def OOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b] exerciser))
+ (is (= (.methodOOO ^AdapterExerciser exerciser OOOadapter) "OOO"))
+ (def ODOadapter (fn [^AdapterExerciser a ^double b] exerciser))
+ (is (= (.methodODO ^AdapterExerciser exerciser ODOadapter) "ODO"))
+ (def DOOadapter (fn [^double a ^AdapterExerciser b] exerciser))
+ (is (= (.methodDOO ^AdapterExerciser exerciser DOOadapter) "DOO"))
+ (def OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser))
+ (is (= (.methodOOOO ^AdapterExerciser exerciser OOOOadapter) "OOOO"))
+ (def OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser))
+ (is (= (.methodOOOOO ^AdapterExerciser exerciser OOOOOadapter) "OOOOO"))
+ (def OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser))
+ (is (= (.methodOOOOOO ^AdapterExerciser exerciser OOOOOOadapter) "OOOOOO"))
+ (def OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser))
+ (is (= (.methodOOOOOOO ^AdapterExerciser exerciser OOOOOOOadapter) "OOOOOOO"))
+ (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 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 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 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
new file mode 100644
index 0000000000..7e6212c3ab
--- /dev/null
+++ b/test/clojure/test_clojure/generated_functional_adapters_in_def_requiring_reflection.clj
@@ -0,0 +1,206 @@
+
+(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 Ladapter (fn [] (long 1)))
+ (is (= (.methodL exerciser Ladapter) "L"))
+ (def Iadapter (fn [] 1))
+ (is (= (.methodI exerciser Iadapter) "I"))
+ (def Sadapter (fn [] (short 1)))
+ (is (= (.methodS exerciser Sadapter) "S"))
+ (def Badapter (fn [] (byte 1)))
+ (is (= (.methodB exerciser Badapter) "B"))
+ (def Dadapter (fn [] (double 1)))
+ (is (= (.methodD exerciser Dadapter) "D"))
+ (def Fadapter (fn [] (float 1)))
+ (is (= (.methodF exerciser Fadapter) "F"))
+ (def Oadapter (fn [] exerciser))
+ (is (= (.methodO exerciser Oadapter) "O"))
+ (def LLadapter (fn [^long a] (long 1)))
+ (is (= (.methodLL exerciser LLadapter) "LL"))
+ (def DLadapter (fn [^double a] (long 1)))
+ (is (= (.methodDL exerciser DLadapter) "DL"))
+ (def OLadapter (fn [^AdapterExerciser a] (long 1)))
+ (is (= (.methodOL exerciser OLadapter) "OL"))
+ (def LIadapter (fn [^long a] 1))
+ (is (= (.methodLI exerciser LIadapter) "LI"))
+ (def DIadapter (fn [^double a] 1))
+ (is (= (.methodDI exerciser DIadapter) "DI"))
+ (def OIadapter (fn [^AdapterExerciser a] 1))
+ (is (= (.methodOI exerciser OIadapter) "OI"))
+ (def LSadapter (fn [^long a] (short 1)))
+ (is (= (.methodLS exerciser LSadapter) "LS"))
+ (def DSadapter (fn [^double a] (short 1)))
+ (is (= (.methodDS exerciser DSadapter) "DS"))
+ (def OSadapter (fn [^AdapterExerciser a] (short 1)))
+ (is (= (.methodOS exerciser OSadapter) "OS"))
+ (def LBadapter (fn [^long a] (byte 1)))
+ (is (= (.methodLB exerciser LBadapter) "LB"))
+ (def DBadapter (fn [^double a] (byte 1)))
+ (is (= (.methodDB exerciser DBadapter) "DB"))
+ (def OBadapter (fn [^AdapterExerciser a] (byte 1)))
+ (is (= (.methodOB exerciser OBadapter) "OB"))
+ (def LDadapter (fn [^long a] (double 1)))
+ (is (= (.methodLD exerciser LDadapter) "LD"))
+ (def DDadapter (fn [^double a] (double 1)))
+ (is (= (.methodDD exerciser DDadapter) "DD"))
+ (def ODadapter (fn [^AdapterExerciser a] (double 1)))
+ (is (= (.methodOD exerciser ODadapter) "OD"))
+ (def LFadapter (fn [^long a] (float 1)))
+ (is (= (.methodLF exerciser LFadapter) "LF"))
+ (def DFadapter (fn [^double a] (float 1)))
+ (is (= (.methodDF exerciser DFadapter) "DF"))
+ (def OFadapter (fn [^AdapterExerciser a] (float 1)))
+ (is (= (.methodOF exerciser OFadapter) "OF"))
+ (def LOadapter (fn [^long a] exerciser))
+ (is (= (.methodLO exerciser LOadapter) "LO"))
+ (def DOadapter (fn [^double a] exerciser))
+ (is (= (.methodDO exerciser DOadapter) "DO"))
+ (def OOadapter (fn [^AdapterExerciser a] exerciser))
+ (is (= (.methodOO exerciser OOadapter) "OO"))
+ (def LLLadapter (fn [^long a ^long b] (long 1)))
+ (is (= (.methodLLL exerciser LLLadapter) "LLL"))
+ (def LOLadapter (fn [^long a ^AdapterExerciser b] (long 1)))
+ (is (= (.methodLOL exerciser LOLadapter) "LOL"))
+ (def OLLadapter (fn [^AdapterExerciser a ^long b] (long 1)))
+ (is (= (.methodOLL exerciser OLLadapter) "OLL"))
+ (def DDLadapter (fn [^double a ^double b] (long 1)))
+ (is (= (.methodDDL exerciser DDLadapter) "DDL"))
+ (def LDLadapter (fn [^long a ^double b] (long 1)))
+ (is (= (.methodLDL exerciser LDLadapter) "LDL"))
+ (def DLLadapter (fn [^double a ^long b] (long 1)))
+ (is (= (.methodDLL exerciser DLLadapter) "DLL"))
+ (def OOLadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (long 1)))
+ (is (= (.methodOOL exerciser OOLadapter) "OOL"))
+ (def ODLadapter (fn [^AdapterExerciser a ^double b] (long 1)))
+ (is (= (.methodODL exerciser ODLadapter) "ODL"))
+ (def DOLadapter (fn [^double a ^AdapterExerciser b] (long 1)))
+ (is (= (.methodDOL exerciser DOLadapter) "DOL"))
+ (def LLIadapter (fn [^long a ^long b] 1))
+ (is (= (.methodLLI exerciser LLIadapter) "LLI"))
+ (def LOIadapter (fn [^long a ^AdapterExerciser b] 1))
+ (is (= (.methodLOI exerciser LOIadapter) "LOI"))
+ (def OLIadapter (fn [^AdapterExerciser a ^long b] 1))
+ (is (= (.methodOLI exerciser OLIadapter) "OLI"))
+ (def DDIadapter (fn [^double a ^double b] 1))
+ (is (= (.methodDDI exerciser DDIadapter) "DDI"))
+ (def LDIadapter (fn [^long a ^double b] 1))
+ (is (= (.methodLDI exerciser LDIadapter) "LDI"))
+ (def DLIadapter (fn [^double a ^long b] 1))
+ (is (= (.methodDLI exerciser DLIadapter) "DLI"))
+ (def OOIadapter (fn [^AdapterExerciser a ^AdapterExerciser b] 1))
+ (is (= (.methodOOI exerciser OOIadapter) "OOI"))
+ (def ODIadapter (fn [^AdapterExerciser a ^double b] 1))
+ (is (= (.methodODI exerciser ODIadapter) "ODI"))
+ (def DOIadapter (fn [^double a ^AdapterExerciser b] 1))
+ (is (= (.methodDOI exerciser DOIadapter) "DOI"))
+ (def LLSadapter (fn [^long a ^long b] (short 1)))
+ (is (= (.methodLLS exerciser LLSadapter) "LLS"))
+ (def LOSadapter (fn [^long a ^AdapterExerciser b] (short 1)))
+ (is (= (.methodLOS exerciser LOSadapter) "LOS"))
+ (def OLSadapter (fn [^AdapterExerciser a ^long b] (short 1)))
+ (is (= (.methodOLS exerciser OLSadapter) "OLS"))
+ (def DDSadapter (fn [^double a ^double b] (short 1)))
+ (is (= (.methodDDS exerciser DDSadapter) "DDS"))
+ (def LDSadapter (fn [^long a ^double b] (short 1)))
+ (is (= (.methodLDS exerciser LDSadapter) "LDS"))
+ (def DLSadapter (fn [^double a ^long b] (short 1)))
+ (is (= (.methodDLS exerciser DLSadapter) "DLS"))
+ (def OOSadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (short 1)))
+ (is (= (.methodOOS exerciser OOSadapter) "OOS"))
+ (def ODSadapter (fn [^AdapterExerciser a ^double b] (short 1)))
+ (is (= (.methodODS exerciser ODSadapter) "ODS"))
+ (def DOSadapter (fn [^double a ^AdapterExerciser b] (short 1)))
+ (is (= (.methodDOS exerciser DOSadapter) "DOS"))
+ (def LLBadapter (fn [^long a ^long b] (byte 1)))
+ (is (= (.methodLLB exerciser LLBadapter) "LLB"))
+ (def LOBadapter (fn [^long a ^AdapterExerciser b] (byte 1)))
+ (is (= (.methodLOB exerciser LOBadapter) "LOB"))
+ (def OLBadapter (fn [^AdapterExerciser a ^long b] (byte 1)))
+ (is (= (.methodOLB exerciser OLBadapter) "OLB"))
+ (def DDBadapter (fn [^double a ^double b] (byte 1)))
+ (is (= (.methodDDB exerciser DDBadapter) "DDB"))
+ (def LDBadapter (fn [^long a ^double b] (byte 1)))
+ (is (= (.methodLDB exerciser LDBadapter) "LDB"))
+ (def DLBadapter (fn [^double a ^long b] (byte 1)))
+ (is (= (.methodDLB exerciser DLBadapter) "DLB"))
+ (def OOBadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (byte 1)))
+ (is (= (.methodOOB exerciser OOBadapter) "OOB"))
+ (def ODBadapter (fn [^AdapterExerciser a ^double b] (byte 1)))
+ (is (= (.methodODB exerciser ODBadapter) "ODB"))
+ (def DOBadapter (fn [^double a ^AdapterExerciser b] (byte 1)))
+ (is (= (.methodDOB exerciser DOBadapter) "DOB"))
+ (def LLDadapter (fn [^long a ^long b] (double 1)))
+ (is (= (.methodLLD exerciser LLDadapter) "LLD"))
+ (def LODadapter (fn [^long a ^AdapterExerciser b] (double 1)))
+ (is (= (.methodLOD exerciser LODadapter) "LOD"))
+ (def OLDadapter (fn [^AdapterExerciser a ^long b] (double 1)))
+ (is (= (.methodOLD exerciser OLDadapter) "OLD"))
+ (def DDDadapter (fn [^double a ^double b] (double 1)))
+ (is (= (.methodDDD exerciser DDDadapter) "DDD"))
+ (def LDDadapter (fn [^long a ^double b] (double 1)))
+ (is (= (.methodLDD exerciser LDDadapter) "LDD"))
+ (def DLDadapter (fn [^double a ^long b] (double 1)))
+ (is (= (.methodDLD exerciser DLDadapter) "DLD"))
+ (def OODadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (double 1)))
+ (is (= (.methodOOD exerciser OODadapter) "OOD"))
+ (def ODDadapter (fn [^AdapterExerciser a ^double b] (double 1)))
+ (is (= (.methodODD exerciser ODDadapter) "ODD"))
+ (def DODadapter (fn [^double a ^AdapterExerciser b] (double 1)))
+ (is (= (.methodDOD exerciser DODadapter) "DOD"))
+ (def LLFadapter (fn [^long a ^long b] (float 1)))
+ (is (= (.methodLLF exerciser LLFadapter) "LLF"))
+ (def LOFadapter (fn [^long a ^AdapterExerciser b] (float 1)))
+ (is (= (.methodLOF exerciser LOFadapter) "LOF"))
+ (def OLFadapter (fn [^AdapterExerciser a ^long b] (float 1)))
+ (is (= (.methodOLF exerciser OLFadapter) "OLF"))
+ (def DDFadapter (fn [^double a ^double b] (float 1)))
+ (is (= (.methodDDF exerciser DDFadapter) "DDF"))
+ (def LDFadapter (fn [^long a ^double b] (float 1)))
+ (is (= (.methodLDF exerciser LDFadapter) "LDF"))
+ (def DLFadapter (fn [^double a ^long b] (float 1)))
+ (is (= (.methodDLF exerciser DLFadapter) "DLF"))
+ (def OOFadapter (fn [^AdapterExerciser a ^AdapterExerciser b] (float 1)))
+ (is (= (.methodOOF exerciser OOFadapter) "OOF"))
+ (def ODFadapter (fn [^AdapterExerciser a ^double b] (float 1)))
+ (is (= (.methodODF exerciser ODFadapter) "ODF"))
+ (def DOFadapter (fn [^double a ^AdapterExerciser b] (float 1)))
+ (is (= (.methodDOF exerciser DOFadapter) "DOF"))
+ (def LLOadapter (fn [^long a ^long b] exerciser))
+ (is (= (.methodLLO exerciser LLOadapter) "LLO"))
+ (def LOOadapter (fn [^long a ^AdapterExerciser b] exerciser))
+ (is (= (.methodLOO exerciser LOOadapter) "LOO"))
+ (def OLOadapter (fn [^AdapterExerciser a ^long b] exerciser))
+ (is (= (.methodOLO exerciser OLOadapter) "OLO"))
+ (def DDOadapter (fn [^double a ^double b] exerciser))
+ (is (= (.methodDDO exerciser DDOadapter) "DDO"))
+ (def LDOadapter (fn [^long a ^double b] exerciser))
+ (is (= (.methodLDO exerciser LDOadapter) "LDO"))
+ (def DLOadapter (fn [^double a ^long b] exerciser))
+ (is (= (.methodDLO exerciser DLOadapter) "DLO"))
+ (def OOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b] exerciser))
+ (is (= (.methodOOO exerciser OOOadapter) "OOO"))
+ (def ODOadapter (fn [^AdapterExerciser a ^double b] exerciser))
+ (is (= (.methodODO exerciser ODOadapter) "ODO"))
+ (def DOOadapter (fn [^double a ^AdapterExerciser b] exerciser))
+ (is (= (.methodDOO exerciser DOOadapter) "DOO"))
+ (def OOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c] exerciser))
+ (is (= (.methodOOOO exerciser OOOOadapter) "OOOO"))
+ (def OOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d] exerciser))
+ (is (= (.methodOOOOO exerciser OOOOOadapter) "OOOOO"))
+ (def OOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e] exerciser))
+ (is (= (.methodOOOOOO exerciser OOOOOOadapter) "OOOOOO"))
+ (def OOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f] exerciser))
+ (is (= (.methodOOOOOOO exerciser OOOOOOOadapter) "OOOOOOO"))
+ (def OOOOOOOOadapter (fn [^AdapterExerciser a ^AdapterExerciser b ^AdapterExerciser c ^AdapterExerciser d ^AdapterExerciser e ^AdapterExerciser f ^AdapterExerciser g] exerciser))
+ (is (= (.methodOOOOOOOO exerciser OOOOOOOOadapter) "OOOOOOOO"))
+ (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 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 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/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)))
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"))))))
diff --git a/test/clojure/test_clojure/java/process.clj b/test/clojure/test_clojure/java/process.clj
new file mode 100644
index 0000000000..3e187d58ec
--- /dev/null
+++ b/test/clojure/test_clojure/java/process.clj
@@ -0,0 +1,28 @@
+; 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 (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")))))
+
+(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))))
diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj
index 30fab56e56..3b28cafadc 100644
--- a/test/clojure/test_clojure/java_interop.clj
+++ b/test/clojure/test_clojure/java_interop.clj
@@ -11,9 +11,18 @@
(ns clojure.test-clojure.java-interop
(:use clojure.test)
- (:require [clojure.inspector]
- [clojure.set :as set])
- (:import java.util.Base64))
+ (:require [clojure.data :as data]
+ [clojure.inspector]
+ [clojure.pprint :as pp]
+ [clojure.set :as set]
+ [clojure.string :as str]
+ [clojure.test-clojure.proxy.examples :as proxy-examples]
+ [clojure.test-helper :refer [should-not-reflect]])
+ (:import java.util.Base64
+ (java.io File FileFilter FilenameFilter)
+ (java.util UUID)
+ (java.util.concurrent.atomic AtomicLong AtomicInteger)
+ (clojure.test FIConstructor FIStatic FunctionalTester AdapterExerciser)))
; http://clojure.org/java_interop
; http://clojure.org/compilation
@@ -175,6 +184,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
@@ -373,7 +413,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))
@@ -589,3 +629,263 @@
(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)))))
+
+(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])))
+
+ ;; 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
+ (^long 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-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]))))
+ )
+
+(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)))))
+
+;; 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)))))))
+
+(deftest CLJ-2914-Qualified-Method-Expr-NPE
+ (is (fails-with-cause? IllegalArgumentException
+ #"Malformed method expression.*String/\.length"
+ (eval '(fn [] (java.lang.String/.length))))))
diff --git a/test/clojure/test_clojure/keywords.clj b/test/clojure/test_clojure/keywords.clj
index 9ef86d7dd2..b486a067ab 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 \(> 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)))))
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/math.clj b/test/clojure/test_clojure/math.clj
new file mode 100644
index 0000000000..4520b41b2b
--- /dev/null
+++ b/test/clojure/test_clojure/math.clj
@@ -0,0 +1,326 @@
+; 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))))
+
+(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 (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 (ulp= (m/cos m/PI) (m/cos (- m/PI)) 1)))
+
+(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 (ulp= (- (m/tan m/PI)) (m/tan (- m/PI)) 1)))
+
+(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 (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 (ulp= (m/atan 1) 0.7853981633974483 1)))
+
+(deftest test-radians-degrees-roundtrip
+ (doseq [d (range 0.0 360.0 5.0)]
+ (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 (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 (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 (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 (= (m/sqrt 4.0) 2.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 (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)))
+ (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))))
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)
diff --git a/test/clojure/test_clojure/method_thunks.clj b/test/clojure/test_clojure/method_thunks.clj
new file mode 100644
index 0000000000..b999e539a4
--- /dev/null
+++ b/test/clojure/test_clojure/method_thunks.clj
@@ -0,0 +1,62 @@
+; 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)
+ (: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)
+
+(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]))))
+
+(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"]))))
+ (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})
+(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)))
+ (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))))
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)
diff --git a/test/clojure/test_clojure/ns_libs.clj b/test/clojure/test_clojure/ns_libs.clj
index 0e470d7394..256f99ae87 100644
--- a/test/clojure/test_clojure/ns_libs.clj
+++ b/test/clojure/test_clojure/ns_libs.clj
@@ -103,3 +103,43 @@
(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, 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 (= (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
+ (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)
diff --git a/test/clojure/test_clojure/numbers.clj b/test/clojure/test_clojure/numbers.clj
index 26140a7c29..be4f7a0a60 100644
--- a/test/clojure/test_clojure/numbers.clj
+++ b/test/clojure/test_clojure/numbers.clj
@@ -181,9 +181,12 @@
(let [wrapped (fn [x]
(try
(f x)
- (catch IllegalArgumentException e :error)))]
+ (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)
@@ -595,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)
@@ -644,6 +657,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))
diff --git a/test/clojure/test_clojure/other_functions.clj b/test/clojure/test_clojure/other_functions.clj
index 958df5eca8..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")))
@@ -277,7 +281,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
@@ -348,6 +354,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
@@ -366,3 +385,21 @@
;; 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))))
+
+(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))))
diff --git a/test/clojure/test_clojure/param_tags.clj b/test/clojure/test_clojure/param_tags.clj
new file mode 100644
index 0000000000..bccd3ef127
--- /dev/null
+++ b/test/clojure/test_clojure/param_tags.clj
@@ -0,0 +1,220 @@
+; 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.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)
+
+(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)))
+ (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"
+ (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")))))
+ (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,
+;; :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))))))
+
+(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))
+
+(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"))))
diff --git a/test/clojure/test_clojure/parse.clj b/test/clojure/test_clojure/parse.clj
new file mode 100644
index 0000000000..8078c527f6
--- /dev/null
+++ b/test/clojure/test_clojure/parse.clj
@@ -0,0 +1,102 @@
+(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
+ "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-double s))
+ "double" ;; invalid string
+ "1.7976931348623157G309")) ;; invalid, but similar to valid
+
+;; 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))
diff --git a/test/clojure/test_clojure/pprint/test_pretty.clj b/test/clojure/test_clojure/pprint/test_pretty.clj
index c9b321fdff..4d31a21396 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 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),\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)]]]\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
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
diff --git a/test/clojure/test_clojure/printer.clj b/test/clojure/test_clojure/printer.clj
index 3d9cc65f8f..0216f4f48f 100644
--- a/test/clojure/test_clojure/printer.clj
+++ b/test/clojure/test_clojure/printer.clj
@@ -14,7 +14,9 @@
;; 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
(let [coll () val "()"]
@@ -121,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"
@@ -135,8 +138,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)))
+ (= (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}"
+ {: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))))))
diff --git a/test/clojure/test_clojure/protocols.clj b/test/clojure/test_clojure/protocols.clj
index 3072915481..4cd87a42b5 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
@@ -674,3 +674,48 @@
(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})))))
+
+(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"))))
+
+;; 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"))))))
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 [_]))
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))
diff --git a/test/clojure/test_clojure/reader.cljc b/test/clojure/test_clojure/reader.cljc
index 522a27928a..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?)
@@ -453,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 (~@)
diff --git a/test/clojure/test_clojure/reflect.clj b/test/clojure/test_clojure/reflect.clj
index 36ea68172e..2cb92a5a8f 100644
--- a/test/clojure/test_clojure/reflect.clj
+++ b/test/clojure/test_clojure/reflect.clj
@@ -51,4 +51,13 @@
(checkCLJ2066 (javax.xml.stream.XMLInputFactory/newInstance))
;; CLJ-2414 - find default method on interface of inaccessible class
- (checkCLJ2414 (java.nio.file.Paths/get "src" (into-array String []))))
\ No newline at end of file
+ (checkCLJ2414 (java.nio.file.Paths/get "src" (into-array String []))))
+
+(defn sleep [ms]
+ ;; in Java <19, does not reflect. Java >= 19, does reflect
+ (Thread/sleep ms))
+
+
+(deftest check-CLJ-2843
+ (sleep 1)
+ (sleep (Integer/valueOf 1)))
diff --git a/test/clojure/test_clojure/repl/deps.clj b/test/clojure/test_clojure/repl/deps.clj
new file mode 100644
index 0000000000..a2a69078d1
--- /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"})))))
+; )
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))))))
+
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))))
diff --git a/test/clojure/test_clojure/sequences.clj b/test/clojure/test_clojure/sequences.clj
index e568b52557..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)
@@ -781,6 +824,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]) () )
@@ -796,6 +841,25 @@
(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 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]) ()
+ (partitionv -2 [1 2 3]) () ))
(deftest test-iterate
(are [x y] (= x y)
@@ -834,7 +898,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
@@ -846,8 +912,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)
@@ -986,9 +1096,14 @@
() '(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 100
+(defspec longrange-equals-range 1000
(prop/for-all [start gen/int
end gen/int
step gen/s-pos-int]
@@ -1058,6 +1173,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
@@ -1119,7 +1243,10 @@
{}
#{}
""
- (into-array []) )
+ (into-array [])
+ (transient [])
+ (transient #{})
+ (transient {}))
(are [x] (not (empty? x))
'(1 2)
@@ -1128,7 +1255,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?
@@ -1331,6 +1461,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])]
@@ -1368,3 +1504,150 @@
(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})))))))
+
+(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 :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 :somef #(< % 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
+ :somef (comp #{:a :b :c} :item)
+ :kf :k
+ :vf :item))
+ (vec (iteration api
+ :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))
+
+(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]
+ (let [src (fn []
+ (let [rng (java.util.Random. seed)]
+ (iteration #(unchecked-add % (.nextLong rng))
+ :somef (complement #(zero? (mod % 1000)))
+ :vf str
+ :initk initk)))]
+ (= (into [] (src))
+ (into [] (seq (src)))))))
diff --git a/test/clojure/test_clojure/serialization.clj b/test/clojure/test_clojure/serialization.clj
index 51a0d6a263..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,5 +183,11 @@
(agent nil)
;; stateful seqs
- (enumeration-seq (java.util.Collections/enumeration (range 50)))
- (iterator-seq (.iterator (range 50)))))
\ No newline at end of file
+ (enumeration-seq (java.util.Collections/enumeration (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
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)))))
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)))))
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]))))
+
diff --git a/test/clojure/test_clojure/vectors.clj b/test/clojure/test_clojure/vectors.clj
index 0bea3ff4b8..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)
@@ -416,3 +420,73 @@
(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)))))
+
+(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]]))))
+
+(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
diff --git a/test/java/clojure/test/AdapterExerciser.java b/test/java/clojure/test/AdapterExerciser.java
new file mode 100644
index 0000000000..5e2758b1d7
--- /dev/null
+++ b/test/java/clojure/test/AdapterExerciser.java
@@ -0,0 +1,499 @@
+
+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 O {
+ public AdapterExerciser takesRetO();
+ }
+ @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 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 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 OOOO {
+ public AdapterExerciser takesOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c);
+ }
+ @FunctionalInterface
+ public interface OOOOO {
+ public AdapterExerciser takesOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d);
+ }
+ @FunctionalInterface
+ public interface OOOOOO {
+ public AdapterExerciser takesOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e);
+ }
+ @FunctionalInterface
+ public interface OOOOOOO {
+ public AdapterExerciser takesOOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f);
+ }
+ @FunctionalInterface
+ public interface OOOOOOOO {
+ public AdapterExerciser takesOOOOOOORetO(AdapterExerciser a, AdapterExerciser b, AdapterExerciser c, AdapterExerciser d, AdapterExerciser e, AdapterExerciser f, AdapterExerciser g);
+ }
+ @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 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 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 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 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 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 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 methodOOOO(OOOO a) { return "OOOO"; }
+ public String methodOOOOO(OOOOO a) { return "OOOOO"; }
+ public String methodOOOOOO(OOOOOO a) { return "OOOOOO"; }
+ public String methodOOOOOOO(OOOOOOO a) { return "OOOOOOO"; }
+ public String methodOOOOOOOO(OOOOOOOO a) { return "OOOOOOOO"; }
+ public String methodOOOOOOOOO(OOOOOOOOO a) { return "OOOOOOOOO"; }
+ public String methodOOOOOOOOOO(OOOOOOOOOO a) { return "OOOOOOOOOO"; }
+ public String methodOOOOOOOOOOO(OOOOOOOOOOO a) { return "OOOOOOOOOOO"; }}
\ 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/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