Skip to content

Commit

Permalink
Painless: Fix def invoked qualified method refs (#22918)
Browse files Browse the repository at this point in the history
We were incorrectly resolving qualified method references at run
time when invoked on `def`. This lead to errors like
`The struct with name [org] has not been defined.` when attempting

```
doc.date.dates.stream().map(
  org.joda.time.ReadableDateTime::centuryOfEra
).collect(Collectors.toList())
```
  • Loading branch information
nik9000 committed Feb 2, 2017
1 parent 4ead294 commit 278b4ae
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ static MethodHandle lookupMethod(Lookup lookup, MethodType callSiteType,
if (lambdaArgs.get(i - 1)) {
// decode signature of form 'type.call,2'
String signature = (String) args[upTo++];
int separator = signature.indexOf('.');
int separator = signature.lastIndexOf('.');
int separator2 = signature.indexOf(',');
String type = signature.substring(1, separator);
String call = signature.substring(separator+1, separator2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@

package org.elasticsearch.painless;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

import static java.util.Collections.singletonMap;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.startsWith;

public class FunctionRefTests extends ScriptTestCase {

public void testStaticMethodReference() {
Expand All @@ -37,6 +44,30 @@ public void testVirtualMethodReferenceDef() {
assertEquals(2, exec("def l = new ArrayList(); l.add(1); l.add(1); return l.stream().mapToInt(Integer::intValue).sum();"));
}

public void testQualifiedStaticMethodReference() {
assertEquals(true,
exec("List l = [true]; l.stream().map(org.elasticsearch.painless.FeatureTest::overloadedStatic).findFirst().get()"));
}

public void testQualifiedStaticMethodReferenceDef() {
assertEquals(true,
exec("def l = [true]; l.stream().map(org.elasticsearch.painless.FeatureTest::overloadedStatic).findFirst().get()"));
}

public void testQualifiedVirtualMethodReference() {
long instant = randomLong();
assertEquals(instant, exec(
"List l = [params.d]; return l.stream().mapToLong(org.joda.time.ReadableDateTime::getMillis).sum()",
singletonMap("d", new DateTime(instant, DateTimeZone.UTC)), true));
}

public void testQualifiedVirtualMethodReferenceDef() {
long instant = randomLong();
assertEquals(instant, exec(
"def l = [params.d]; return l.stream().mapToLong(org.joda.time.ReadableDateTime::getMillis).sum()",
singletonMap("d", new DateTime(instant, DateTimeZone.UTC)), true));
}

public void testCtorMethodReference() {
assertEquals(3.0D,
exec("List l = new ArrayList(); l.add(1.0); l.add(2.0); " +
Expand Down Expand Up @@ -144,10 +175,33 @@ public void testInterfaceDefaultMethodDef() {
}

public void testMethodMissing() {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("List l = new ArrayList(); l.add(2); l.add(1); l.sort(Integer::bogus); return l.get(0);");
Exception e = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("List l = [2, 1]; l.sort(Integer::bogus); return l.get(0);");
});
assertTrue(expected.getMessage().contains("Unknown reference"));
assertThat(e.getMessage(), startsWith("Unknown reference"));
}

public void testQualifiedMethodMissing() {
Exception e = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("List l = [2, 1]; l.sort(org.joda.time.ReadableDateTime::bogus); return l.get(0);", false);
});
assertThat(e.getMessage(), startsWith("Unknown reference"));
}

public void testClassMissing() {
Exception e = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("List l = [2, 1]; l.sort(Bogus::bogus); return l.get(0);", false);
});
assertThat(e.getMessage(), endsWith("Variable [Bogus] is not defined."));
}

public void testQualifiedClassMissing() {
Exception e = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("List l = [2, 1]; l.sort(org.joda.time.BogusDateTime::bogus); return l.get(0);", false);
});
/* Because the type isn't known and we use the lexer hack this fails to parse. I find this error message confusing but it is the one
* we have... */
assertEquals("invalid sequence of tokens near ['::'].", e.getMessage());
}

public void testNotFunctionalInterface() {
Expand Down

0 comments on commit 278b4ae

Please sign in to comment.