Improve error messages for lambdas when the number of arguments is wrong

This commit is contained in:
Robert Muir 2016-06-20 07:57:00 -04:00
parent 4d78be5b9e
commit cd1a7b441c
4 changed files with 40 additions and 1 deletions

View File

@ -341,6 +341,12 @@ public final class Def {
MethodHandle.class);
handle = (MethodHandle) accessor.invokeExact();
} catch (NoSuchFieldException | IllegalAccessException e) {
// is it a synthetic method? If we generated the method ourselves, be more helpful. It can only fail
// because the arity does not match the expected interface type.
if (call.contains("$")) {
throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.name +
"] in [" + clazz.clazz + "]");
}
throw new IllegalArgumentException("Unknown call [" + call + "] with [" + arity + "] arguments.");
}
ref = new FunctionRef(clazz, interfaceMethod, handle, captures);

View File

@ -176,7 +176,12 @@ public class FunctionRef {
* If the interface expects a primitive type to be returned, we can't return Object,
* But we can set SAM to the wrapper version, and a cast will take place
*/
private static MethodType adapt(MethodType expected, MethodType actual) {
private MethodType adapt(MethodType expected, MethodType actual) {
// add some checks, now that we've set everything up, to deliver exceptions as early as possible.
if (expected.parameterCount() != actual.parameterCount()) {
throw new IllegalArgumentException("Incorrect number of parameters for [" + invokedName +
"] in [" + invokedType.returnType() + "]");
}
if (expected.returnType().isPrimitive() && actual.returnType() == Object.class) {
actual = actual.changeReturnType(MethodType.methodType(expected.returnType()).wrap().returnType());
}

View File

@ -162,4 +162,18 @@ public class FunctionRefTests extends ScriptTestCase {
exec("List l = new ArrayList(); l.add(2); l.add(1); l.sort(String::startsWith); return l.get(0);");
});
}
public void testWrongArity() {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("Optional.empty().orElseGet(String::startsWith);");
});
assertTrue(expected.getMessage().contains("Unknown reference"));
}
public void testWrongArityDef() {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("def y = Optional.empty(); return y.orElseGet(String::startsWith);");
});
assertTrue(expected.getMessage().contains("Unknown reference"));
}
}

View File

@ -142,4 +142,18 @@ public class LambdaTests extends ScriptTestCase {
assertEquals(1, exec("boolean x = false; int y = 1;" +
"return Optional.empty().orElseGet(() -> x ? 5 : Optional.empty().orElseGet(() -> y));"));
}
public void testWrongArity() {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("Optional.empty().orElseGet(x -> x);");
});
assertTrue(expected.getMessage().contains("Incorrect number of parameters"));
}
public void testWrongArityDef() {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("def y = Optional.empty(); return y.orElseGet(x -> x);");
});
assertTrue(expected.getMessage(), expected.getMessage().contains("Incorrect number of parameters"));
}
}