This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch GROOVY_4_0_X in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 15905aaa2d900833384c02b900e2b0ba8aa75c3c Author: Eric Milles <[email protected]> AuthorDate: Mon Aug 15 12:29:51 2022 -0500 GROOVY-9415: STC: support `Type[i]` when class provides a static `getAt` --- .../classgen/asm/sc/StaticTypesCallSiteWriter.java | 22 +++++++--------------- .../transform/stc/StaticTypeCheckingVisitor.java | 12 +++++------- src/test/groovy/transform/stc/BugsSTCTest.groovy | 11 +++++++++++ 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java index 27d77e5337..3a0d78de31 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java @@ -74,6 +74,7 @@ import static org.codehaus.groovy.ast.ClassHelper.isBigDecimalType; import static org.codehaus.groovy.ast.ClassHelper.isBigIntegerType; import static org.codehaus.groovy.ast.ClassHelper.isClassType; import static org.codehaus.groovy.ast.ClassHelper.isGeneratedFunction; +import static org.codehaus.groovy.ast.ClassHelper.isObjectType; import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveBoolean; import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType; import static org.codehaus.groovy.ast.ClassHelper.isStringType; @@ -92,7 +93,6 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.propX; import static org.codehaus.groovy.ast.tools.GeneralUtils.varX; import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.chooseBestMethod; import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findDGMMethodsByNameAndArguments; -import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf; import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.isClassClassNodeWrappingConcreteType; import static org.objectweb.asm.Opcodes.AALOAD; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; @@ -599,7 +599,7 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter { "this error and file a bug report at https://issues.apache.org/jira/browse/GROOVY"); } - private boolean trySubscript(final Expression receiver, final String message, final Expression arguments, ClassNode rType, final ClassNode aType, boolean safe) { + private boolean trySubscript(final Expression receiver, final String message, final Expression arguments, final ClassNode rType, final ClassNode aType, final boolean safe) { if (getWrapper(rType).isDerivedFrom(Number_TYPE) && getWrapper(aType).isDerivedFrom(Number_TYPE)) { if ("plus".equals(message) || "minus".equals(message) || "multiply".equals(message) || "div".equals(message)) { @@ -622,9 +622,9 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter { return true; } else { // check if a getAt method can be found on the receiver - ClassNode current = rType; + ClassNode current = isClassClassNodeWrappingConcreteType(rType) ? rType.getGenericsTypes()[0].getType() : rType; MethodNode getAtNode = null; - while (current != null && getAtNode == null) { + while (current != null && !isObjectType(current) && getAtNode == null) { getAtNode = current.getDeclaredMethod("getAt", new Parameter[]{new Parameter(aType, "index")}); if (getAtNode == null) { getAtNode = getCompatibleMethod(current, "getAt", aType); @@ -652,18 +652,10 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter { return true; } - // make sure Map#getAt() and List#getAt handled with the bracket syntax are properly compiled + // make sure Map#getAt and List#getAt handled with the bracket syntax are properly compiled ClassNode[] args = {aType}; - boolean acceptAnyMethod = - MAP_TYPE.equals(rType) || rType.implementsInterface(MAP_TYPE) - || LIST_TYPE.equals(rType) || rType.implementsInterface(LIST_TYPE); List<MethodNode> nodes = findDGMMethodsByNameAndArguments(controller.getSourceUnit().getClassLoader(), rType, message, args); - if (nodes.isEmpty()) { - // retry with raw types - rType = rType.getPlainNodeReference(); - nodes = findDGMMethodsByNameAndArguments(controller.getSourceUnit().getClassLoader(), rType, message, args); - } - if (nodes.size() == 1 || (nodes.size() > 1 && acceptAnyMethod)) { + if (nodes.size() == 1 || (nodes.size() > 1 && (isOrImplements(rType, MAP_TYPE) || isOrImplements(rType, LIST_TYPE)))) { MethodCallExpression call = callX(receiver, message, arguments); call.setImplicitThis(false); call.setMethodTarget(nodes.get(0)); @@ -672,7 +664,7 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter { call.visit(controller.getAcg()); return true; } - if (implementsInterfaceOrIsSubclassOf(rType, MAP_TYPE)) { + if (isOrImplements(rType, MAP_TYPE)) { // fallback to Map#get MethodCallExpression call = callX(receiver, "get", arguments); call.setImplicitThis(false); diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index fb3b3394f5..06dff4df64 100644 --- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -4507,15 +4507,13 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { } if (isArrayOp(op)) { - // using getPNR() to ignore generics at this point - // and a different binary expression not to pollute the AST - BinaryExpression newExpr = binX(leftExpression, expr.getOperation(), rightExpression); - newExpr.setSourcePosition(expr); - MethodNode method = findMethodOrFail(newExpr, left.getPlainNodeReference(), "getAt", right.getPlainNodeReference()); - if (method != null && implementsInterfaceOrIsSubclassOf(right, RANGE_TYPE)) { + Expression copy = binX(leftExpression, expr.getOperation(), rightExpression); + copy.setSourcePosition(expr); // do not propagate BINARY_EXP_TARGET, etc. + MethodNode method = findMethodOrFail(copy, left, "getAt", rightRedirect); + if (method != null && !isNumberCategory(getWrapper(rightRedirect))) { return inferReturnTypeGenerics(left, method, rightExpression); } - return method != null ? inferComponentType(left, right) : null; + return inferComponentType(left, right); } String operationName = getOperationName(op); diff --git a/src/test/groovy/transform/stc/BugsSTCTest.groovy b/src/test/groovy/transform/stc/BugsSTCTest.groovy index 591a31d724..99d718cfb4 100644 --- a/src/test/groovy/transform/stc/BugsSTCTest.groovy +++ b/src/test/groovy/transform/stc/BugsSTCTest.groovy @@ -934,6 +934,17 @@ Printer ''' } + // GROOVY-9415 + void testStaticGetAtAndSquareBracketIndexing() { + assertScript ''' + class C9415 { + static <T> T getAt(T t) { t } + } + def result = C9415[1] // Cannot find matching method Class#getAt(int) + assert result == 1 + ''' + } + // GROOVY-9463 void testMethodPointerUnknownReference() { shouldFailWithMessages '''
