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(