diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java index 233958a6fe..9dbe547d0b 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java @@ -4437,4 +4437,35 @@ public void testTypeChecked10330() { runConformTest(sources, "works"); } + + @Test + public void testTypeChecked10336() { + assumeTrue(isParrotParser()); + + //@formatter:off + String[] sources = { + "Main.groovy", + "import java.util.function.Supplier\n" + + "class C {\n" + + " Integer m() { 1 }\n" + + "}\n" + + "@groovy.transform.TypeChecked\n" + + "void test() {\n" + + " Supplier outer = () -> {\n" + + " Closure inner = (Object o, Supplier s) -> 2L\n" + + " inner(new Object(), new C()::m)\n" + + " }\n" + + "}\n" + + "test()\n", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in Main.groovy (at line 9)\n" + + "\tinner(new Object(), new C()::m)\n" + + "\t ^^^^^^^^^^\n" + + "Groovy:The argument is a method reference, but the parameter type is not a functional interface\n" + + "----------\n"); + } } diff --git a/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index 1b46305a03..7df1d7e534 100644 --- a/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -4064,6 +4064,7 @@ private void inferMethodReferenceType(final ClassNode receiver, final ArgumentLi } Parameter[] parameters = selectedMethod.getParameters(); + final int nthParameter = parameters.length - 1; List methodReferenceParamIndexList = new LinkedList<>(); List newArgumentExpressionList = new LinkedList<>(); @@ -4073,10 +4074,15 @@ private void inferMethodReferenceType(final ClassNode receiver, final ArgumentLi newArgumentExpressionList.add(argumentExpression); continue; } - + /* GRECLIPSE edit -- GROOVY-10336 Parameter param = parameters[i]; ClassNode paramType = param.getType(); - + */ + Parameter param = parameters[Math.min(i, nthParameter)]; + ClassNode paramType = param.getType(); + if (i >= nthParameter && paramType.isArray()) + paramType = paramType.getComponentType(); + // GRECLIPSE end if (!isFunctionalInterface(paramType.redirect())) { addError("The argument is a method reference, but the parameter type is not a functional interface", argumentExpression); newArgumentExpressionList.add(argumentExpression); diff --git a/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index 7778f4dcd1..151f6137e6 100644 --- a/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -3761,34 +3761,36 @@ private void inferMethodReferenceType(final ClassNode receiver, final ArgumentLi } Parameter[] parameters = selectedMethod.getParameters(); + final int nthParameter = parameters.length - 1; - List methodReferenceParamIndexList = new LinkedList<>(); - List newArgumentExpressionList = new LinkedList<>(); + List methodReferencePositions = new LinkedList<>(); + List newArgumentExpressions = new LinkedList<>(); for (int i = 0, n = argumentExpressions.size(); i < n; i += 1) { Expression argumentExpression = argumentExpressions.get(i); if (!(argumentExpression instanceof MethodReferenceExpression)) { - newArgumentExpressionList.add(argumentExpression); - continue; - } - - Parameter param = parameters[i]; - ClassNode paramType = param.getType(); - - if (!isFunctionalInterface(paramType.redirect())) { - addError("The argument is a method reference, but the parameter type is not a functional interface", argumentExpression); - newArgumentExpressionList.add(argumentExpression); + newArgumentExpressions.add(argumentExpression); } else { - newArgumentExpressionList.add(constructLambdaExpressionForMethodReference(paramType)); - methodReferenceParamIndexList.add(i); + Parameter param = parameters[Math.min(i, nthParameter)]; // GROOVY-10336 + ClassNode paramType = param.getType(); + if (i >= nthParameter && paramType.isArray()) + paramType = paramType.getComponentType(); + + if (!isFunctionalInterface(paramType.redirect())) { + addError("The argument is a method reference, but the parameter type is not a functional interface", argumentExpression); + newArgumentExpressions.add(argumentExpression); + } else { + methodReferencePositions.add(i); + newArgumentExpressions.add(constructLambdaExpressionForMethodReference(paramType)); + } } } - // GRECLIPSE add -- GROOVY-10269 - if (methodReferenceParamIndexList.isEmpty()) return; - // GRECLIPSE end - visitMethodCallArguments(receiver, args(newArgumentExpressionList), true, selectedMethod); - for (int index : methodReferenceParamIndexList) { - Expression lambdaExpression = newArgumentExpressionList.get(index); + if (methodReferencePositions.isEmpty()) return; // GROOVY-10269 + + visitMethodCallArguments(receiver, args(newArgumentExpressions), true, selectedMethod); + + for (int index : methodReferencePositions) { + Expression lambdaExpression = newArgumentExpressions.get(index); Expression methodReferenceExpression = argumentExpressions.get(index); methodReferenceExpression.putNodeMetaData(CLOSURE_ARGUMENTS, lambdaExpression.getNodeMetaData(CLOSURE_ARGUMENTS)); }