Skip to content

Commit 3e8474d

Browse files
committed
GROOVY-9918
1 parent d1f3d8c commit 3e8474d

File tree

4 files changed

+114
-11
lines changed

4 files changed

+114
-11
lines changed

base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java

+18
Original file line numberDiff line numberDiff line change
@@ -5756,4 +5756,22 @@ public void testCompileStatic9893a() {
57565756

57575757
runConformTest(sources, "String");
57585758
}
5759+
5760+
@Test
5761+
public void testCompileStatic9918() {
5762+
//@formatter:off
5763+
String[] sources = {
5764+
"Main.groovy",
5765+
"def m(one, ... zeroOrMore) { }\n" +
5766+
"@groovy.transform.CompileStatic\n" +
5767+
"void test() {\n" +
5768+
" Object[] array = ['a', 'b']\n" +
5769+
" m(array)\n" + // ouch!
5770+
"}\n" +
5771+
"test()\n",
5772+
};
5773+
//@formatter:on
5774+
5775+
runConformTest(sources, "");
5776+
}
57595777
}

base/org.codehaus.groovy25/src/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java

+9-5
Original file line numberDiff line numberDiff line change
@@ -448,12 +448,16 @@ protected void loadArguments(List<Expression> argumentList, Parameter[] para) {
448448
ClassNode lastArgType = argumentListSize > 0 ?
449449
typeChooser.resolveType(argumentList.get(argumentListSize -1), controller.getClassNode()):null;
450450
if (lastParaType.isArray()
451-
&& ((argumentListSize > para.length)
451+
&& (argumentListSize > para.length
452+
/* GRECLIPSE edit -- GROOVY-9918
452453
|| ((argumentListSize == (para.length - 1)) && !lastParaType.equals(lastArgType))
453-
|| ((argumentListSize == para.length && lastArgType!=null && !lastArgType.isArray())
454-
&& (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(lastArgType,lastParaType.getComponentType())))
455-
|| ClassHelper.GSTRING_TYPE.equals(lastArgType) && ClassHelper.STRING_TYPE.equals(lastParaType.getComponentType()))
456-
) {
454+
*/
455+
|| argumentListSize == para.length - 1
456+
// GRECLIPSE end
457+
|| (argumentListSize == para.length && lastArgType!=null && !lastArgType.isArray()
458+
&& (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(lastArgType,lastParaType.getComponentType())
459+
|| ClassHelper.GSTRING_TYPE.equals(lastArgType) && ClassHelper.STRING_TYPE.equals(lastParaType.getComponentType())))
460+
)) {
457461
int stackLen = operandStack.getStackLength() + argumentListSize;
458462
MethodVisitor mv = controller.getMethodVisitor();
459463
controller.setMethodVisitor(mv);

base/org.codehaus.groovy30/src/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java

+9-5
Original file line numberDiff line numberDiff line change
@@ -432,12 +432,16 @@ protected void loadArguments(final List<Expression> argumentList, final Paramete
432432
ClassNode lastArgType = argumentListSize > 0 ?
433433
typeChooser.resolveType(argumentList.get(argumentListSize -1), controller.getClassNode()) : null;
434434
if (lastParaType.isArray()
435-
&& ((argumentListSize > para.length)
435+
&& (argumentListSize > para.length
436+
/* GRECLIPSE edit -- GROOVY-9918
436437
|| ((argumentListSize == (para.length - 1)) && !lastParaType.equals(lastArgType))
437-
|| ((argumentListSize == para.length && lastArgType!=null && !lastArgType.isArray())
438-
&& (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(lastArgType,lastParaType.getComponentType())))
439-
|| ClassHelper.GSTRING_TYPE.equals(lastArgType) && ClassHelper.STRING_TYPE.equals(lastParaType.getComponentType()))
440-
) {
438+
*/
439+
|| argumentListSize == para.length - 1
440+
// GRECLIPSE end
441+
|| (argumentListSize == para.length && lastArgType!=null && !lastArgType.isArray()
442+
&& (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(lastArgType,lastParaType.getComponentType())
443+
|| ClassHelper.GSTRING_TYPE.equals(lastArgType) && ClassHelper.STRING_TYPE.equals(lastParaType.getComponentType())))
444+
)) {
441445
int stackLen = operandStack.getStackLength() + argumentListSize;
442446
MethodVisitor mv = controller.getMethodVisitor();
443447
controller.setMethodVisitor(mv);

base/org.codehaus.groovy40/src/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java

+78-1
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,11 @@
6565
import groovyjarjarasm.asm.MethodVisitor;
6666

6767
import java.util.ArrayList;
68+
import java.util.Arrays;
6869
import java.util.List;
6970
import java.util.Map;
7071
import java.util.concurrent.atomic.AtomicInteger;
72+
import static java.util.stream.Collectors.joining;
7173

7274
import static org.apache.groovy.ast.tools.ClassNodeUtils.samePackageName;
7375
import static org.apache.groovy.ast.tools.ExpressionUtils.isNullConstant;
@@ -422,7 +424,8 @@ protected static boolean isPrivateBridgeMethodsCallAllowed(final ClassNode recei
422424
}
423425

424426
@Override
425-
protected void loadArguments(final List<Expression> argumentList, final Parameter[] para) {
427+
protected void loadArguments(final List<Expression> argumentList, final Parameter[] parameters) {
428+
/* GRECLIPSE edit -- GROOVY-9918
426429
if (para.length == 0) return;
427430
ClassNode lastParaType = para[para.length - 1].getOriginType();
428431
AsmClassGenerator acg = controller.getAcg();
@@ -492,6 +495,80 @@ protected void loadArguments(final List<Expression> argumentList, final Paramete
492495
visitArgument(arguments[i], para[i].getType());
493496
}
494497
}
498+
*/
499+
final int nArgs = argumentList.size(), nPrms = parameters.length; if (nPrms == 0) return;
500+
501+
ClassNode classNode = controller.getClassNode();
502+
TypeChooser typeChooser = controller.getTypeChooser();
503+
ClassNode lastArgType = nArgs == 0 ? null : typeChooser.resolveType(argumentList.get(nArgs - 1), classNode);
504+
ClassNode lastPrmType = parameters[nPrms - 1].getOriginType();
505+
506+
// target is variadic and args are too many or one short or just enough with array compatibility
507+
if (lastPrmType.isArray() && (nArgs > nPrms || nArgs == nPrms - 1
508+
|| (nArgs == nPrms && !lastArgType.isArray()
509+
&& (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(lastArgType, lastPrmType.getComponentType())
510+
|| ClassHelper.GSTRING_TYPE.equals(lastArgType) && ClassHelper.STRING_TYPE.equals(lastPrmType.getComponentType())))
511+
)) {
512+
OperandStack operandStack = controller.getOperandStack();
513+
int stackLength = operandStack.getStackLength() + nArgs;
514+
// first arguments/parameters as usual
515+
for (int i = 0; i < nPrms - 1; i += 1) {
516+
visitArgument(argumentList.get(i), parameters[i].getType());
517+
}
518+
// wrap remaining arguments in an array for last parameter
519+
List<Expression> lastArgs = new ArrayList<>();
520+
for (int i = nPrms - 1; i < nArgs; i += 1) {
521+
lastArgs.add(argumentList.get(i));
522+
}
523+
ArrayExpression array = new ArrayExpression(lastPrmType.getComponentType(), lastArgs);
524+
array.visit(controller.getAcg());
525+
// adjust stack length
526+
while (operandStack.getStackLength() < stackLength) {
527+
operandStack.push(ClassHelper.OBJECT_TYPE);
528+
}
529+
if (nArgs == nPrms - 1) {
530+
operandStack.remove(1);
531+
}
532+
} else if (nArgs == nPrms) {
533+
for (int i = 0; i < nArgs; i += 1) {
534+
visitArgument(argumentList.get(i), parameters[i].getType());
535+
}
536+
} else { // call with default arguments
537+
Expression[] arguments = new Expression[nPrms];
538+
for (int i = 0, j = 0; i < nPrms; i += 1) {
539+
Parameter p = parameters[i];
540+
ClassNode pType = p.getType();
541+
Expression a = (j < nArgs ? argumentList.get(j) : null);
542+
ClassNode aType = (a == null ? null : typeChooser.resolveType(a, classNode));
543+
544+
Expression expression = getInitialExpression(p); // default argument
545+
if (expression != null && !compatibleArgumentType(aType, pType)) {
546+
arguments[i] = expression;
547+
} else if (a != null) {
548+
arguments[i] = a;
549+
j += 1;
550+
} else {
551+
controller.getSourceUnit().addFatalError("Binding failed" +
552+
" for arguments [" + argumentList.stream().map(arg -> typeChooser.resolveType(arg, classNode).toString(false)).collect(joining(", ")) + "]" +
553+
" and parameters [" + Arrays.stream(parameters).map(prm -> prm.getType().toString(false)).collect(joining(", ")) + "]", getCurrentCall());
554+
}
555+
}
556+
for (int i = 0; i < nArgs; i += 1) {
557+
visitArgument(arguments[i], parameters[i].getType());
558+
}
559+
}
560+
// GRECLIPSE end
561+
}
562+
563+
private static Expression getInitialExpression(final Parameter parameter) {
564+
Expression initialExpression = parameter.getNodeMetaData(StaticTypesMarker.INITIAL_EXPRESSION);
565+
if (initialExpression == null && parameter.hasInitialExpression()) {
566+
initialExpression = parameter.getInitialExpression();
567+
}
568+
if (initialExpression == null && parameter.getNodeMetaData(Verifier.INITIAL_EXPRESSION) != null) {
569+
initialExpression = parameter.getNodeMetaData(Verifier.INITIAL_EXPRESSION);
570+
}
571+
return initialExpression;
495572
}
496573

497574
private void visitArgument(final Expression argumentExpr, final ClassNode parameterType) {

0 commit comments

Comments
 (0)