You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/12/10 17:32:00 UTC

[groovy] branch master updated: GROOVY-7992: STC: strong witness overrides type witness for `? super T`

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 326bd57de3 GROOVY-7992: STC: strong witness overrides type witness for `? super T`
326bd57de3 is described below

commit 326bd57de38dce7d7221193ec4594ec6f637bc62
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Dec 10 11:07:31 2022 -0600

    GROOVY-7992: STC: strong witness overrides type witness for `? super T`
---
 .../transform/stc/StaticTypeCheckingSupport.java   | 26 ++++++++++++----------
 .../stc/DefaultGroovyMethodsSTCTest.groovy         |  4 +---
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 23 +++++++++++++++----
 .../groovy/groovysh/InteractiveShellRunner.groovy  |  5 +++--
 4 files changed, 37 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 48cf4afe26..16a797db4c 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -1737,25 +1737,26 @@ public abstract class StaticTypeCheckingSupport {
         // both have generics
         for (int i = 0, n = usage.length; i < n; i += 1) {
             GenericsType ui = usage[i], di = declaration[i];
-            if (di.isPlaceholder()) {
+            if (di.isPlaceholder()) {     // di like "T"
                 storeGenericsConnection(connections, di.getName(), ui);
-            } else if (di.isWildcard()) {
+            } else if (di.isWildcard()) { // di like "?", "? super T", "? extends T", ...
                 ClassNode lowerBound = di.getLowerBound(), upperBounds[] = di.getUpperBounds();
-                if (ui.isWildcard()) {
+                if (ui.isWildcard()) {    // ui like "?", "? super Type" or "? extends Type"
                     extractGenericsConnections(connections, ui.getLowerBound(), lowerBound);
                     extractGenericsConnections(connections, ui.getUpperBounds(), upperBounds);
                 } else if (!isUnboundedWildcard(di)) {
                     ClassNode boundType = lowerBound != null ? lowerBound : upperBounds[0];
-                    if (boundType.isGenericsPlaceHolder() // GROOVY-9998
-                            && boundType != ui.getType()) { // GROOVY-10765
+                    if (boundType.isGenericsPlaceHolder()) { // di like "? extends/super T"
+                        // 6731,7992,8983,9998,10047,10499,10749,10765,...
+                        ui = new GenericsType(ui.getType()); // erase type
+                        if (lowerBound != null) ui.setWildcard(true); // weak
                         String placeholderName = boundType.getUnresolvedName();
-                        ui = new GenericsType(ui.getType()); ui.setWildcard(true);
                         storeGenericsConnection(connections, placeholderName, ui);
-                    } else { // di like "? super Collection<T>" and ui like "List<Type>"
+                    } else { // di like "? extends Iterable<T>" and ui like "List<Type>"
                         extractGenericsConnections(connections, ui.getType(), boundType);
                     }
                 }
-            } else {
+            } else { // di like "List<T>", "List<Type>", "List<? extends T>", ...
                 extractGenericsConnections(connections, ui.getType(), di.getType());
             }
         }
@@ -1908,10 +1909,11 @@ public abstract class StaticTypeCheckingSupport {
         return genericsType.getType();
     }
 
-    static GenericsType getCombinedGenericsType(GenericsType gt1, GenericsType gt2) {
-        // GROOVY-9998, GROOVY-10499: unpack "?" that is from "? extends T"
-        if (isUnboundedWildcard(gt1)) gt1 = gt1.getType().asGenericsType();
-        if (isUnboundedWildcard(gt2)) gt2 = gt2.getType().asGenericsType();
+    static GenericsType getCombinedGenericsType(final GenericsType gt1, final GenericsType gt2) {
+        // GROOVY-7992, GROOVY-10765: "? super T" for gt1 or gt2?
+        if (isUnboundedWildcard(gt1) != isUnboundedWildcard(gt2))
+            return isUnboundedWildcard(gt2) ? gt1 : gt2;
+        // GROOVY-10315, GROOVY-10317, GROOVY-10339, ...
         ClassNode cn1 = GenericsUtils.makeClassSafe0(CLASS_Type, gt1);
         ClassNode cn2 = GenericsUtils.makeClassSafe0(CLASS_Type, gt2);
         ClassNode lub = lowestUpperBound(cn1, cn2);
diff --git a/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy b/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
index ea46a0674c..4bb950a25f 100644
--- a/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/DefaultGroovyMethodsSTCTest.groovy
@@ -18,8 +18,6 @@
  */
 package groovy.transform.stc
 
-import groovy.test.NotYetImplemented
-
 /**
  * Unit tests for static type checking : default groovy methods.
  */
@@ -240,7 +238,7 @@ class DefaultGroovyMethodsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    @NotYetImplemented // GROOVY-7992
+    // GROOVY-7992
     void testMaxWithComparatorAcceptingSuperclass() {
         assertScript '''
             List<Number> numbers = [1,2,3]
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 523f64790e..b30d8e8749 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -686,8 +686,23 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    // GROOVY-10622
+    // GROOVY-7992
     void testReturnTypeInferenceWithMethodGenerics26() {
+        assertScript '''
+            List<String> strings = ['foo','bar','baz']
+            Comparator<Object> cmp = { o1, o2 -> o1.toString() <=> o2.toString() }
+
+            @groovy.transform.ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.getNodeMetaData(INFERRED_TYPE)
+                assert type.toString(false) == 'java.util.List<java.lang.String>'
+            })
+            def result = strings.sort(false, cmp) // List<T> sort(Iterable<T>,boolean,Comparator<? super T>)
+            assert result == ['bar', 'baz', 'foo']
+        '''
+    }
+
+    // GROOVY-10622
+    void testReturnTypeInferenceWithMethodGenerics27() {
         String types = '''
             @groovy.transform.TupleConstructor(defaults=false)
             class A<X> {
@@ -720,7 +735,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10637
-    void testReturnTypeInferenceWithMethodGenerics27() {
+    void testReturnTypeInferenceWithMethodGenerics28() {
         assertScript '''
             class Outer extends groovy.transform.stc.MyBean<Inner> {
                 static class Inner {
@@ -737,7 +752,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10646
-    void testReturnTypeInferenceWithMethodGenerics28() {
+    void testReturnTypeInferenceWithMethodGenerics29() {
         String types = '''
             class Model {
             }
@@ -778,7 +793,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10749
-    void testReturnTypeInferenceWithMethodGenerics29() {
+    void testReturnTypeInferenceWithMethodGenerics30() {
         String named = 'class Named { String name }'
 
         for (expr in ['Named.&getName', '{Named named -> named.getName()}', '(Named named) -> named.getName()']) {
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/InteractiveShellRunner.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/InteractiveShellRunner.groovy
index ce1eca55c4..d5bea2bcf3 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/InteractiveShellRunner.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/InteractiveShellRunner.groovy
@@ -24,6 +24,7 @@ import groovy.transform.CompileStatic
 import jline.console.ConsoleReader
 import jline.console.completer.AggregateCompleter
 import jline.console.completer.CandidateListCompletionHandler
+import jline.console.completer.Completer
 import jline.console.completer.CompletionHandler
 import jline.console.history.FileHistory
 import org.apache.groovy.groovysh.completion.FileNameCompleter
@@ -162,9 +163,9 @@ class CommandsMultiCompleter extends AggregateCompleter {
 
     protected final Logger log = Logger.create(getClass())
 
-    List/*<Completer>*/ list = []
+    List<Completer> list = []
 
-    private boolean dirty = false
+    private boolean dirty
 
     def add(Command command) {
         assert command