From 97b57d6868a6e699cd4dd91e602de0acbff3ef54 Mon Sep 17 00:00:00 2001 From: Alex Miller Date: Tue, 25 Feb 2025 15:00:06 -0600 Subject: [PATCH] CLJ-2898 Add additional check to prevent FI conversion if object is both IFn and FI --- src/jvm/clojure/lang/Compiler.java | 11 +++++++---- test/clojure/test_clojure/java_interop.clj | 12 ++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 6324456fa1..49c2daa161 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -1651,7 +1651,7 @@ private static Class toInvokerParamType(Class c) { * If targetClass is FI and has an adaptable functional method * Find fn invoker method matching adaptable method of FI * Emit bytecode for (expr is emitted): - * if(expr instanceof IFn) + * if(expr instanceof IFn && !(expr instanceof FI)) * invokeDynamic(targetMethod, fnInvokerImplMethod) * Else emit nothing */ @@ -1686,15 +1686,18 @@ static boolean maybeEmitFIAdapter(ObjExpr objx, GeneratorAdapter gen, Expr expr, try { java.lang.reflect.Method fnInvokerMethod = FnInvokers.class.getMethod(invokerMethodName, invokerParams); - // if(exp instanceof IFn) { emitInvokeDynamic(targetMethod, fnInvokerMethod) } + // if not (expr instanceof IFn), go to end label expr.emit(C.EXPRESSION, objx, gen); gen.dup(); gen.instanceOf(ifnType); - - // if not instanceof IFn, go to end Label endLabel = gen.newLabel(); gen.ifZCmp(Opcodes.IFEQ, endLabel); + // if (expr instanceof FI), go to end label + gen.dup(); + gen.instanceOf(samType); + gen.ifZCmp(Opcodes.IFNE, endLabel); + // else adapt fn invoker method as impl for target method emitInvokeDynamicAdapter(gen, targetClass, targetMethod, FnInvokers.class, fnInvokerMethod); diff --git a/test/clojure/test_clojure/java_interop.clj b/test/clojure/test_clojure/java_interop.clj index 4a50388417..4b1112c9b5 100644 --- a/test/clojure/test_clojure/java_interop.clj +++ b/test/clojure/test_clojure/java_interop.clj @@ -859,3 +859,15 @@ (testing "Static method accepting FI arg, provided overloaded static class FI" (is (= \S (FunctionalTester/staticMethodWithFIArg "Static" 0 FunctionalTester/getChar))))) + +(deftest CLJ-2898-reified-objs-both-IFn-and-FI + (let [tl (ThreadLocal/withInitial + (reify + java.util.function.Supplier + (get [_] 100) + + clojure.lang.IFn + (applyTo [_ _] 201) + (invoke [_] 200)))] + ;; should not be adapted and use Supplier.get() impl on tl + (is (= 100 (.get tl))))) \ No newline at end of file