diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java index 102441effb1..c18b724c350 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java @@ -29,7 +29,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; -import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -321,14 +320,26 @@ public final class Def { String call, Class... captures) throws LambdaConversionException { final FunctionRef ref; if ("this".equals(type)) { + // user written method Method interfaceMethod = clazz.struct.getFunctionalMethod(); if (interfaceMethod == null) { throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " + "to [" + clazz.name + "], not a functional interface"); } - int arity = interfaceMethod.arguments.size(); - // user written method - ref = null; + int arity = interfaceMethod.arguments.size() + captures.length; + final MethodHandle handle; + try { + MethodHandle accessor = lookup.findStaticGetter(lookup.lookupClass(), + "handle$" + call + "$" + arity, + MethodHandle.class); + handle = (MethodHandle) accessor.invokeExact(); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new IllegalArgumentException("Unknown call [" + call + "] with [" + arity + "] arguments."); + } catch (Throwable t) { + rethrow(t); + throw new AssertionError(); + } + ref = new FunctionRef(clazz, interfaceMethod, handle, captures); } else { // whitelist lookup ref = new FunctionRef(clazz, type, call, captures); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java index 7e0fd520b75..9015b4dee61 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java @@ -101,6 +101,27 @@ public class FunctionRef { samMethodType = impl.getMethodType().dropParameterTypes(0, captures.length); } + /** + * Creates a new FunctionRef (low level). + *

+ * This will not set implMethodASM. It is for runtime use only. + */ + public FunctionRef(Definition.Type expected, Definition.Method method, MethodHandle impl, Class... captures) { + // e.g. compareTo + invokedName = method.name; + // e.g. (Object)Comparator + invokedType = MethodType.methodType(expected.clazz, captures); + // e.g. (Object,Object)int + interfaceMethodType = method.getMethodType().dropParameterTypes(0, 1); + + implMethod = impl; + + implMethodASM = null; + + // remove any prepended captured arguments for the 'natural' signature. + samMethodType = impl.type().dropParameterTypes(0, captures.length); + } + /** * Looks up {@code type::call} from the whitelist, and returns a matching method. */ diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java index 30b4fc37901..00a69e0b7b9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java @@ -31,7 +31,6 @@ import org.objectweb.asm.Type; import static org.elasticsearch.painless.WriterConstants.LAMBDA_BOOTSTRAP_HANDLE; import java.lang.invoke.LambdaMetafactory; -import java.lang.reflect.Modifier; /** * Represents a function reference. diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionRefTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionRefTests.java index 8790ba61e40..00e52f056d9 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionRefTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionRefTests.java @@ -114,7 +114,6 @@ public class FunctionRefTests extends ScriptTestCase { "List l = new ArrayList(); l.add(2); l.add(1); l.sort(this::mycompare); return l.get(0);")); } - @AwaitsFix(bugUrl = "working on it") public void testOwnStaticMethodReferenceDef() { assertEquals(2, exec("int mycompare(int i, int j) { j - i } " + "def l = new ArrayList(); l.add(2); l.add(1); l.sort(this::mycompare); return l.get(0);"));