This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY-9821
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 78331f6b74d86fdd93fd202fcab44852eb367c5d
Author: Eric Milles <[email protected]>
AuthorDate: Thu Nov 19 15:29:06 2020 -0600

    GROOVY-9821: STC: check "T" from "? extends T" for spread property
---
 .../transform/stc/StaticTypeCheckingSupport.java   |  2 +-
 .../transform/stc/StaticTypeCheckingVisitor.java   | 41 +++++++++++-----------
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 32 +++++++++++++++++
 3 files changed, 54 insertions(+), 21 deletions(-)

diff --git 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index 126afb0..5034dec 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1900,7 +1900,7 @@ public abstract class StaticTypeCheckingSupport {
         return newBound;
     }
 
-    private static ClassNode getCombinedBoundType(final GenericsType 
genericsType) {
+    static ClassNode getCombinedBoundType(final GenericsType genericsType) {
         // TODO: this method should really return some kind of meta ClassNode
         // representing the combination of all bounds. The code here, just 
picks
         // something out to be able to proceed and is not actually correct
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 115988c..136f7fe 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -189,6 +189,7 @@ import static 
org.codehaus.groovy.ast.tools.GeneralUtils.constX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.getSetterName;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.isOrImplements;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.localVarX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.thisPropX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.toGenericTypesString;
@@ -246,6 +247,7 @@ import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findDG
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findSetters;
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findTargetVariable;
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.fullyResolveType;
+import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getCombinedBoundType;
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getCorrectedClassNode;
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getGenericsWithoutArray;
 import static 
org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getOperationName;
@@ -899,12 +901,10 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
     }
 
     private void validateResourceInARM(final BinaryExpression expression, 
final ClassNode lType) {
-        if (expression instanceof DeclarationExpression) {
-            if (TryCatchStatement.isResource(expression)) {
-                if (!lType.implementsInterface(AUTOCLOSEABLE_TYPE)) {
-                    addError("Resource[" + lType.getName() + "] in ARM should 
be of type AutoCloseable", expression);
-                }
-            }
+        if (expression instanceof DeclarationExpression
+                && TryCatchStatement.isResource(expression)
+                && !isOrImplements(lType, AUTOCLOSEABLE_TYPE)) {
+            addError("Resource[" + lType.getName() + "] in ARM should be of 
type AutoCloseable", expression);
         }
     }
 
@@ -1660,19 +1660,20 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
     }
 
     private ClassNode getTypeForSpreadExpression(final ClassNode testClass, 
final ClassNode objectExpressionType, final PropertyExpression pexp) {
-        if (!pexp.isSpreadSafe()) return null;
-        MethodCallExpression mce = callX(varX("_", testClass), "iterator", 
ArgumentListExpression.EMPTY_ARGUMENTS);
-        mce.setImplicitThis(false);
-        mce.visit(this);
-        ClassNode callType = getType(mce);
-        if (!implementsInterfaceOrIsSubclassOf(callType, Iterator_TYPE)) 
return null;
-        GenericsType[] types = callType.getGenericsTypes();
-        ClassNode contentType = OBJECT_TYPE;
-        if (types != null && types.length == 1) contentType = 
types[0].getType();
-        PropertyExpression subExp = new PropertyExpression(varX("{}", 
contentType), pexp.getPropertyAsString());
-        AtomicReference<ClassNode> result = new AtomicReference<>();
-        if (existsProperty(subExp, true, new PropertyLookupVisitor(result))) {
-            return extension.buildListType(result.get());
+        if (pexp.isSpreadSafe()) {
+            MethodCallExpression mce = callX(varX("_", testClass), "iterator");
+            mce.setImplicitThis(false);
+            mce.visit(this);
+            ClassNode iteratorType = getType(mce);
+            if (isOrImplements(iteratorType, Iterator_TYPE)) {
+                GenericsType[] gts = iteratorType.getGenericsTypes();
+                ClassNode itemType = (gts != null && gts.length == 1 ? 
getCombinedBoundType(gts[0]) : OBJECT_TYPE);
+
+                AtomicReference<ClassNode> propertyType = new 
AtomicReference<>();
+                if (existsProperty(propX(varX("{}", itemType), 
pexp.getProperty()), true, new PropertyLookupVisitor(propertyType))) {
+                    return extension.buildListType(propertyType.get());
+                }
+            }
         }
         return null;
     }
@@ -2228,7 +2229,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
 
     private boolean looksLikeNamedArgConstructor(final ClassNode receiver, 
final ClassNode[] argumentTypes) {
         if (argumentTypes.length == 1 || argumentTypes.length == 2 && 
argumentTypes[0].equals(receiver.getOuterClass())) {
-            return argumentTypes[argumentTypes.length - 
1].implementsInterface(MAP_TYPE);
+            return isOrImplements(argumentTypes[argumentTypes.length - 1], 
MAP_TYPE);
         }
         return false;
     }
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy 
b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 345252b..6cc3a86 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -2232,6 +2232,38 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase 
{
             }
             null
         '''
+
+        // GROOVY-9821
+        config.with {
+            targetDirectory = File.createTempDir()
+            jointCompilationOptions = [memStub: true]
+        }
+        File parentDir = File.createTempDir()
+        try {
+            def a = new File(parentDir, 'Types.java')
+            a.write '''
+                interface A {
+                    java.util.Collection<? extends B> getBees();
+                }
+                interface B {
+                    Object getC();
+                }
+            '''
+            def b = new File(parentDir, 'Script.groovy')
+            b.write '''
+                def test(A a) {
+                    a.bees*.c
+                }
+            '''
+
+            def loader = new GroovyClassLoader(this.class.classLoader)
+            def cu = new JavaAwareCompilationUnit(config, loader)
+            cu.addSources(a, b)
+            cu.compile()
+        } finally {
+            parentDir.deleteDir()
+            config.targetDirectory.deleteDir()
+        }
     }
 
     // GROOVY-7804

Reply via email to