diff --git a/modules/lang-painless/src/main/antlr/PainlessParser.g4 b/modules/lang-painless/src/main/antlr/PainlessParser.g4
index 5125e7b29a6..0abab56dad2 100644
--- a/modules/lang-painless/src/main/antlr/PainlessParser.g4
+++ b/modules/lang-painless/src/main/antlr/PainlessParser.g4
@@ -73,7 +73,7 @@ decltype
;
funcref
- : TYPE REF ID
+ : TYPE REF ( ID | NEW )
;
declvar
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 bd8e09f504b..60c42e2af55 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
@@ -22,6 +22,9 @@ package org.elasticsearch.painless;
import org.elasticsearch.painless.Definition.Method;
import org.elasticsearch.painless.Definition.RuntimeClass;
+import java.lang.invoke.CallSite;
+import java.lang.invoke.LambdaConversionException;
+import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
@@ -123,7 +126,52 @@ public final class Def {
}
/**
- * Looks up handle for a dynamic method call.
+ * Looks up method entry for a dynamic method call.
+ *
+ * A dynamic method call for variable {@code x} of type {@code def} looks like:
+ * {@code x.method(args...)}
+ *
+ * This method traverses {@code recieverClass}'s class hierarchy (including interfaces)
+ * until it finds a matching whitelisted method. If one is not found, it throws an exception.
+ * Otherwise it returns the matching method.
+ *
+ * @param receiverClass Class of the object to invoke the method on.
+ * @param name Name of the method.
+ * @param arity arity of method
+ * @return matching method to invoke. never returns null.
+ * @throws IllegalArgumentException if no matching whitelisted method was found.
+ */
+ static Method lookupMethodInternal(Class> receiverClass, String name, int arity) {
+ Definition.MethodKey key = new Definition.MethodKey(name, arity);
+ // check whitelist for matching method
+ for (Class> clazz = receiverClass; clazz != null; clazz = clazz.getSuperclass()) {
+ RuntimeClass struct = Definition.getRuntimeClass(clazz);
+
+ if (struct != null) {
+ Method method = struct.methods.get(key);
+ if (method != null) {
+ return method;
+ }
+ }
+
+ for (Class> iface : clazz.getInterfaces()) {
+ struct = Definition.getRuntimeClass(iface);
+
+ if (struct != null) {
+ Method method = struct.methods.get(key);
+ if (method != null) {
+ return method;
+ }
+ }
+ }
+ }
+
+ throw new IllegalArgumentException("Unable to find dynamic method [" + name + "] with [" + arity + "] arguments " +
+ "for class [" + receiverClass.getCanonicalName() + "].");
+ }
+
+ /**
+ * Looks up handle for a dynamic method call, with lambda replacement
*
* A dynamic method call for variable {@code x} of type {@code def} looks like:
* {@code x.method(args...)}
@@ -134,41 +182,72 @@ public final class Def {
*
* @param receiverClass Class of the object to invoke the method on.
* @param name Name of the method.
- * @param type Callsite signature. Need not match exactly, except the number of parameters.
+ * @param args args passed to callsite
+ * @param recipe bitset marking functional parameters
* @return pointer to matching method to invoke. never returns null.
* @throws IllegalArgumentException if no matching whitelisted method was found.
*/
- static MethodHandle lookupMethod(Class> receiverClass, String name, MethodType type) {
- // we don't consider receiver an argument/counting towards arity
- type = type.dropParameterTypes(0, 1);
- Definition.MethodKey key = new Definition.MethodKey(name, type.parameterCount());
- // check whitelist for matching method
- for (Class> clazz = receiverClass; clazz != null; clazz = clazz.getSuperclass()) {
- RuntimeClass struct = Definition.getRuntimeClass(clazz);
+ static MethodHandle lookupMethod(Class> receiverClass, String name, Object args[], long recipe) {
+ Method method = lookupMethodInternal(receiverClass, name, args.length - 1);
+ MethodHandle handle = method.handle;
+ MethodHandle filters[] = new MethodHandle[args.length];
- if (struct != null) {
- Method method = struct.methods.get(key);
- if (method != null) {
- return method.handle;
- }
- }
-
- for (final Class> iface : clazz.getInterfaces()) {
- struct = Definition.getRuntimeClass(iface);
-
- if (struct != null) {
- Method method = struct.methods.get(key);
- if (method != null) {
- return method.handle;
- }
+ if (recipe != 0) {
+ for (int i = 0; i < args.length; i++) {
+ // its a functional reference, replace the argument with an impl
+ if ((recipe & (1L << (i - 1))) != 0) {
+ filters[i] = lookupReference(method.arguments.get(i - 1).clazz, (String) args[i]);
}
}
}
-
- // no matching methods in whitelist found
- throw new IllegalArgumentException("Unable to find dynamic method [" + name + "] with signature [" + type + "] " +
- "for class [" + receiverClass.getCanonicalName() + "].");
- }
+ handle = MethodHandles.filterArguments(handle, 0, filters);
+
+ return handle;
+ }
+
+ /** Returns a method handle to an implementation of clazz, given method reference signature */
+ private static MethodHandle lookupReference(Class> clazz, String signature) {
+ int separator = signature.indexOf('.');
+ FunctionRef ref = new FunctionRef(clazz, signature.substring(0, separator), signature.substring(separator+1));
+ MethodHandles.Lookup lookup = MethodHandles.lookup(); // XXX: no lookuping needed, we should pass this from DefBootstrap!
+ final CallSite callSite;
+ // XXX: clean all this up to use handles in FunctionRef, deal with ASM in EFunctionRef differently
+ MethodType invokedType = MethodType.fromMethodDescriptorString(ref.invokedType.getDescriptor(), Def.class.getClassLoader());
+ MethodType samMethodType = MethodType.fromMethodDescriptorString(ref.samMethodType.getDescriptor(), Def.class.getClassLoader());
+ MethodType interfaceType = MethodType.fromMethodDescriptorString(ref.interfaceType.getDescriptor(), Def.class.getClassLoader());
+ try {
+ if (ref.interfaceType.equals(ref.samMethodType)) {
+ callSite = LambdaMetafactory.altMetafactory(lookup,
+ ref.invokedName,
+ invokedType,
+ samMethodType,
+ ref.implMethodHandle,
+ samMethodType,
+ 0);
+ } else {
+ callSite = LambdaMetafactory.altMetafactory(lookup,
+ ref.invokedName,
+ invokedType,
+ samMethodType,
+ ref.implMethodHandle,
+ samMethodType,
+ LambdaMetafactory.FLAG_BRIDGES,
+ 1,
+ interfaceType);
+ }
+ } catch (LambdaConversionException e) {
+ throw new RuntimeException(e);
+ }
+ try {
+ // create an implementation of the interface (instance)
+ Object instance = callSite.dynamicInvoker().asType(MethodType.methodType(clazz)).invoke();
+ // bind this instance as a constant replacement for the parameter
+ return MethodHandles.dropArguments(MethodHandles.constant(clazz, instance), 0, Object.class);
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
/**
* Looks up handle for a dynamic field getter (field load)
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java
index 40b9cc6cbe8..4c30891dd2d 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java
@@ -66,12 +66,16 @@ public final class DefBootstrap {
private final String name;
private final int flavor;
+ private final long recipe;
int depth; // pkg-protected for testing
- PIC(String name, MethodType type, int flavor) {
+ PIC(String name, MethodType type, int flavor, long recipe) {
super(type);
this.name = name;
this.flavor = flavor;
+ this.recipe = recipe;
+ assert recipe == 0 || flavor == METHOD_CALL;
+ assert Long.bitCount(flavor) <= type.parameterCount();
final MethodHandle fallback = FALLBACK.bindTo(this)
.asCollector(Object[].class, type.parameterCount())
@@ -91,10 +95,10 @@ public final class DefBootstrap {
/**
* Does a slow lookup against the whitelist.
*/
- private static MethodHandle lookup(int flavor, Class> clazz, String name, MethodType type) {
+ private static MethodHandle lookup(int flavor, Class> clazz, String name, Object[] args, long recipe) {
switch(flavor) {
case METHOD_CALL:
- return Def.lookupMethod(clazz, name, type);
+ return Def.lookupMethod(clazz, name, args, recipe);
case LOAD:
return Def.lookupGetter(clazz, name);
case STORE:
@@ -115,7 +119,7 @@ public final class DefBootstrap {
final MethodType type = type();
final Object receiver = args[0];
final Class> receiverClass = receiver.getClass();
- final MethodHandle target = lookup(flavor, receiverClass, name, type).asType(type);
+ final MethodHandle target = lookup(flavor, receiverClass, name, args, recipe).asType(type);
if (depth >= MAX_DEPTH) {
// revert to a vtable call
@@ -157,8 +161,8 @@ public final class DefBootstrap {
*
* see https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokedynamic
*/
- public static CallSite bootstrap(Lookup lookup, String name, MethodType type, int flavor) {
- return new PIC(name, type, flavor);
+ public static CallSite bootstrap(Lookup lookup, String name, MethodType type, int flavor, long recipe) {
+ return new PIC(name, type, flavor, recipe);
}
}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java
index 50ee4649074..061ef0d95d7 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java
@@ -24,6 +24,7 @@ import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Modifier;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
@@ -31,6 +32,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
/**
* The entire API for Painless. Also used as a whitelist for checking for legal
@@ -171,21 +174,6 @@ public final class Definition {
}
}
- public static final class Constructor {
- public final String name;
- public final Struct owner;
- public final List arguments;
- public final org.objectweb.asm.commons.Method method;
-
- private Constructor(String name, Struct owner, List arguments,
- org.objectweb.asm.commons.Method method) {
- this.name = name;
- this.owner = owner;
- this.arguments = Collections.unmodifiableList(arguments);
- this.method = method;
- }
- }
-
public static class Method {
public final String name;
public final Struct owner;
@@ -287,7 +275,7 @@ public final class Definition {
public final Class> clazz;
public final org.objectweb.asm.Type type;
- public final Map constructors;
+ public final Map constructors;
public final Map staticMethods;
public final Map methods;
@@ -439,6 +427,18 @@ public final class Definition {
for (Map.Entry> clazz : hierarchy.entrySet()) {
copyStruct(clazz.getKey(), clazz.getValue());
}
+ // if someone declares an interface type, its still an Object
+ for (Map.Entry clazz : structsMap.entrySet()) {
+ String name = clazz.getKey();
+ Class> javaPeer = clazz.getValue().clazz;
+ if (javaPeer.isInterface()) {
+ copyStruct(name, Collections.singletonList("Object"));
+ } else if (name.equals("def") == false && name.equals("Object") == false && javaPeer.isPrimitive() == false) {
+ // but otherwise, unless its a primitive type, it really should
+ assert hierarchy.get(name) != null : "class '" + name + "' does not extend Object!";
+ assert hierarchy.get(name).contains("Object") : "class '" + name + "' does not extend Object!";
+ }
+ }
// precompute runtime classes
for (Struct struct : structsMap.values()) {
addRuntimeClass(struct);
@@ -573,7 +573,7 @@ public final class Definition {
"Owner struct [" + struct + "] not defined for constructor [" + name + "].");
}
- if (!name.matches("^[_a-zA-Z][_a-zA-Z0-9]*$")) {
+ if (!name.matches("")) {
throw new IllegalArgumentException(
"Invalid constructor name [" + name + "] with the struct [" + owner.name + "].");
}
@@ -611,7 +611,18 @@ public final class Definition {
}
final org.objectweb.asm.commons.Method asm = org.objectweb.asm.commons.Method.getMethod(reflect);
- final Constructor constructor = new Constructor(name, owner, Arrays.asList(args), asm);
+ final Type returnType = getTypeInternal("void");
+ final MethodHandle handle;
+
+ try {
+ handle = MethodHandles.publicLookup().in(owner.clazz).unreflectConstructor(reflect);
+ } catch (final IllegalAccessException exception) {
+ throw new IllegalArgumentException("Constructor " +
+ " not found for class [" + owner.clazz.getName() + "]" +
+ " with arguments " + Arrays.toString(classes) + ".");
+ }
+
+ final Method constructor = new Method(name, owner, returnType, Arrays.asList(args), asm, reflect.getModifiers(), handle);
owner.constructors.put(methodKey, constructor);
}
@@ -653,7 +664,7 @@ public final class Definition {
if (!elements[0].equals(className)) {
throw new IllegalArgumentException("Constructors must return their own type");
}
- addConstructorInternal(className, "new", args);
+ addConstructorInternal(className, "", args);
} else {
if (methodName.indexOf('/') >= 0) {
String nameAndAlias[] = methodName.split("/");
@@ -720,7 +731,7 @@ public final class Definition {
" method [" + name + "]" +
" within the struct [" + owner.name + "].");
}
-
+
final org.objectweb.asm.commons.Method asm = org.objectweb.asm.commons.Method.getMethod(reflect);
MethodHandle handle;
@@ -821,11 +832,37 @@ public final class Definition {
throw new ClassCastException("Child struct [" + child.name + "]" +
" is not a super type of owner struct [" + owner.name + "] in copy.");
}
-
+
for (Map.Entry kvPair : child.methods.entrySet()) {
MethodKey methodKey = kvPair.getKey();
Method method = kvPair.getValue();
if (owner.methods.get(methodKey) == null) {
+ // sanity check, look for missing covariant/generic override
+ if (owner.clazz.isInterface() && child.clazz == Object.class) {
+ // ok
+ } else if (child.clazz == Spliterator.OfPrimitive.class || child.clazz == PrimitiveIterator.class) {
+ // ok, we rely on generics erasure for these (its guaranteed in the javadocs though!!!!)
+ } else {
+ try {
+ Class> arguments[] = new Class>[method.arguments.size()];
+ for (int i = 0; i < method.arguments.size(); i++) {
+ arguments[i] = method.arguments.get(i).clazz;
+ }
+ java.lang.reflect.Method m = owner.clazz.getMethod(method.method.getName(), arguments);
+ if (m.getReturnType() != method.rtn.clazz) {
+ throw new IllegalStateException("missing covariant override for: " + m + " in " + owner.name);
+ }
+ if (m.isBridge() && !Modifier.isVolatile(method.modifiers)) {
+ // its a bridge in the destination, but not in the source, but it might still be ok, check generics:
+ java.lang.reflect.Method source = child.clazz.getMethod(method.method.getName(), arguments);
+ if (!Arrays.equals(source.getGenericParameterTypes(), source.getParameterTypes())) {
+ throw new IllegalStateException("missing generic override for: " + m + " in " + owner.name);
+ }
+ }
+ } catch (ReflectiveOperationException e) {
+ throw new AssertionError(e);
+ }
+ }
owner.methods.put(methodKey,
new Method(method.name, owner, method.rtn, method.arguments, method.method, method.modifiers, method.handle));
}
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
new file mode 100644
index 00000000000..5b121d3a31a
--- /dev/null
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.painless;
+
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.reflect.Modifier;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * computes "everything you need" to call LambdaMetaFactory, given an expected interface,
+ * and reference class + method name
+ */
+public class FunctionRef {
+ // XXX: this is a mess, because of ASM versus MethodHandle types
+ // clean all this up, move reflection out of here into definition, etc etc
+ public final String invokedName;
+ public final Type invokedType;
+ public final Handle implMethod;
+ public final Type samMethodType;
+ public final Type interfaceType;
+
+ public final MethodHandle implMethodHandle;
+
+ public FunctionRef(Class> expected, String type, String call) {
+ boolean isCtorReference = "new".equals(call);
+ // check its really a functional interface
+ // for e.g. Comparable
+ java.lang.reflect.Method method = getFunctionalMethod(type, call, expected);
+ // e.g. compareTo
+ invokedName = method.getName();
+ // e.g. (Object)Comparator
+ invokedType = Type.getMethodType(Type.getType(expected));
+ // e.g. (Object,Object)int
+ interfaceType = Type.getMethodType(Type.getMethodDescriptor(method));
+ // lookup requested method
+ Definition.Struct struct = Definition.getType(type).struct;
+ final Definition.Method impl;
+ // ctor ref
+ if (isCtorReference) {
+ impl = struct.constructors.get(new Definition.MethodKey("", method.getParameterCount()));
+ } else {
+ // look for a static impl first
+ Definition.Method staticImpl = struct.staticMethods.get(new Definition.MethodKey(call, method.getParameterCount()));
+ if (staticImpl == null) {
+ // otherwise a virtual impl
+ impl = struct.methods.get(new Definition.MethodKey(call, method.getParameterCount()-1));
+ } else {
+ impl = staticImpl;
+ }
+ }
+ if (impl == null) {
+ throw new IllegalArgumentException("Unknown reference [" + type + "::" + call + "] matching " +
+ "[" + expected + "]");
+ }
+
+ final int tag;
+ if (isCtorReference) {
+ tag = Opcodes.H_NEWINVOKESPECIAL;
+ } else if (Modifier.isStatic(impl.modifiers)) {
+ tag = Opcodes.H_INVOKESTATIC;
+ } else {
+ tag = Opcodes.H_INVOKEVIRTUAL;
+ }
+ implMethod = new Handle(tag, struct.type.getInternalName(), impl.name, impl.method.getDescriptor());
+ implMethodHandle = impl.handle;
+ if (isCtorReference) {
+ samMethodType = Type.getMethodType(interfaceType.getReturnType(), impl.method.getArgumentTypes());
+ } else if (Modifier.isStatic(impl.modifiers)) {
+ samMethodType = Type.getMethodType(impl.method.getReturnType(), impl.method.getArgumentTypes());
+ } else {
+ Type[] argTypes = impl.method.getArgumentTypes();
+ Type[] params = new Type[argTypes.length + 1];
+ System.arraycopy(argTypes, 0, params, 1, argTypes.length);
+ params[0] = struct.type;
+ samMethodType = Type.getMethodType(impl.method.getReturnType(), params);
+ }
+ }
+
+ static final Set OBJECT_METHODS = new HashSet<>();
+ static {
+ for (java.lang.reflect.Method m : Object.class.getMethods()) {
+ OBJECT_METHODS.add(new Definition.MethodKey(m.getName(), m.getParameterCount()));
+ }
+ }
+
+ // TODO: move all this crap out, to Definition to compute up front
+ java.lang.reflect.Method getFunctionalMethod(String type, String call, Class> clazz) {
+ if (!clazz.isInterface()) {
+ throw new IllegalArgumentException("Cannot convert function reference ["
+ + type + "::" + call + "] to [" + clazz + "]");
+ }
+ for (java.lang.reflect.Method m : clazz.getMethods()) {
+ if (m.isDefault()) {
+ continue;
+ }
+ if (OBJECT_METHODS.contains(new Definition.MethodKey(m.getName(), m.getParameterCount()))) {
+ continue;
+ }
+ return m;
+ }
+ throw new IllegalArgumentException("Cannot convert function reference ["
+ + type + "::" + call + "] to [" + clazz + "]");
+ }
+}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java
index 4971c08b086..0d8d9fa4a8b 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java
@@ -40,7 +40,6 @@ import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptImpl.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptImpl.java
index 380b6c2bf21..52388a5942e 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptImpl.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptImpl.java
@@ -119,7 +119,7 @@ final class ScriptImpl implements ExecutableScript, LeafSearchScript {
public Object run() {
try {
return executable.execute(variables, scorer, doc, aggregationValue);
- } catch (PainlessError | Exception t) {
+ } catch (PainlessError | BootstrapMethodError | Exception t) {
throw convertToScriptException(t);
}
}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java
index a4804cde434..1e10446e7b4 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java
@@ -27,6 +27,8 @@ import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method;
import java.lang.invoke.CallSite;
+import java.lang.invoke.LambdaMetafactory;
+import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.BitSet;
@@ -62,7 +64,7 @@ public final class WriterConstants {
/** dynamic callsite bootstrap signature */
public final static MethodType DEF_BOOTSTRAP_TYPE =
- MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class);
+ MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class, long.class);
public final static Handle DEF_BOOTSTRAP_HANDLE =
new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(DefBootstrap.class),
"bootstrap", DEF_BOOTSTRAP_TYPE.toMethodDescriptorString());
@@ -101,7 +103,15 @@ public final class WriterConstants {
public final static Method DEF_LTE_CALL = getAsmMethod(boolean.class, "lte", Object.class, Object.class);
public final static Method DEF_GT_CALL = getAsmMethod(boolean.class, "gt" , Object.class, Object.class);
public final static Method DEF_GTE_CALL = getAsmMethod(boolean.class, "gte", Object.class, Object.class);
-
+
+ /** invokedynamic bootstrap for lambda expression/method references */
+ public final static MethodType LAMBDA_BOOTSTRAP_TYPE =
+ MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class,
+ MethodType.class, Object[].class);
+ public final static Handle LAMBDA_BOOTSTRAP_HANDLE =
+ new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(LambdaMetafactory.class),
+ "altMetafactory", LAMBDA_BOOTSTRAP_TYPE.toMethodDescriptorString());
+
/** dynamic invokedynamic bootstrap for indy string concats (Java 9+) */
public final static Handle INDY_STRING_CONCAT_BOOTSTRAP_HANDLE;
static {
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java
index 98eb16732fd..a0903de5574 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java
@@ -986,6 +986,7 @@ class PainlessParser extends Parser {
public TerminalNode TYPE() { return getToken(PainlessParser.TYPE, 0); }
public TerminalNode REF() { return getToken(PainlessParser.REF, 0); }
public TerminalNode ID() { return getToken(PainlessParser.ID, 0); }
+ public TerminalNode NEW() { return getToken(PainlessParser.NEW, 0); }
public FuncrefContext(ParserRuleContext parent, int invokingState) {
super(parent, invokingState);
}
@@ -1000,6 +1001,7 @@ class PainlessParser extends Parser {
public final FuncrefContext funcref() throws RecognitionException {
FuncrefContext _localctx = new FuncrefContext(_ctx, getState());
enterRule(_localctx, 18, RULE_funcref);
+ int _la;
try {
enterOuterAlt(_localctx, 1);
{
@@ -1008,7 +1010,12 @@ class PainlessParser extends Parser {
setState(162);
match(REF);
setState(163);
- match(ID);
+ _la = _input.LA(1);
+ if ( !(_la==NEW || _la==ID) ) {
+ _errHandler.recoverInline(this);
+ } else {
+ consume();
+ }
}
}
catch (RecognitionException re) {
@@ -2623,112 +2630,112 @@ class PainlessParser extends Parser {
"\24\3\24\3\24\3\24\3\24\5\24\u015f\n\24\3\25\3\25\3\25\3\25\3\26\3\26"+
"\3\26\3\26\7\26\u0169\n\26\f\26\16\26\u016c\13\26\5\26\u016e\n\26\3\26"+
"\3\26\3\27\3\27\5\27\u0174\n\27\3\27\2\3\34\30\2\4\6\b\n\f\16\20\22\24"+
- "\26\30\32\34\36 \"$&(*,\2\r\3\3\r\r\3\2\66A\3\2\34\36\3\2\37 \3\2!#\3"+
- "\2$\'\3\2(+\3\2\64\65\3\2BE\4\2\32\33\37 \3\2LM\u019b\2\61\3\2\2\2\4{"+
- "\3\2\2\2\6\177\3\2\2\2\b\u0081\3\2\2\2\n\u008a\3\2\2\2\f\u008e\3\2\2\2"+
- "\16\u0090\3\2\2\2\20\u0092\3\2\2\2\22\u009b\3\2\2\2\24\u00a3\3\2\2\2\26"+
- "\u00a7\3\2\2\2\30\u00ac\3\2\2\2\32\u00b3\3\2\2\2\34\u00be\3\2\2\2\36\u011b"+
- "\3\2\2\2 \u013f\3\2\2\2\"\u0151\3\2\2\2$\u0157\3\2\2\2&\u015e\3\2\2\2"+
- "(\u0160\3\2\2\2*\u0164\3\2\2\2,\u0173\3\2\2\2.\60\5\4\3\2/.\3\2\2\2\60"+
- "\63\3\2\2\2\61/\3\2\2\2\61\62\3\2\2\2\62\64\3\2\2\2\63\61\3\2\2\2\64\65"+
- "\7\2\2\3\65\3\3\2\2\2\66\67\7\16\2\2\678\7\t\2\289\5\34\17\29:\7\n\2\2"+
- ":>\5\6\4\2;<\7\17\2\2\5\6\4\2=?\6\3\2\2>;\3\2\2\2>=\3\2\2\2?|\3\2\2"+
- "\2@A\7\20\2\2AB\7\t\2\2BC\5\34\17\2CF\7\n\2\2DG\5\6\4\2EG\5\n\6\2FD\3"+
- "\2\2\2FE\3\2\2\2G|\3\2\2\2HI\7\21\2\2IJ\5\b\5\2JK\7\20\2\2KL\7\t\2\2L"+
- "M\5\34\17\2MN\7\n\2\2NO\5\32\16\2O|\3\2\2\2PQ\7\22\2\2QS\7\t\2\2RT\5\f"+
- "\7\2SR\3\2\2\2ST\3\2\2\2TU\3\2\2\2UW\7\r\2\2VX\5\34\17\2WV\3\2\2\2WX\3"+
- "\2\2\2XY\3\2\2\2Y[\7\r\2\2Z\\\5\16\b\2[Z\3\2\2\2[\\\3\2\2\2\\]\3\2\2\2"+
- "]`\7\n\2\2^a\5\6\4\2_a\5\n\6\2`^\3\2\2\2`_\3\2\2\2a|\3\2\2\2bc\5\20\t"+
- "\2cd\5\32\16\2d|\3\2\2\2ef\7\23\2\2f|\5\32\16\2gh\7\24\2\2h|\5\32\16\2"+
- "ij\7\25\2\2jk\5\34\17\2kl\5\32\16\2l|\3\2\2\2mn\7\27\2\2np\5\b\5\2oq\5"+
- "\30\r\2po\3\2\2\2qr\3\2\2\2rp\3\2\2\2rs\3\2\2\2s|\3\2\2\2tu\7\31\2\2u"+
- "v\5\34\17\2vw\5\32\16\2w|\3\2\2\2xy\5\34\17\2yz\5\32\16\2z|\3\2\2\2{\66"+
- "\3\2\2\2{@\3\2\2\2{H\3\2\2\2{P\3\2\2\2{b\3\2\2\2{e\3\2\2\2{g\3\2\2\2{"+
- "i\3\2\2\2{m\3\2\2\2{t\3\2\2\2{x\3\2\2\2|\5\3\2\2\2}\u0080\5\b\5\2~\u0080"+
- "\5\4\3\2\177}\3\2\2\2\177~\3\2\2\2\u0080\7\3\2\2\2\u0081\u0085\7\5\2\2"+
- "\u0082\u0084\5\4\3\2\u0083\u0082\3\2\2\2\u0084\u0087\3\2\2\2\u0085\u0083"+
- "\3\2\2\2\u0085\u0086\3\2\2\2\u0086\u0088\3\2\2\2\u0087\u0085\3\2\2\2\u0088"+
- "\u0089\7\6\2\2\u0089\t\3\2\2\2\u008a\u008b\7\r\2\2\u008b\13\3\2\2\2\u008c"+
- "\u008f\5\20\t\2\u008d\u008f\5\34\17\2\u008e\u008c\3\2\2\2\u008e\u008d"+
- "\3\2\2\2\u008f\r\3\2\2\2\u0090\u0091\5\34\17\2\u0091\17\3\2\2\2\u0092"+
- "\u0093\5\22\n\2\u0093\u0098\5\26\f\2\u0094\u0095\7\f\2\2\u0095\u0097\5"+
- "\26\f\2\u0096\u0094\3\2\2\2\u0097\u009a\3\2\2\2\u0098\u0096\3\2\2\2\u0098"+
- "\u0099\3\2\2\2\u0099\21\3\2\2\2\u009a\u0098\3\2\2\2\u009b\u00a0\7J\2\2"+
- "\u009c\u009d\7\7\2\2\u009d\u009f\7\b\2\2\u009e\u009c\3\2\2\2\u009f\u00a2"+
- "\3\2\2\2\u00a0\u009e\3\2\2\2\u00a0\u00a1\3\2\2\2\u00a1\23\3\2\2\2\u00a2"+
- "\u00a0\3\2\2\2\u00a3\u00a4\7J\2\2\u00a4\u00a5\7\63\2\2\u00a5\u00a6\7K"+
- "\2\2\u00a6\25\3\2\2\2\u00a7\u00aa\7K\2\2\u00a8\u00a9\7\66\2\2\u00a9\u00ab"+
- "\5\34\17\2\u00aa\u00a8\3\2\2\2\u00aa\u00ab\3\2\2\2\u00ab\27\3\2\2\2\u00ac"+
- "\u00ad\7\30\2\2\u00ad\u00ae\7\t\2\2\u00ae\u00af\7J\2\2\u00af\u00b0\7K"+
- "\2\2\u00b0\u00b1\7\n\2\2\u00b1\u00b2\5\b\5\2\u00b2\31\3\2\2\2\u00b3\u00b4"+
- "\t\2\2\2\u00b4\33\3\2\2\2\u00b5\u00b6\b\17\1\2\u00b6\u00b7\5 \21\2\u00b7"+
- "\u00b8\t\3\2\2\u00b8\u00b9\5\34\17\3\u00b9\u00ba\b\17\1\2\u00ba\u00bf"+
- "\3\2\2\2\u00bb\u00bc\5\36\20\2\u00bc\u00bd\b\17\1\2\u00bd\u00bf\3\2\2"+
- "\2\u00be\u00b5\3\2\2\2\u00be\u00bb\3\2\2\2\u00bf\u00fb\3\2\2\2\u00c0\u00c1"+
- "\f\16\2\2\u00c1\u00c2\t\4\2\2\u00c2\u00c3\5\34\17\17\u00c3\u00c4\b\17"+
- "\1\2\u00c4\u00fa\3\2\2\2\u00c5\u00c6\f\r\2\2\u00c6\u00c7\t\5\2\2\u00c7"+
- "\u00c8\5\34\17\16\u00c8\u00c9\b\17\1\2\u00c9\u00fa\3\2\2\2\u00ca\u00cb"+
- "\f\f\2\2\u00cb\u00cc\t\6\2\2\u00cc\u00cd\5\34\17\r\u00cd\u00ce\b\17\1"+
- "\2\u00ce\u00fa\3\2\2\2\u00cf\u00d0\f\13\2\2\u00d0\u00d1\t\7\2\2\u00d1"+
- "\u00d2\5\34\17\f\u00d2\u00d3\b\17\1\2\u00d3\u00fa\3\2\2\2\u00d4\u00d5"+
- "\f\n\2\2\u00d5\u00d6\t\b\2\2\u00d6\u00d7\5\34\17\13\u00d7\u00d8\b\17\1"+
- "\2\u00d8\u00fa\3\2\2\2\u00d9\u00da\f\t\2\2\u00da\u00db\7,\2\2\u00db\u00dc"+
- "\5\34\17\n\u00dc\u00dd\b\17\1\2\u00dd\u00fa\3\2\2\2\u00de\u00df\f\b\2"+
- "\2\u00df\u00e0\7-\2\2\u00e0\u00e1\5\34\17\t\u00e1\u00e2\b\17\1\2\u00e2"+
- "\u00fa\3\2\2\2\u00e3\u00e4\f\7\2\2\u00e4\u00e5\7.\2\2\u00e5\u00e6\5\34"+
- "\17\b\u00e6\u00e7\b\17\1\2\u00e7\u00fa\3\2\2\2\u00e8\u00e9\f\6\2\2\u00e9"+
- "\u00ea\7/\2\2\u00ea\u00eb\5\34\17\7\u00eb\u00ec\b\17\1\2\u00ec\u00fa\3"+
- "\2\2\2\u00ed\u00ee\f\5\2\2\u00ee\u00ef\7\60\2\2\u00ef\u00f0\5\34\17\6"+
- "\u00f0\u00f1\b\17\1\2\u00f1\u00fa\3\2\2\2\u00f2\u00f3\f\4\2\2\u00f3\u00f4"+
- "\7\61\2\2\u00f4\u00f5\5\34\17\2\u00f5\u00f6\7\62\2\2\u00f6\u00f7\5\34"+
- "\17\4\u00f7\u00f8\b\17\1\2\u00f8\u00fa\3\2\2\2\u00f9\u00c0\3\2\2\2\u00f9"+
- "\u00c5\3\2\2\2\u00f9\u00ca\3\2\2\2\u00f9\u00cf\3\2\2\2\u00f9\u00d4\3\2"+
- "\2\2\u00f9\u00d9\3\2\2\2\u00f9\u00de\3\2\2\2\u00f9\u00e3\3\2\2\2\u00f9"+
- "\u00e8\3\2\2\2\u00f9\u00ed\3\2\2\2\u00f9\u00f2\3\2\2\2\u00fa\u00fd\3\2"+
- "\2\2\u00fb\u00f9\3\2\2\2\u00fb\u00fc\3\2\2\2\u00fc\35\3\2\2\2\u00fd\u00fb"+
- "\3\2\2\2\u00fe\u00ff\6\20\16\3\u00ff\u0100\t\t\2\2\u0100\u011c\5 \21\2"+
- "\u0101\u0102\6\20\17\3\u0102\u0103\5 \21\2\u0103\u0104\t\t\2\2\u0104\u011c"+
- "\3\2\2\2\u0105\u0106\6\20\20\3\u0106\u011c\5 \21\2\u0107\u0108\6\20\21"+
- "\3\u0108\u0109\t\n\2\2\u0109\u011c\b\20\1\2\u010a\u010b\6\20\22\3\u010b"+
- "\u010c\7G\2\2\u010c\u011c\b\20\1\2\u010d\u010e\6\20\23\3\u010e\u010f\7"+
- "H\2\2\u010f\u011c\b\20\1\2\u0110\u0111\6\20\24\3\u0111\u0112\7I\2\2\u0112"+
- "\u011c\b\20\1\2\u0113\u0114\6\20\25\3\u0114\u0115\t\13\2\2\u0115\u011c"+
- "\5\36\20\2\u0116\u0117\7\t\2\2\u0117\u0118\5\22\n\2\u0118\u0119\7\n\2"+
- "\2\u0119\u011a\5\36\20\2\u011a\u011c\3\2\2\2\u011b\u00fe\3\2\2\2\u011b"+
- "\u0101\3\2\2\2\u011b\u0105\3\2\2\2\u011b\u0107\3\2\2\2\u011b\u010a\3\2"+
- "\2\2\u011b\u010d\3\2\2\2\u011b\u0110\3\2\2\2\u011b\u0113\3\2\2\2\u011b"+
- "\u0116\3\2\2\2\u011c\37\3\2\2\2\u011d\u0121\5\"\22\2\u011e\u0120\5$\23"+
- "\2\u011f\u011e\3\2\2\2\u0120\u0123\3\2\2\2\u0121\u011f\3\2\2\2\u0121\u0122"+
- "\3\2\2\2\u0122\u0140\3\2\2\2\u0123\u0121\3\2\2\2\u0124\u0125\5\22\n\2"+
- "\u0125\u0129\5&\24\2\u0126\u0128\5$\23\2\u0127\u0126\3\2\2\2\u0128\u012b"+
- "\3\2\2\2\u0129\u0127\3\2\2\2\u0129\u012a\3\2\2\2\u012a\u0140\3\2\2\2\u012b"+
- "\u0129\3\2\2\2\u012c\u012d\7\26\2\2\u012d\u0132\7J\2\2\u012e\u012f\7\7"+
- "\2\2\u012f\u0130\5\34\17\2\u0130\u0131\7\b\2\2\u0131\u0133\3\2\2\2\u0132"+
- "\u012e\3\2\2\2\u0133\u0134\3\2\2\2\u0134\u0132\3\2\2\2\u0134\u0135\3\2"+
- "\2\2\u0135\u013d\3\2\2\2\u0136\u013a\5&\24\2\u0137\u0139\5$\23\2\u0138"+
- "\u0137\3\2\2\2\u0139\u013c\3\2\2\2\u013a\u0138\3\2\2\2\u013a\u013b\3\2"+
- "\2\2\u013b\u013e\3\2\2\2\u013c\u013a\3\2\2\2\u013d\u0136\3\2\2\2\u013d"+
- "\u013e\3\2\2\2\u013e\u0140\3\2\2\2\u013f\u011d\3\2\2\2\u013f\u0124\3\2"+
- "\2\2\u013f\u012c\3\2\2\2\u0140!\3\2\2\2\u0141\u0142\6\22\26\3\u0142\u0143"+
- "\7\t\2\2\u0143\u0144\5\34\17\2\u0144\u0145\7\n\2\2\u0145\u0146\b\22\1"+
- "\2\u0146\u0152\3\2\2\2\u0147\u0148\6\22\27\3\u0148\u0149\7\t\2\2\u0149"+
- "\u014a\5\36\20\2\u014a\u014b\7\n\2\2\u014b\u0152\3\2\2\2\u014c\u0152\7"+
- "F\2\2\u014d\u0152\7K\2\2\u014e\u014f\7\26\2\2\u014f\u0150\7J\2\2\u0150"+
- "\u0152\5*\26\2\u0151\u0141\3\2\2\2\u0151\u0147\3\2\2\2\u0151\u014c\3\2"+
- "\2\2\u0151\u014d\3\2\2\2\u0151\u014e\3\2\2\2\u0152#\3\2\2\2\u0153\u0154"+
- "\6\23\30\3\u0154\u0158\5&\24\2\u0155\u0156\6\23\31\3\u0156\u0158\5(\25"+
- "\2\u0157\u0153\3\2\2\2\u0157\u0155\3\2\2\2\u0158%\3\2\2\2\u0159\u015a"+
- "\7\13\2\2\u015a\u015b\7M\2\2\u015b\u015f\5*\26\2\u015c\u015d\7\13\2\2"+
- "\u015d\u015f\t\f\2\2\u015e\u0159\3\2\2\2\u015e\u015c\3\2\2\2\u015f\'\3"+
- "\2\2\2\u0160\u0161\7\7\2\2\u0161\u0162\5\34\17\2\u0162\u0163\7\b\2\2\u0163"+
- ")\3\2\2\2\u0164\u016d\7\t\2\2\u0165\u016a\5,\27\2\u0166\u0167\7\f\2\2"+
- "\u0167\u0169\5,\27\2\u0168\u0166\3\2\2\2\u0169\u016c\3\2\2\2\u016a\u0168"+
- "\3\2\2\2\u016a\u016b\3\2\2\2\u016b\u016e\3\2\2\2\u016c\u016a\3\2\2\2\u016d"+
- "\u0165\3\2\2\2\u016d\u016e\3\2\2\2\u016e\u016f\3\2\2\2\u016f\u0170\7\n"+
- "\2\2\u0170+\3\2\2\2\u0171\u0174\5\34\17\2\u0172\u0174\5\24\13\2\u0173"+
- "\u0171\3\2\2\2\u0173\u0172\3\2\2\2\u0174-\3\2\2\2!\61>FSW[`r{\177\u0085"+
- "\u008e\u0098\u00a0\u00aa\u00be\u00f9\u00fb\u011b\u0121\u0129\u0134\u013a"+
- "\u013d\u013f\u0151\u0157\u015e\u016a\u016d\u0173";
+ "\26\30\32\34\36 \"$&(*,\2\16\4\2\26\26KK\3\3\r\r\3\2\66A\3\2\34\36\3\2"+
+ "\37 \3\2!#\3\2$\'\3\2(+\3\2\64\65\3\2BE\4\2\32\33\37 \3\2LM\u019b\2\61"+
+ "\3\2\2\2\4{\3\2\2\2\6\177\3\2\2\2\b\u0081\3\2\2\2\n\u008a\3\2\2\2\f\u008e"+
+ "\3\2\2\2\16\u0090\3\2\2\2\20\u0092\3\2\2\2\22\u009b\3\2\2\2\24\u00a3\3"+
+ "\2\2\2\26\u00a7\3\2\2\2\30\u00ac\3\2\2\2\32\u00b3\3\2\2\2\34\u00be\3\2"+
+ "\2\2\36\u011b\3\2\2\2 \u013f\3\2\2\2\"\u0151\3\2\2\2$\u0157\3\2\2\2&\u015e"+
+ "\3\2\2\2(\u0160\3\2\2\2*\u0164\3\2\2\2,\u0173\3\2\2\2.\60\5\4\3\2/.\3"+
+ "\2\2\2\60\63\3\2\2\2\61/\3\2\2\2\61\62\3\2\2\2\62\64\3\2\2\2\63\61\3\2"+
+ "\2\2\64\65\7\2\2\3\65\3\3\2\2\2\66\67\7\16\2\2\678\7\t\2\289\5\34\17\2"+
+ "9:\7\n\2\2:>\5\6\4\2;<\7\17\2\2\5\6\4\2=?\6\3\2\2>;\3\2\2\2>=\3\2\2"+
+ "\2?|\3\2\2\2@A\7\20\2\2AB\7\t\2\2BC\5\34\17\2CF\7\n\2\2DG\5\6\4\2EG\5"+
+ "\n\6\2FD\3\2\2\2FE\3\2\2\2G|\3\2\2\2HI\7\21\2\2IJ\5\b\5\2JK\7\20\2\2K"+
+ "L\7\t\2\2LM\5\34\17\2MN\7\n\2\2NO\5\32\16\2O|\3\2\2\2PQ\7\22\2\2QS\7\t"+
+ "\2\2RT\5\f\7\2SR\3\2\2\2ST\3\2\2\2TU\3\2\2\2UW\7\r\2\2VX\5\34\17\2WV\3"+
+ "\2\2\2WX\3\2\2\2XY\3\2\2\2Y[\7\r\2\2Z\\\5\16\b\2[Z\3\2\2\2[\\\3\2\2\2"+
+ "\\]\3\2\2\2]`\7\n\2\2^a\5\6\4\2_a\5\n\6\2`^\3\2\2\2`_\3\2\2\2a|\3\2\2"+
+ "\2bc\5\20\t\2cd\5\32\16\2d|\3\2\2\2ef\7\23\2\2f|\5\32\16\2gh\7\24\2\2"+
+ "h|\5\32\16\2ij\7\25\2\2jk\5\34\17\2kl\5\32\16\2l|\3\2\2\2mn\7\27\2\2n"+
+ "p\5\b\5\2oq\5\30\r\2po\3\2\2\2qr\3\2\2\2rp\3\2\2\2rs\3\2\2\2s|\3\2\2\2"+
+ "tu\7\31\2\2uv\5\34\17\2vw\5\32\16\2w|\3\2\2\2xy\5\34\17\2yz\5\32\16\2"+
+ "z|\3\2\2\2{\66\3\2\2\2{@\3\2\2\2{H\3\2\2\2{P\3\2\2\2{b\3\2\2\2{e\3\2\2"+
+ "\2{g\3\2\2\2{i\3\2\2\2{m\3\2\2\2{t\3\2\2\2{x\3\2\2\2|\5\3\2\2\2}\u0080"+
+ "\5\b\5\2~\u0080\5\4\3\2\177}\3\2\2\2\177~\3\2\2\2\u0080\7\3\2\2\2\u0081"+
+ "\u0085\7\5\2\2\u0082\u0084\5\4\3\2\u0083\u0082\3\2\2\2\u0084\u0087\3\2"+
+ "\2\2\u0085\u0083\3\2\2\2\u0085\u0086\3\2\2\2\u0086\u0088\3\2\2\2\u0087"+
+ "\u0085\3\2\2\2\u0088\u0089\7\6\2\2\u0089\t\3\2\2\2\u008a\u008b\7\r\2\2"+
+ "\u008b\13\3\2\2\2\u008c\u008f\5\20\t\2\u008d\u008f\5\34\17\2\u008e\u008c"+
+ "\3\2\2\2\u008e\u008d\3\2\2\2\u008f\r\3\2\2\2\u0090\u0091\5\34\17\2\u0091"+
+ "\17\3\2\2\2\u0092\u0093\5\22\n\2\u0093\u0098\5\26\f\2\u0094\u0095\7\f"+
+ "\2\2\u0095\u0097\5\26\f\2\u0096\u0094\3\2\2\2\u0097\u009a\3\2\2\2\u0098"+
+ "\u0096\3\2\2\2\u0098\u0099\3\2\2\2\u0099\21\3\2\2\2\u009a\u0098\3\2\2"+
+ "\2\u009b\u00a0\7J\2\2\u009c\u009d\7\7\2\2\u009d\u009f\7\b\2\2\u009e\u009c"+
+ "\3\2\2\2\u009f\u00a2\3\2\2\2\u00a0\u009e\3\2\2\2\u00a0\u00a1\3\2\2\2\u00a1"+
+ "\23\3\2\2\2\u00a2\u00a0\3\2\2\2\u00a3\u00a4\7J\2\2\u00a4\u00a5\7\63\2"+
+ "\2\u00a5\u00a6\t\2\2\2\u00a6\25\3\2\2\2\u00a7\u00aa\7K\2\2\u00a8\u00a9"+
+ "\7\66\2\2\u00a9\u00ab\5\34\17\2\u00aa\u00a8\3\2\2\2\u00aa\u00ab\3\2\2"+
+ "\2\u00ab\27\3\2\2\2\u00ac\u00ad\7\30\2\2\u00ad\u00ae\7\t\2\2\u00ae\u00af"+
+ "\7J\2\2\u00af\u00b0\7K\2\2\u00b0\u00b1\7\n\2\2\u00b1\u00b2\5\b\5\2\u00b2"+
+ "\31\3\2\2\2\u00b3\u00b4\t\3\2\2\u00b4\33\3\2\2\2\u00b5\u00b6\b\17\1\2"+
+ "\u00b6\u00b7\5 \21\2\u00b7\u00b8\t\4\2\2\u00b8\u00b9\5\34\17\3\u00b9\u00ba"+
+ "\b\17\1\2\u00ba\u00bf\3\2\2\2\u00bb\u00bc\5\36\20\2\u00bc\u00bd\b\17\1"+
+ "\2\u00bd\u00bf\3\2\2\2\u00be\u00b5\3\2\2\2\u00be\u00bb\3\2\2\2\u00bf\u00fb"+
+ "\3\2\2\2\u00c0\u00c1\f\16\2\2\u00c1\u00c2\t\5\2\2\u00c2\u00c3\5\34\17"+
+ "\17\u00c3\u00c4\b\17\1\2\u00c4\u00fa\3\2\2\2\u00c5\u00c6\f\r\2\2\u00c6"+
+ "\u00c7\t\6\2\2\u00c7\u00c8\5\34\17\16\u00c8\u00c9\b\17\1\2\u00c9\u00fa"+
+ "\3\2\2\2\u00ca\u00cb\f\f\2\2\u00cb\u00cc\t\7\2\2\u00cc\u00cd\5\34\17\r"+
+ "\u00cd\u00ce\b\17\1\2\u00ce\u00fa\3\2\2\2\u00cf\u00d0\f\13\2\2\u00d0\u00d1"+
+ "\t\b\2\2\u00d1\u00d2\5\34\17\f\u00d2\u00d3\b\17\1\2\u00d3\u00fa\3\2\2"+
+ "\2\u00d4\u00d5\f\n\2\2\u00d5\u00d6\t\t\2\2\u00d6\u00d7\5\34\17\13\u00d7"+
+ "\u00d8\b\17\1\2\u00d8\u00fa\3\2\2\2\u00d9\u00da\f\t\2\2\u00da\u00db\7"+
+ ",\2\2\u00db\u00dc\5\34\17\n\u00dc\u00dd\b\17\1\2\u00dd\u00fa\3\2\2\2\u00de"+
+ "\u00df\f\b\2\2\u00df\u00e0\7-\2\2\u00e0\u00e1\5\34\17\t\u00e1\u00e2\b"+
+ "\17\1\2\u00e2\u00fa\3\2\2\2\u00e3\u00e4\f\7\2\2\u00e4\u00e5\7.\2\2\u00e5"+
+ "\u00e6\5\34\17\b\u00e6\u00e7\b\17\1\2\u00e7\u00fa\3\2\2\2\u00e8\u00e9"+
+ "\f\6\2\2\u00e9\u00ea\7/\2\2\u00ea\u00eb\5\34\17\7\u00eb\u00ec\b\17\1\2"+
+ "\u00ec\u00fa\3\2\2\2\u00ed\u00ee\f\5\2\2\u00ee\u00ef\7\60\2\2\u00ef\u00f0"+
+ "\5\34\17\6\u00f0\u00f1\b\17\1\2\u00f1\u00fa\3\2\2\2\u00f2\u00f3\f\4\2"+
+ "\2\u00f3\u00f4\7\61\2\2\u00f4\u00f5\5\34\17\2\u00f5\u00f6\7\62\2\2\u00f6"+
+ "\u00f7\5\34\17\4\u00f7\u00f8\b\17\1\2\u00f8\u00fa\3\2\2\2\u00f9\u00c0"+
+ "\3\2\2\2\u00f9\u00c5\3\2\2\2\u00f9\u00ca\3\2\2\2\u00f9\u00cf\3\2\2\2\u00f9"+
+ "\u00d4\3\2\2\2\u00f9\u00d9\3\2\2\2\u00f9\u00de\3\2\2\2\u00f9\u00e3\3\2"+
+ "\2\2\u00f9\u00e8\3\2\2\2\u00f9\u00ed\3\2\2\2\u00f9\u00f2\3\2\2\2\u00fa"+
+ "\u00fd\3\2\2\2\u00fb\u00f9\3\2\2\2\u00fb\u00fc\3\2\2\2\u00fc\35\3\2\2"+
+ "\2\u00fd\u00fb\3\2\2\2\u00fe\u00ff\6\20\16\3\u00ff\u0100\t\n\2\2\u0100"+
+ "\u011c\5 \21\2\u0101\u0102\6\20\17\3\u0102\u0103\5 \21\2\u0103\u0104\t"+
+ "\n\2\2\u0104\u011c\3\2\2\2\u0105\u0106\6\20\20\3\u0106\u011c\5 \21\2\u0107"+
+ "\u0108\6\20\21\3\u0108\u0109\t\13\2\2\u0109\u011c\b\20\1\2\u010a\u010b"+
+ "\6\20\22\3\u010b\u010c\7G\2\2\u010c\u011c\b\20\1\2\u010d\u010e\6\20\23"+
+ "\3\u010e\u010f\7H\2\2\u010f\u011c\b\20\1\2\u0110\u0111\6\20\24\3\u0111"+
+ "\u0112\7I\2\2\u0112\u011c\b\20\1\2\u0113\u0114\6\20\25\3\u0114\u0115\t"+
+ "\f\2\2\u0115\u011c\5\36\20\2\u0116\u0117\7\t\2\2\u0117\u0118\5\22\n\2"+
+ "\u0118\u0119\7\n\2\2\u0119\u011a\5\36\20\2\u011a\u011c\3\2\2\2\u011b\u00fe"+
+ "\3\2\2\2\u011b\u0101\3\2\2\2\u011b\u0105\3\2\2\2\u011b\u0107\3\2\2\2\u011b"+
+ "\u010a\3\2\2\2\u011b\u010d\3\2\2\2\u011b\u0110\3\2\2\2\u011b\u0113\3\2"+
+ "\2\2\u011b\u0116\3\2\2\2\u011c\37\3\2\2\2\u011d\u0121\5\"\22\2\u011e\u0120"+
+ "\5$\23\2\u011f\u011e\3\2\2\2\u0120\u0123\3\2\2\2\u0121\u011f\3\2\2\2\u0121"+
+ "\u0122\3\2\2\2\u0122\u0140\3\2\2\2\u0123\u0121\3\2\2\2\u0124\u0125\5\22"+
+ "\n\2\u0125\u0129\5&\24\2\u0126\u0128\5$\23\2\u0127\u0126\3\2\2\2\u0128"+
+ "\u012b\3\2\2\2\u0129\u0127\3\2\2\2\u0129\u012a\3\2\2\2\u012a\u0140\3\2"+
+ "\2\2\u012b\u0129\3\2\2\2\u012c\u012d\7\26\2\2\u012d\u0132\7J\2\2\u012e"+
+ "\u012f\7\7\2\2\u012f\u0130\5\34\17\2\u0130\u0131\7\b\2\2\u0131\u0133\3"+
+ "\2\2\2\u0132\u012e\3\2\2\2\u0133\u0134\3\2\2\2\u0134\u0132\3\2\2\2\u0134"+
+ "\u0135\3\2\2\2\u0135\u013d\3\2\2\2\u0136\u013a\5&\24\2\u0137\u0139\5$"+
+ "\23\2\u0138\u0137\3\2\2\2\u0139\u013c\3\2\2\2\u013a\u0138\3\2\2\2\u013a"+
+ "\u013b\3\2\2\2\u013b\u013e\3\2\2\2\u013c\u013a\3\2\2\2\u013d\u0136\3\2"+
+ "\2\2\u013d\u013e\3\2\2\2\u013e\u0140\3\2\2\2\u013f\u011d\3\2\2\2\u013f"+
+ "\u0124\3\2\2\2\u013f\u012c\3\2\2\2\u0140!\3\2\2\2\u0141\u0142\6\22\26"+
+ "\3\u0142\u0143\7\t\2\2\u0143\u0144\5\34\17\2\u0144\u0145\7\n\2\2\u0145"+
+ "\u0146\b\22\1\2\u0146\u0152\3\2\2\2\u0147\u0148\6\22\27\3\u0148\u0149"+
+ "\7\t\2\2\u0149\u014a\5\36\20\2\u014a\u014b\7\n\2\2\u014b\u0152\3\2\2\2"+
+ "\u014c\u0152\7F\2\2\u014d\u0152\7K\2\2\u014e\u014f\7\26\2\2\u014f\u0150"+
+ "\7J\2\2\u0150\u0152\5*\26\2\u0151\u0141\3\2\2\2\u0151\u0147\3\2\2\2\u0151"+
+ "\u014c\3\2\2\2\u0151\u014d\3\2\2\2\u0151\u014e\3\2\2\2\u0152#\3\2\2\2"+
+ "\u0153\u0154\6\23\30\3\u0154\u0158\5&\24\2\u0155\u0156\6\23\31\3\u0156"+
+ "\u0158\5(\25\2\u0157\u0153\3\2\2\2\u0157\u0155\3\2\2\2\u0158%\3\2\2\2"+
+ "\u0159\u015a\7\13\2\2\u015a\u015b\7M\2\2\u015b\u015f\5*\26\2\u015c\u015d"+
+ "\7\13\2\2\u015d\u015f\t\r\2\2\u015e\u0159\3\2\2\2\u015e\u015c\3\2\2\2"+
+ "\u015f\'\3\2\2\2\u0160\u0161\7\7\2\2\u0161\u0162\5\34\17\2\u0162\u0163"+
+ "\7\b\2\2\u0163)\3\2\2\2\u0164\u016d\7\t\2\2\u0165\u016a\5,\27\2\u0166"+
+ "\u0167\7\f\2\2\u0167\u0169\5,\27\2\u0168\u0166\3\2\2\2\u0169\u016c\3\2"+
+ "\2\2\u016a\u0168\3\2\2\2\u016a\u016b\3\2\2\2\u016b\u016e\3\2\2\2\u016c"+
+ "\u016a\3\2\2\2\u016d\u0165\3\2\2\2\u016d\u016e\3\2\2\2\u016e\u016f\3\2"+
+ "\2\2\u016f\u0170\7\n\2\2\u0170+\3\2\2\2\u0171\u0174\5\34\17\2\u0172\u0174"+
+ "\5\24\13\2\u0173\u0171\3\2\2\2\u0173\u0172\3\2\2\2\u0174-\3\2\2\2!\61"+
+ ">FSW[`r{\177\u0085\u008e\u0098\u00a0\u00aa\u00be\u00f9\u00fb\u011b\u0121"+
+ "\u0129\u0134\u013a\u013d\u013f\u0151\u0157\u015e\u016a\u016d\u0173";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java
index 0f155ceb4c1..66d854fd220 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java
@@ -391,7 +391,15 @@ public final class Walker extends PainlessParserBaseVisitor