diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java index 8adae6607a9..1d1498a51c4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java @@ -41,6 +41,29 @@ import java.util.Set; import static org.elasticsearch.painless.WriterConstants.LAMBDA_BOOTSTRAP_HANDLE; +/** + * Lambda expression node. + *

+ * This can currently only be the direct argument of a call (method/constructor). + * When the argument is of a known type, it uses + * + * Java's lambda translation. However, if its a def call, then we don't have + * enough information, and have to defer this until link time. In that case a placeholder + * and all captures are pushed onto the stack and folded into the signature of the parent call. + *

+ * For example: + *
+ * {@code def list = new ArrayList(); int capture = 0; list.sort((x,y) -> x - y + capture)} + *
+ * is converted into a call (pseudocode) such as: + *
+ * {@code sort(list, lambda$0, capture)} + *
+ * At link time, when we know the interface type, this is decomposed with MethodHandle + * combinators back into (pseudocode): + *
+ * {@code sort(list, lambda$0(capture))} + */ public class ELambda extends AExpression implements ILambda { final String name; final FunctionReserved reserved; diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/LambdaTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/LambdaTests.java index 01aeb440694..c321b010ecf 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/LambdaTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/LambdaTests.java @@ -85,6 +85,24 @@ public class LambdaTests extends ScriptTestCase { public void testUnneededCurlyStatements() { assertEquals(2, exec("int applyOne(IntFunction arg) { arg.apply(1) } applyOne(x -> { x + 1 })")); } + + /** interface ignores return value */ + public void testVoidReturn() { + assertEquals(2, exec("List list = new ArrayList(); " + + "list.add(2); " + + "List list2 = new ArrayList(); " + + "list.forEach(x -> list2.add(x));" + + "return list[0]")); + } + + /** interface ignores return value */ + public void testVoidReturnDef() { + assertEquals(2, exec("def list = new ArrayList(); " + + "list.add(2); " + + "List list2 = new ArrayList(); " + + "list.forEach(x -> list2.add(x));" + + "return list[0]")); + } public void testTwoLambdas() { assertEquals("testingcdefg", exec(