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/07/12 21:51:06 UTC

[groovy] branch master updated (deb32b0f67 -> 1942684f64)

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

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


    from deb32b0f67 GROOVY-8643: SC: null-safe for-in loop
     new c2fcbc2880 GROOVY-8965, GROOVY-10180, GROOVY-10668: STC: multiple `instanceof`
     new 897f3c5e0a GROOVY-8965: `LUB(Double,Integer)` is `(Number or Comparable)`
     new 1942684f64 retain primitive semantics for literal numbers

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../apache/groovy/parser/antlr4/AstBuilder.java    |  91 +++++++---------
 .../groovy/ast/tools/WideningCategories.java       |  22 ++--
 .../transform/stc/StaticTypeCheckingSupport.java   |  19 ++--
 .../transform/stc/StaticTypeCheckingVisitor.java   |  68 ++++++------
 src/test/groovy/transform/stc/BugsSTCTest.groovy   |  43 ++++----
 .../transform/stc/TernaryOperatorSTCTest.groovy    |   6 +-
 .../transform/stc/TypeInferenceSTCTest.groovy      |   6 +-
 .../groovy/parser/antlr4/util/AstDumper.groovy     |  20 ++--
 .../groovy/ast/tools/WideningCategoriesTest.groovy | 118 ++++++++++-----------
 .../classgen/asm/sc/BugsStaticCompileTest.groovy   |  30 +++---
 .../asm/sc/TypeInferenceStaticCompileTest.groovy   |  30 +-----
 .../asm/sc/bugs/ReproducibleBytecodeBugs.groovy    |  65 ++++++------
 12 files changed, 228 insertions(+), 290 deletions(-)


[groovy] 03/03: retain primitive semantics for literal numbers

Posted by em...@apache.org.
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

commit 1942684f645a30969e4f94bdfb7112e4e326dd92
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Jul 11 15:29:21 2022 -0500

    retain primitive semantics for literal numbers
---
 .../apache/groovy/parser/antlr4/AstBuilder.java    | 91 +++++++++-------------
 .../classgen/asm/sc/BugsStaticCompileTest.groovy   |  2 +-
 2 files changed, 38 insertions(+), 55 deletions(-)

diff --git a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
index 801d0dd1cb..a268e5bcc7 100644
--- a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
+++ b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
@@ -2302,7 +2302,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
 
             if (classNode.isInterface()) {
                 if (!asBoolean(initialValue)) {
-                    initialValue = !asBoolean(defaultValue) ? null : new ConstantExpression(defaultValue);
+                    initialValue = !asBoolean(defaultValue) ? null : new ConstantExpression(defaultValue, true);
                 }
 
                 modifiers |= Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
@@ -3109,9 +3109,8 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
     public ConstantExpression visitStringLiteral(final StringLiteralContext ctx) {
         String text = parseStringLiteral(ctx.StringLiteral().getText());
 
-        ConstantExpression constantExpression = new ConstantExpression(text, true);
-        constantExpression.putNodeMetaData(IS_STRING, true);
-
+        ConstantExpression constantExpression = new ConstantExpression(text);
+        constantExpression.putNodeMetaData(IS_STRING, Boolean.TRUE);
         return configureAST(constantExpression, ctx);
     }
 
@@ -3257,56 +3256,44 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
 
     @Override
     public Expression visitUnaryAddExprAlt(final UnaryAddExprAltContext ctx) {
-        ExpressionContext expressionCtx = ctx.expression();
-        Expression expression = (Expression) this.visit(expressionCtx);
-
+        Expression expression = (Expression) this.visit(ctx.expression());
         switch (ctx.op.getType()) {
-            case ADD: {
-                if (isNonStringConstantOutsideParentheses(expression)) {
-                    return configureAST(expression, ctx);
-                }
-
-                return configureAST(new UnaryPlusExpression(expression), ctx);
+          case ADD:
+            if (this.isNonStringConstantOutsideParentheses(expression)) {
+                return configureAST(expression, ctx);
             }
-            case SUB: {
-                if (isNonStringConstantOutsideParentheses(expression)) {
-                    ConstantExpression constantExpression = (ConstantExpression) expression;
-
-                    try {
-                        String integerLiteralText = constantExpression.getNodeMetaData(INTEGER_LITERAL_TEXT);
-                        if (null != integerLiteralText) {
-
-                            ConstantExpression result = new ConstantExpression(Numbers.parseInteger(SUB_STR + integerLiteralText));
-
-                            this.numberFormatError = null; // reset the numberFormatError
-
-                            return configureAST(result, ctx);
-                        }
-
-                        String floatingPointLiteralText = constantExpression.getNodeMetaData(FLOATING_POINT_LITERAL_TEXT);
-                        if (null != floatingPointLiteralText) {
-                            ConstantExpression result = new ConstantExpression(Numbers.parseDecimal(SUB_STR + floatingPointLiteralText));
-
-                            this.numberFormatError = null; // reset the numberFormatError
-
-                            return configureAST(result, ctx);
-                        }
-                    } catch (Exception e) {
-                        throw createParsingFailedException(e.getMessage(), ctx);
+            return configureAST(new UnaryPlusExpression(expression), ctx);
+
+          case SUB:
+            if (this.isNonStringConstantOutsideParentheses(expression)) {
+                ConstantExpression constantExpression = (ConstantExpression) expression;
+                try {
+                    String integerLiteralText = constantExpression.getNodeMetaData(INTEGER_LITERAL_TEXT);
+                    if (integerLiteralText != null) {
+                        ConstantExpression result = new ConstantExpression(Numbers.parseInteger(SUB_STR + integerLiteralText), true);
+                        this.numberFormatError = null; // reset
+                        return configureAST(result, ctx);
                     }
 
-                    throw new GroovyBugError("Failed to find the original number literal text: " + constantExpression.getText());
+                    String floatingPointLiteralText = constantExpression.getNodeMetaData(FLOATING_POINT_LITERAL_TEXT);
+                    if (floatingPointLiteralText != null) {
+                        ConstantExpression result = new ConstantExpression(Numbers.parseDecimal(SUB_STR + floatingPointLiteralText), true);
+                        this.numberFormatError = null; // reset
+                        return configureAST(result, ctx);
+                    }
+                } catch (Exception e) {
+                    throw this.createParsingFailedException(e.getMessage(), ctx);
                 }
-
-                return configureAST(new UnaryMinusExpression(expression), ctx);
+                throw new GroovyBugError("Failed to find the original number literal text: " + constantExpression.getText());
             }
+            return configureAST(new UnaryMinusExpression(expression), ctx);
 
-            case INC:
-            case DEC:
-                return configureAST(new PrefixExpression(this.createGroovyToken(ctx.op), expression), ctx);
+          case INC:
+          case DEC:
+            return configureAST(new PrefixExpression(this.createGroovyToken(ctx.op), expression), ctx);
 
-            default:
-                throw createParsingFailedException("Unsupported unary operation: " + ctx.getText(), ctx);
+          default:
+            throw this.createParsingFailedException("Unsupported unary operation: " + ctx.getText(), ctx);
         }
     }
 
@@ -3902,7 +3889,6 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
     @Override
     public ConstantExpression visitIntegerLiteralAlt(final IntegerLiteralAltContext ctx) {
         String text = ctx.IntegerLiteral().getText();
-
         Number num = null;
         try {
             num = Numbers.parseInteger(text);
@@ -3910,17 +3896,15 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
             this.numberFormatError = tuple(ctx, e);
         }
 
-        ConstantExpression constantExpression = new ConstantExpression(num, !text.startsWith(SUB_STR));
-        constantExpression.putNodeMetaData(IS_NUMERIC, Boolean.TRUE);
+        ConstantExpression constantExpression = new ConstantExpression(num, true);
         constantExpression.putNodeMetaData(INTEGER_LITERAL_TEXT, text);
-
+        constantExpression.putNodeMetaData(IS_NUMERIC, Boolean.TRUE);
         return configureAST(constantExpression, ctx);
     }
 
     @Override
     public ConstantExpression visitFloatingPointLiteralAlt(final FloatingPointLiteralAltContext ctx) {
         String text = ctx.FloatingPointLiteral().getText();
-
         Number num = null;
         try {
             num = Numbers.parseDecimal(text);
@@ -3928,10 +3912,9 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
             this.numberFormatError = tuple(ctx, e);
         }
 
-        ConstantExpression constantExpression = new ConstantExpression(num, !text.startsWith(SUB_STR));
-        constantExpression.putNodeMetaData(IS_NUMERIC, Boolean.TRUE);
+        ConstantExpression constantExpression = new ConstantExpression(num, true);
         constantExpression.putNodeMetaData(FLOATING_POINT_LITERAL_TEXT, text);
-
+        constantExpression.putNodeMetaData(IS_NUMERIC, Boolean.TRUE);
         return configureAST(constantExpression, ctx);
     }
 
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
index c78f02a04a..b608b6879c 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
@@ -1355,7 +1355,7 @@ println someInt
             class Foo {
                 long rankOrderingOrId
                 void setRankOrderingOrId(long rankOrderingOrId) {
-                    this.rankOrderingOrId = rankOrderingOrId < 0 ? -1L : rankOrderingOrId
+                    this.rankOrderingOrId = rankOrderingOrId < 0 ? -1 : rankOrderingOrId
                 }
             }
             def f = new Foo()


[groovy] 02/03: GROOVY-8965: `LUB(Double,Integer)` is `(Number or Comparable)`

Posted by em...@apache.org.
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

commit 897f3c5e0ac98bac646edea63815bb034ca92e4f
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Jul 11 14:25:27 2022 -0500

    GROOVY-8965: `LUB(Double,Integer)` is `(Number or Comparable)`
---
 .../groovy/ast/tools/WideningCategories.java       |  22 ++--
 .../transform/stc/TernaryOperatorSTCTest.groovy    |   6 +-
 .../transform/stc/TypeInferenceSTCTest.groovy      |   4 +-
 .../groovy/ast/tools/WideningCategoriesTest.groovy | 118 ++++++++++-----------
 .../classgen/asm/sc/BugsStaticCompileTest.groovy   |  32 +++---
 5 files changed, 87 insertions(+), 95 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
index e919103564..f07568d515 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
@@ -41,12 +41,10 @@ import static org.codehaus.groovy.ast.ClassHelper.byte_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.double_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.float_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.getNextSuperClass;
-import static org.codehaus.groovy.ast.ClassHelper.getUnwrapper;
 import static org.codehaus.groovy.ast.ClassHelper.getWrapper;
 import static org.codehaus.groovy.ast.ClassHelper.int_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.isBigDecimalType;
 import static org.codehaus.groovy.ast.ClassHelper.isBigIntegerType;
-import static org.codehaus.groovy.ast.ClassHelper.isNumberType;
 import static org.codehaus.groovy.ast.ClassHelper.isObjectType;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveByte;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveChar;
@@ -173,8 +171,10 @@ public class WideningCategories {
      * @return first common supertype
      */
     public static ClassNode lowestUpperBound(final List<ClassNode> nodes) {
-        if (nodes.size() == 1) return nodes.get(0);
-        return lowestUpperBound(nodes.get(0), lowestUpperBound(nodes.subList(1, nodes.size())));
+        int n = nodes.size();
+        if (n == 1) return nodes.get(0);
+        if (n == 2) return lowestUpperBound(nodes.get(0), nodes.get(1));
+        return lowestUpperBound(nodes.get(0), lowestUpperBound(nodes.subList(1, n)));
     }
 
     /**
@@ -340,20 +340,10 @@ public class WideningCategories {
         if (isPrimitiveA && isPrimitiveB) {
             Integer pa = NUMBER_TYPES_PRECEDENCE.get(a);
             Integer pb = NUMBER_TYPES_PRECEDENCE.get(b);
-            if (pa!=null && pb!=null) {
-                if (pa<=pb) return a;
-                return b;
-            }
-            return a.equals(b)?a:lowestUpperBound(getWrapper(a), getWrapper(b), null, null);
-        }
-        if (isNumberType(a.redirect()) && isNumberType(b.redirect())) {
-            ClassNode ua = getUnwrapper(a);
-            ClassNode ub = getUnwrapper(b);
-            Integer pa = NUMBER_TYPES_PRECEDENCE.get(ua);
-            Integer pb = NUMBER_TYPES_PRECEDENCE.get(ub);
             if (pa != null && pb != null) {
-                return pa <= pb ? a : b;
+                return (pa <= pb ? a : b);
             }
+            return a.equals(b) ? a : lowestUpperBound(getWrapper(a), getWrapper(b), null, null);
         }
 
         // handle interfaces
diff --git a/src/test/groovy/transform/stc/TernaryOperatorSTCTest.groovy b/src/test/groovy/transform/stc/TernaryOperatorSTCTest.groovy
index 1c5a7da7b7..92b708e40c 100644
--- a/src/test/groovy/transform/stc/TernaryOperatorSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TernaryOperatorSTCTest.groovy
@@ -109,7 +109,7 @@ class TernaryOperatorSTCTest extends StaticTypeCheckingTestCase {
     void testDoubleFloatWithBoxedTypes() {
         assertScript '''
             @ASTTest(phase=INSTRUCTION_SELECTION, value={
-                assert node.getNodeMetaData(INFERRED_TYPE) == Double_TYPE
+                assert node.getNodeMetaData(INFERRED_TYPE).name == 'java.lang.Number'
             })
             def y = true?new Double(1d):new Float(1f)
         '''
@@ -118,7 +118,7 @@ class TernaryOperatorSTCTest extends StaticTypeCheckingTestCase {
     void testDoubleFloatWithOneBoxedType1() {
         assertScript '''
             @ASTTest(phase=INSTRUCTION_SELECTION, value={
-                assert node.getNodeMetaData(INFERRED_TYPE) == Double_TYPE
+                assert node.getNodeMetaData(INFERRED_TYPE).name == 'java.lang.Number'
             })
             def y = true?1d:new Float(1f)
         '''
@@ -127,7 +127,7 @@ class TernaryOperatorSTCTest extends StaticTypeCheckingTestCase {
     void testDoubleFloatWithOneBoxedType2() {
         assertScript '''
             @ASTTest(phase=INSTRUCTION_SELECTION, value={
-                assert node.getNodeMetaData(INFERRED_TYPE) == Double_TYPE
+                assert node.getNodeMetaData(INFERRED_TYPE).name == 'java.lang.Number'
             })
             def y = true?new Double(1d):1f
         '''
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index 6f1efc8dc7..c172240660 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -347,11 +347,13 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
             assertScript """
                 def foo(o) {
                     if (o instanceof Integer || o instanceof Double) {
-                        ${it}.floatValue() // CCE: Double cannot be cast to Integer
+                        ${it}.floatValue() // ClassCastException
                     }
                 }
                 def bar = foo(1.1d)
                 assert bar == 1.1f
+                def baz = foo(1)
+                assert baz == 1
             """
         }
     }
diff --git a/src/test/org/codehaus/groovy/ast/tools/WideningCategoriesTest.groovy b/src/test/org/codehaus/groovy/ast/tools/WideningCategoriesTest.groovy
index 4be116256e..212588cd4d 100644
--- a/src/test/org/codehaus/groovy/ast/tools/WideningCategoriesTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/tools/WideningCategoriesTest.groovy
@@ -28,14 +28,14 @@ final class WideningCategoriesTest extends GenericsTestCase {
 
     void testBuildCommonTypeWithNullClassNode() {
         ClassNode a = null
-        ClassNode b = make(Serializable)
+        ClassNode b = SERIALIZABLE_TYPE
         assert lowestUpperBound(a,b) == null
         assert lowestUpperBound(b,a) == null
     }
 
     void testBuildCommonTypeWithObjectClassNode() {
         ClassNode a = OBJECT_TYPE
-        ClassNode b = make(Serializable)
+        ClassNode b = SERIALIZABLE_TYPE
         assert lowestUpperBound(a,b) == OBJECT_TYPE
         assert lowestUpperBound(b,a) == OBJECT_TYPE
     }
@@ -49,40 +49,40 @@ final class WideningCategoriesTest extends GenericsTestCase {
 
     void testBuildCommonTypeWithVoidClassNodeAndAnyNode() {
         ClassNode a = VOID_TYPE
-        ClassNode b = make(Set)
+        ClassNode b = SET_TYPE
         assert lowestUpperBound(a,b) == OBJECT_TYPE
         assert lowestUpperBound(b,a) == OBJECT_TYPE
     }
 
     void testBuildCommonTypeWithIdenticalInterfaces() {
-        ClassNode a = make(Serializable)
-        ClassNode b = make(Serializable)
-        assert lowestUpperBound(a,b) == make(Serializable)
+        ClassNode a = SERIALIZABLE_TYPE
+        ClassNode b = SERIALIZABLE_TYPE
+        assert lowestUpperBound(a,b) == SERIALIZABLE_TYPE
     }
 
     void testBuildCommonTypeWithOneInterfaceInheritsFromOther() {
-        ClassNode a = make(Set)
+        ClassNode a = SET_TYPE
         ClassNode b = make(SortedSet)
-        assert lowestUpperBound(a,b) == make(Set)
-        assert lowestUpperBound(b,a) == make(Set)
+        assert lowestUpperBound(a,b) == SET_TYPE
+        assert lowestUpperBound(b,a) == SET_TYPE
     }
 
     void testBuildCommonTypeWithTwoIncompatibleInterfaces() {
-        ClassNode a = make(Set)
-        ClassNode b = make(Map)
+        ClassNode a = SET_TYPE
+        ClassNode b = MAP_TYPE
         assert lowestUpperBound(a,b) == OBJECT_TYPE
         assert lowestUpperBound(b,a) == OBJECT_TYPE
     }
 
     void testBuildCommonTypeWithOneClassAndOneImplementedInterface() {
-        ClassNode a = make(Set)
+        ClassNode a = SET_TYPE
         ClassNode b = make(HashSet)
-        assert lowestUpperBound(a,b) == make(Set)
-        assert lowestUpperBound(b,a) == make(Set)
+        assert lowestUpperBound(a,b) == SET_TYPE
+        assert lowestUpperBound(b,a) == SET_TYPE
     }
 
     void testBuildCommonTypeWithOneClassAndNoImplementedInterface() {
-        ClassNode a = make(Map)
+        ClassNode a = MAP_TYPE
         ClassNode b = make(HashSet)
         assert lowestUpperBound(a,b) == OBJECT_TYPE
         assert lowestUpperBound(b,a) == OBJECT_TYPE
@@ -91,8 +91,8 @@ final class WideningCategoriesTest extends GenericsTestCase {
     void testBuildCommonTypeWithTwoClassesWithoutSuperClass() {
         ClassNode a = make(ClassA)
         ClassNode b = make(ClassB)
-        assert lowestUpperBound(a,b) == make(GroovyObject) // GroovyObject because Groovy classes implicitly implement GroovyObject
-        assert lowestUpperBound(b,a) == make(GroovyObject)
+        assert lowestUpperBound(a,b) == GROOVY_OBJECT_TYPE // GroovyObject because Groovy classes implicitly implement GroovyObject
+        assert lowestUpperBound(b,a) == GROOVY_OBJECT_TYPE
     }
 
     void testBuildCommonTypeWithIdenticalPrimitiveTypes() {
@@ -151,15 +151,15 @@ final class WideningCategoriesTest extends GenericsTestCase {
     void testBuildCommonTypeFromTwoClassesInDifferentBranches() {
         ClassNode a = make(ClassA1)
         ClassNode b = make(ClassB1)
-        assert lowestUpperBound(a,b) == make(GroovyObject)
-        assert lowestUpperBound(b,a) == make(GroovyObject)
+        assert lowestUpperBound(a,b) == GROOVY_OBJECT_TYPE
+        assert lowestUpperBound(b,a) == GROOVY_OBJECT_TYPE
     }
 
     void testBuildCommonTypeFromTwoClassesInDifferentBranchesAndOneCommonInterface() {
         ClassNode a = make(ClassA1_Serializable)
         ClassNode b = make(ClassB1_Serializable)
-        assert lowestUpperBound(a,b).interfaces as Set == [make(Serializable), make(GroovyObject)] as Set
-        assert lowestUpperBound(b,a).interfaces as Set == [make(Serializable), make(GroovyObject)] as Set
+        assert lowestUpperBound(a,b).interfaces as Set == [SERIALIZABLE_TYPE, GROOVY_OBJECT_TYPE] as Set
+        assert lowestUpperBound(b,a).interfaces as Set == [SERIALIZABLE_TYPE, GROOVY_OBJECT_TYPE] as Set
     }
 
     void testBuildCommonTypeFromTwoClassesWithCommonSuperClassAndOneCommonInterface() {
@@ -168,32 +168,32 @@ final class WideningCategoriesTest extends GenericsTestCase {
         ClassNode type = lowestUpperBound(a, b)
         assert type.name =~ /.*Top/
         assert type.superClass == make(Top) // includes interface GroovyObject
-        assert type.interfaces as Set == [make(Serializable)] as Set // extra interface
+        assert type.interfaces as Set == [SERIALIZABLE_TYPE] as Set // extra interface
         type = lowestUpperBound(b, a)
         assert type.name =~ /.*Top/
         assert type.superClass == make(Top)
-        assert type.interfaces as Set == [make(Serializable)] as Set
+        assert type.interfaces as Set == [SERIALIZABLE_TYPE] as Set
     }
 
     // GROOVY-8111
     void testBuildCommonTypeFromTwoClassesWithTwoCommonInterfacesOneIsSelfReferential() {
         ClassNode a = boolean_TYPE
-        ClassNode b = extractTypesFromCode("${getClass().getName()}.Pair<String,String> type").type
+        ClassNode b = extractTypesFromCode("${this.class.name}.Pair<String,String> type").type
         ClassNode lub = lowestUpperBound(a, b)
 
         assert lub.superClass == OBJECT_TYPE
-        assert lub.interfaces as Set == [make(Comparable), make(Serializable)] as Set
+        assert lub.interfaces as Set == [COMPARABLE_TYPE, SERIALIZABLE_TYPE] as Set
 
         lub = lowestUpperBound(b, a)
         assert lub.superClass == OBJECT_TYPE
-        assert lub.interfaces as Set == [make(Comparable), make(Serializable)] as Set
+        assert lub.interfaces as Set == [COMPARABLE_TYPE, SERIALIZABLE_TYPE] as Set
     }
 
     void testStringWithGString() {
         ClassNode a = make(String)
         ClassNode b = make(GString)
         ClassNode type = lowestUpperBound(a,b)
-        assert type.interfaces as Set == [make(CharSequence), make(Comparable), make(Serializable)] as Set
+        assert type.interfaces as Set == [make(CharSequence), COMPARABLE_TYPE, SERIALIZABLE_TYPE] as Set
     }
 
     void testDistinctPrimitiveTypes() {
@@ -210,46 +210,46 @@ final class WideningCategoriesTest extends GenericsTestCase {
     }
 
     void testLUBWithTwoInterfacesAndSameGenericArg() {
-        ClassNode a = extractTypesFromCode("List<String> type").type
-        ClassNode b = extractTypesFromCode("List<String> type").type
+        ClassNode a = extractTypesFromCode('List<String> type').type
+        ClassNode b = extractTypesFromCode('List<String> type').type
         ClassNode lub = lowestUpperBound(a,b)
-        assert lub == make(List)
+        assert lub == LIST_TYPE
         assert lub.genericsTypes.length == 1
         assert lub.genericsTypes[0].type == STRING_TYPE
     }
 
     void testLUBWithTwoInterfacesAndCommonSuperClassGenericArg() {
-        ClassNode a = extractTypesFromCode("List<Integer> type").type
-        ClassNode b = extractTypesFromCode("List<Long> type").type
+        ClassNode a = extractTypesFromCode('List<Integer> type').type
+        ClassNode b = extractTypesFromCode('List<Long> type').type
         ClassNode lub = lowestUpperBound(a,b)
-        assert lub == make(List)
+        assert lub == LIST_TYPE
         assert lub.genericsTypes.length == 1
         assert lub.genericsTypes[0].wildcard
-        assert lub.genericsTypes[0].upperBounds[0].superClass == Number_TYPE
-        assert make(Comparable) in lub.genericsTypes[0].upperBounds[0].interfaces
+        assert lub.genericsTypes[0].upperBounds[0].name == 'java.lang.Number'
+        assert COMPARABLE_TYPE in lub.genericsTypes[0].upperBounds[0].interfaces
     }
 
     void testLUBWithTwoInterfacesAndSingleCommonInterface() {
-        ClassNode a = extractTypesFromCode("List<Set> type").type
-        ClassNode b = extractTypesFromCode("List<List> type").type
+        ClassNode a = extractTypesFromCode('List<Set> type').type
+        ClassNode b = extractTypesFromCode('List<List> type').type
         ClassNode lub = lowestUpperBound(a,b)
-        assert lub == make(List)
+        assert lub == LIST_TYPE
         assert lub.genericsTypes.length == 1
         assert lub.genericsTypes[0].wildcard
-        assert lub.genericsTypes[0].upperBounds[0] == make(Collection)
+        assert lub.genericsTypes[0].upperBounds[0] == COLLECTION_TYPE
     }
 
     void testLUBWithTwoInterfacesAndNestedSingleCommonInterface() {
-        ClassNode a = extractTypesFromCode("Collection<List<Set>> type").type
-        ClassNode b = extractTypesFromCode("Collection<List<SortedSet>> type").type
+        ClassNode a = extractTypesFromCode('Collection<List<Set>> type').type
+        ClassNode b = extractTypesFromCode('Collection<List<SortedSet>> type').type
         ClassNode lub = lowestUpperBound(a,b)
-        assert lub == make(Collection)
+        assert lub == COLLECTION_TYPE
         assert lub.genericsTypes.length == 1
         def nestedType = lub.genericsTypes[0].type
-        assert nestedType == make(List)
-        assert nestedType.genericsTypes.length==1
+        assert nestedType == LIST_TYPE
+        assert nestedType.genericsTypes.length == 1
         assert nestedType.genericsTypes[0].wildcard
-        assert nestedType.genericsTypes[0].upperBounds[0] == make(Set)
+        assert nestedType.genericsTypes[0].upperBounds[0] == SET_TYPE
     }
 
     void testLUBWithTwoArgumentTypesSharingOneInterfaceNotImplementedBySuperClass() {
@@ -265,7 +265,7 @@ final class WideningCategoriesTest extends GenericsTestCase {
         ClassNode genericType = lub.genericsTypes[0].upperBounds[0]
         assert genericType instanceof LowestUpperBoundClassNode
         assert genericType.superClass == make(Top)
-        assert genericType.interfaces == [make(Serializable)]
+        assert genericType.interfaces == [SERIALIZABLE_TYPE]
     }
 
     void testLUBWithTwoParameterizedTypesSharingOneInterfaceNotImplementedBySuperClass() {
@@ -276,32 +276,34 @@ final class WideningCategoriesTest extends GenericsTestCase {
         ClassNode b = extractTypesFromCode('org.codehaus.groovy.ast.tools.WideningCategoriesTest.PTopLong type').type
         ClassNode lub = lowestUpperBound(a,b)
         assert lub instanceof LowestUpperBoundClassNode // a virtual class which extends PTop<? extends Number> and implements Serializable
+        assert lub.interfaces == [SERIALIZABLE_TYPE]
         assert lub.unresolvedSuperClass == make(PTop)
         assert lub.unresolvedSuperClass.genericsTypes.length == 1
         assert lub.unresolvedSuperClass.genericsTypes[0].wildcard // ? extends Number
-        ClassNode genericType = lub.unresolvedSuperClass.genericsTypes[0].upperBounds[0]
-        assert genericType == Long_TYPE
+        ClassNode upperBound = lub.unresolvedSuperClass.genericsTypes[0].upperBounds[0]
+        assert upperBound.superClass == Number_TYPE
+        assert upperBound.interfaces.contains(COMPARABLE_TYPE)
     }
 
     void testCommonAssignableType() {
         def typeA = extractTypesFromCode('LinkedList type').type
         def typeB = extractTypesFromCode('List type').type
         def superType = lowestUpperBound(typeA, typeB)
-        assert superType == make(List)
+        assert superType == LIST_TYPE
     }
 
     void testCommonAssignableType2() {
         def typeA = extractTypesFromCode('LinkedHashSet type').type
         def typeB = extractTypesFromCode('List type').type
         def superType = lowestUpperBound(typeA, typeB)
-        assert superType == make(Collection)
+        assert superType == COLLECTION_TYPE
     }
 
     void testCommonAssignableTypeWithGenerics() {
         def typeA = extractTypesFromCode('LinkedHashSet<String> type').type
         def typeB = extractTypesFromCode('List<String> type').type
         def superType = lowestUpperBound(typeA, typeB)
-        assert superType == make(Collection)
+        assert superType == COLLECTION_TYPE
     }
 
     void testLUBOfTwoListTypes() {
@@ -310,7 +312,7 @@ final class WideningCategoriesTest extends GenericsTestCase {
         def superType = lowestUpperBound(typeA, typeB)
         assert superType instanceof LowestUpperBoundClassNode
         assert superType.superClass == make(AbstractList)
-        assert superType.interfaces as Set == [make(Serializable), make(Cloneable)] as Set
+        assert superType.interfaces as Set == [SERIALIZABLE_TYPE, make(Cloneable)] as Set
     }
 
     void testLUBOfTwoListTypesWithSameGenerics() {
@@ -319,7 +321,7 @@ final class WideningCategoriesTest extends GenericsTestCase {
         def superType = lowestUpperBound(typeA, typeB)
         assert superType instanceof LowestUpperBoundClassNode
         assert superType.superClass == make(AbstractList)
-        assert superType.interfaces as Set == [make(Serializable), make(Cloneable)] as Set
+        assert superType.interfaces as Set == [SERIALIZABLE_TYPE, make(Cloneable)] as Set
         assert superType.genericsTypes.length == 1
         assert superType.genericsTypes[0].type == STRING_TYPE
 
@@ -331,14 +333,13 @@ final class WideningCategoriesTest extends GenericsTestCase {
         def superType = lowestUpperBound(typeA, typeB)
         assert superType instanceof LowestUpperBoundClassNode
         assert superType.superClass == make(AbstractList)
-        assert superType.interfaces as Set == [make(Serializable), make(Cloneable)] as Set
+        assert superType.interfaces as Set == [SERIALIZABLE_TYPE, make(Cloneable)] as Set
         assert superType.genericsTypes.length == 1
         def type = superType.genericsTypes[0]
         assert type.wildcard
         assert type.upperBounds[0] instanceof LowestUpperBoundClassNode
-        [Comparable, Serializable].each {
-            assert make(it) in type.upperBounds[0].interfaces
-        }
+        assert type.upperBounds[0].interfaces.contains(COMPARABLE_TYPE)
+        assert type.upperBounds[0].interfaces.contains(SERIALIZABLE_TYPE)
     }
 
     void testLUBOfArrayTypes() {
@@ -346,8 +347,7 @@ final class WideningCategoriesTest extends GenericsTestCase {
         def typeB = extractTypesFromCode('Integer[] type').type
         def superType = lowestUpperBound(typeA, typeB)
         assert superType.isArray()
-        def component = superType.getComponentType()
-        assert component == make(Number)
+        assert superType.componentType == Number_TYPE
     }
 
     // ---------- Classes and Interfaces used in this unit test ----------------
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
index 68181ad0c7..c78f02a04a 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
@@ -1310,21 +1310,21 @@ println someInt
 
     void testStaticMethodFromInnerClassConstructor() {
         assertScript '''
-    class Parent {
-        String str
-        Parent(String s) { str = s }
-    }
-    class Outer {
-        private class Inner extends Parent {
-           static String a = 'ok'
-           Inner() { super(getA()) }
-        }
+            class Parent {
+                String str
+                Parent(String s) { str = s }
+            }
+            class Outer {
+                private class Inner extends Parent {
+                   static String a = 'ok'
+                   Inner() { super(getA()) }
+                }
 
-        String test() { new Inner().str }
-    }
-    def o = new Outer()
-    assert o.test() == 'ok'
-    '''
+                String test() { new Inner().str }
+            }
+            def o = new Outer()
+            assert o.test() == 'ok'
+        '''
     }
 
     // GROOVY-6876
@@ -1338,7 +1338,7 @@ println someInt
                 }
             }
             assert new Foo().method() == -1L
-            '''
+        '''
 
         assertScript '''
             class Foo {
@@ -1355,7 +1355,7 @@ println someInt
             class Foo {
                 long rankOrderingOrId
                 void setRankOrderingOrId(long rankOrderingOrId) {
-                    this.rankOrderingOrId = rankOrderingOrId < 0 ? -1 : rankOrderingOrId
+                    this.rankOrderingOrId = rankOrderingOrId < 0 ? -1L : rankOrderingOrId
                 }
             }
             def f = new Foo()


[groovy] 01/03: GROOVY-8965, GROOVY-10180, GROOVY-10668: STC: multiple `instanceof`

Posted by em...@apache.org.
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

commit c2fcbc288013794177435a273c3efb596d1fe268
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Jul 7 15:39:41 2022 -0500

    GROOVY-8965, GROOVY-10180, GROOVY-10668: STC: multiple `instanceof`
---
 .../transform/stc/StaticTypeCheckingSupport.java   | 19 +++---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 68 +++++++++++-----------
 src/test/groovy/transform/stc/BugsSTCTest.groovy   | 43 ++++++--------
 .../transform/stc/TypeInferenceSTCTest.groovy      |  2 +-
 .../groovy/parser/antlr4/util/AstDumper.groovy     | 20 +++----
 .../asm/sc/TypeInferenceStaticCompileTest.groovy   | 30 +---------
 .../asm/sc/bugs/ReproducibleBytecodeBugs.groovy    | 65 ++++++++++-----------
 7 files changed, 105 insertions(+), 142 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 f68572e192..18093b95f5 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -903,8 +903,7 @@ public abstract class StaticTypeCheckingSupport {
             }
             if (result) return true;
         } else if (superOrInterface instanceof UnionTypeClassNode) {
-            UnionTypeClassNode union = (UnionTypeClassNode) superOrInterface;
-            for (ClassNode delegate : union.getDelegates()) {
+            for (ClassNode delegate : ((UnionTypeClassNode) superOrInterface).getDelegates()) {
                 if (implementsInterfaceOrIsSubclassOf(type, delegate)) return true;
             }
         }
@@ -1040,8 +1039,9 @@ public abstract class StaticTypeCheckingSupport {
 
         int bestDist = Integer.MAX_VALUE;
         List<MethodNode> bestChoices = new LinkedList<>();
+        boolean duckType = receiver instanceof UnionTypeClassNode; // GROOVY-8965: type disjunction
         boolean noCulling = methods.size() <= 1 || "<init>".equals(methods.iterator().next().getName());
-        Iterable<MethodNode> candidates = noCulling ? methods : removeCovariantsAndInterfaceEquivalents(methods);
+        Iterable<MethodNode> candidates = noCulling ? methods : removeCovariantsAndInterfaceEquivalents(methods, duckType);
 
         for (MethodNode candidate : candidates) {
             MethodNode safeNode = candidate;
@@ -1096,7 +1096,7 @@ public abstract class StaticTypeCheckingSupport {
                 }
             }
         }
-        if (bestChoices.size() > 1) {
+        if (bestChoices.size() > 1 && !duckType) {
             // GROOVY-6849: prefer extension method in case of ambiguity
             List<MethodNode> onlyExtensionMethods = new LinkedList<>();
             for (MethodNode choice : bestChoices) {
@@ -1195,9 +1195,8 @@ public abstract class StaticTypeCheckingSupport {
         return raw;
     }
 
-    private static List<MethodNode> removeCovariantsAndInterfaceEquivalents(final Collection<MethodNode> collection) {
-        List<MethodNode> toBeRemoved = new ArrayList<>();
-        List<MethodNode> list = new ArrayList<>(new LinkedHashSet<>(collection));
+    private static List<MethodNode> removeCovariantsAndInterfaceEquivalents(final Collection<MethodNode> collection, final boolean disjoint) {
+        List<MethodNode> list = new ArrayList<>(new LinkedHashSet<>(collection)), toBeRemoved = new ArrayList<>();
         for (int i = 0, n = list.size(); i < n - 1; i += 1) {
             MethodNode one = list.get(i);
             if (toBeRemoved.contains(one)) continue;
@@ -1228,11 +1227,9 @@ public abstract class StaticTypeCheckingSupport {
                     } else if (!oneDC.equals(twoDC)) {
                         if (ParameterUtils.parametersEqual(one.getParameters(), two.getParameters())) {
                             // GROOVY-6882, GROOVY-6970: drop overridden or interface equivalent method
-                            if (twoDC.isInterface() ? oneDC.implementsInterface(twoDC)
-                                    : oneDC.isDerivedFrom(twoDC)) {
+                            if (twoDC.isInterface() ? oneDC.implementsInterface(twoDC) : oneDC.isDerivedFrom(twoDC)) {
                                 toBeRemoved.add(two);
-                            } else if (oneDC.isInterface() ? twoDC.isInterface()
-                                    : twoDC.isDerivedFrom(oneDC)) {
+                            } else if (oneDC.isInterface() ? (disjoint ? twoDC.implementsInterface(oneDC) : twoDC.isInterface()) : twoDC.isDerivedFrom(oneDC)) {
                                 toBeRemoved.add(one);
                             }
                         }
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 8c45a0b7d9..f56bc8eaf3 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -3503,7 +3503,20 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     if (areCategoryMethodCalls(mn, name, args)) {
                         addCategoryMethodCallError(call);
                     }
-                    mn = disambiguateMethods(mn, chosenReceiver != null ? chosenReceiver.getType() : null, args, call);
+
+                    {
+                        ClassNode obj = chosenReceiver != null ? chosenReceiver.getType() : null;
+                        if (mn.size() > 1 && obj instanceof UnionTypeClassNode) { // GROOVY-8965: support duck-typing using dynamic resolution
+                            ClassNode returnType = mn.stream().map(MethodNode::getReturnType).reduce(WideningCategories::lowestUpperBound).get();
+                            call.putNodeMetaData(DYNAMIC_RESOLUTION, returnType);
+
+                            MethodNode tmp = new MethodNode(name, 0, returnType, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null);
+                            tmp.setDeclaringClass(obj); // for storeTargetMethod
+                            mn = Collections.singletonList(tmp);
+                        } else {
+                            mn = disambiguateMethods(mn, obj, args, call);
+                        }
+                    }
 
                     if (mn.size() == 1) {
                         MethodNode targetMethodCandidate = mn.get(0);
@@ -3752,7 +3765,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     }
 
     /**
-     * Given an object expression (a receiver expression), generate the list of potential receiver types.
+     * Given an object expression (a message receiver expression), generate list
+     * of possible types.
      *
      * @param objectExpression the receiver expression
      * @return the list of types the receiver may be
@@ -3762,23 +3776,20 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         List<Receiver<String>> owners = new ArrayList<>();
         if (typeCheckingContext.delegationMetadata != null
                 && objectExpression instanceof VariableExpression
-                && ((VariableExpression) objectExpression).getName().equals("owner")
+                && ((Variable) objectExpression).getName().equals("owner")
                 && /*isNested:*/typeCheckingContext.delegationMetadata.getParent() != null) {
             List<Receiver<String>> enclosingClass = Collections.singletonList(
                     Receiver.make(typeCheckingContext.getEnclosingClassNode()));
             addReceivers(owners, enclosingClass, typeCheckingContext.delegationMetadata.getParent(), "owner.");
         } else {
-            if (!typeCheckingContext.temporaryIfBranchTypeInformation.isEmpty()) {
-                List<ClassNode> potentialReceiverType = getTemporaryTypesForExpression(objectExpression);
-                if (potentialReceiverType != null && !potentialReceiverType.isEmpty()) {
-                    for (ClassNode node : potentialReceiverType) {
-                        owners.add(Receiver.make(node));
-                    }
-                }
+            List<ClassNode> temporaryTypes = getTemporaryTypesForExpression(objectExpression);
+            int temporaryTypesCount = (temporaryTypes != null ? temporaryTypes.size() : 0);
+            if (temporaryTypesCount > 0) { // GROOVY-8965, GROOVY-10180, GROOVY-10668
+                owners.add(Receiver.make(lowestUpperBound(temporaryTypes)));
             }
             if (typeCheckingContext.lastImplicitItType != null
                     && objectExpression instanceof VariableExpression
-                    && ((VariableExpression) objectExpression).getName().equals("it")) {
+                    && ((Variable) objectExpression).getName().equals("it")) {
                 owners.add(Receiver.make(typeCheckingContext.lastImplicitItType));
             }
             if (isClassClassNodeWrappingConcreteType(receiver)) {
@@ -3798,6 +3809,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     }
                 }
             }
+            if (temporaryTypesCount > 1 && !(objectExpression instanceof VariableExpression)) {
+                owners.add(Receiver.make(new UnionTypeClassNode(temporaryTypes.toArray(ClassNode.EMPTY_ARRAY))));
+            }
         }
         return owners;
     }
@@ -4717,37 +4731,25 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         return null;
     }
 
-    private List<MethodNode> disambiguateMethods(List<MethodNode> methods, final ClassNode receiver, final ClassNode[] argTypes, final Expression call) {
-        if (methods.size() > 1 && receiver != null && argTypes != null) {
+    private List<MethodNode> disambiguateMethods(List<MethodNode> methods, final ClassNode receiver, final ClassNode[] arguments, final Expression call) {
+        if (methods.size() > 1 && receiver != null && arguments != null) {
             List<MethodNode> filteredWithGenerics = new LinkedList<>();
-            for (MethodNode methodNode : methods) {
-                if (typeCheckMethodsWithGenerics(receiver, argTypes, methodNode)) {
-                    if ((methodNode.getModifiers() & Opcodes.ACC_BRIDGE) == 0) {
-                        filteredWithGenerics.add(methodNode);
-                    }
+            for (MethodNode method : methods) {
+                if (typeCheckMethodsWithGenerics(receiver, arguments, method)
+                        && (method.getModifiers() & Opcodes.ACC_BRIDGE) == 0) {
+                    filteredWithGenerics.add(method);
                 }
             }
             if (filteredWithGenerics.size() == 1) {
                 return filteredWithGenerics;
             }
+
             methods = extension.handleAmbiguousMethods(methods, call);
         }
 
-        if (methods.size() > 1) {
-            if (call instanceof MethodCall) {
-                List<MethodNode> methodNodeList = new LinkedList<>();
-
-                String methodName = ((MethodCall) call).getMethodAsString();
-
-                for (MethodNode methodNode : methods) {
-                    if (!methodNode.getName().equals(methodName)) {
-                        continue;
-                    }
-                    methodNodeList.add(methodNode);
-                }
-
-                methods = methodNodeList;
-            }
+        if (methods.size() > 1 && call instanceof MethodCall) {
+            String methodName = ((MethodCall) call).getMethodAsString();
+            methods = methods.stream().filter(m -> m.getName().equals(methodName)).collect(Collectors.toList());
         }
 
         return methods;
diff --git a/src/test/groovy/transform/stc/BugsSTCTest.groovy b/src/test/groovy/transform/stc/BugsSTCTest.groovy
index 45f0cd4a91..591a31d724 100644
--- a/src/test/groovy/transform/stc/BugsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/BugsSTCTest.groovy
@@ -685,18 +685,16 @@ Printer
         assertScript '''
             interface A { void m() }
             interface B { void m() }
-            interface C extends A, B {}
-
-            class D {
-             D(C c) {
-               c.m()
-             }
+            interface C extends A,B {
             }
-            class CImpl implements C {
-                void m() { }
+            class Impl implements C {
+                void m() {}
             }
 
-            new D(new CImpl())
+            void test(C c) {
+                c.m()
+            }
+            test(new Impl())
         '''
     }
 
@@ -704,16 +702,16 @@ Printer
         assertScript '''
             interface A { void m() }
             interface B { void m() }
-            class C implements A,B {
-                void m() {}
+            interface C extends A,B {
             }
-            class D {
-             D(C c) {
-               c.m()
-             }
+            class Impl implements C,A,B {
+                void m() {}
             }
 
-            new D(new C())
+            void test(C c) {
+                c.m()
+            }
+            test(new Impl())
         '''
     }
 
@@ -721,17 +719,14 @@ Printer
         assertScript '''
             interface A { void m() }
             interface B { void m() }
-            interface C extends A,B {}
-            class CImpl implements C, A,B {
+            class C implements A,B {
                 void m() {}
             }
-            class D {
-             D(C c) {
-               c.m()
-             }
-            }
 
-            new D(new CImpl())
+            void test(C c) {
+                c.m()
+            }
+            test(new C())
         '''
     }
 
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index 93d67cd829..6f1efc8dc7 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -365,7 +365,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
                     thing.addElement(2) // 'addElement' only in Stack
                 }
                 if (thing instanceof Deque || thing instanceof Stack) {
-                    assert thing.peek() in 1..2 // 'peek' in ArrayDeque and Stack but not LUB
+                    assert thing.peek() in 1..2 // 'peek' in Deque and Stack but not LUB
                 }
             }
             test(new Stack())
diff --git a/src/test/org/apache/groovy/parser/antlr4/util/AstDumper.groovy b/src/test/org/apache/groovy/parser/antlr4/util/AstDumper.groovy
index 165f2f26eb..f67e01e6c6 100644
--- a/src/test/org/apache/groovy/parser/antlr4/util/AstDumper.groovy
+++ b/src/test/org/apache/groovy/parser/antlr4/util/AstDumper.groovy
@@ -641,8 +641,7 @@ class AstNodeToScriptVisitor implements CompilationUnit.IPrimaryClassNodeOperati
 
     @Override
     void visitMethodCallExpression(MethodCallExpression expression) {
-
-        Expression objectExp = expression.getObjectExpression()
+        Expression objectExp = expression.objectExpression
         if (objectExp instanceof VariableExpression) {
             visitVariableExpression(objectExp, false)
         } else {
@@ -655,25 +654,23 @@ class AstNodeToScriptVisitor implements CompilationUnit.IPrimaryClassNodeOperati
             print '?'
         }
         print '.'
-        Expression method = expression.getMethod()
+        Expression method = expression.method
         if (method instanceof ConstantExpression) {
             visitConstantExpression(method, true)
         } else {
             method.visit(this)
         }
-        expression.getArguments().visit(this)
+        expression.arguments.visit(this)
     }
 
     @Override
     void visitStaticMethodCallExpression(StaticMethodCallExpression expression) {
         print expression?.ownerType?.name + '.' + expression?.method
-        if (expression?.arguments instanceof VariableExpression || expression?.arguments instanceof MethodCallExpression) {
-            print '('
-            expression?.arguments?.visit this
-            print ')'
-        } else {
-            expression?.arguments?.visit this
-        }
+        boolean parens = expression?.arguments instanceof VariableExpression
+                    || expression?.arguments instanceof MethodCallExpression
+        if (parens) print '('
+        expression?.arguments?.visit this
+        if (parens) print ')'
     }
 
     @Override
@@ -1132,5 +1129,4 @@ class AstNodeToScriptVisitor implements CompilationUnit.IPrimaryClassNodeOperati
         }
         return true
     }
-
 }
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/TypeInferenceStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/TypeInferenceStaticCompileTest.groovy
index b1ff1521c5..b7ae38f82b 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/TypeInferenceStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/TypeInferenceStaticCompileTest.groovy
@@ -26,33 +26,9 @@ import groovy.transform.stc.TypeInferenceSTCTest
  */
 class TypeInferenceStaticCompileTest extends TypeInferenceSTCTest implements StaticCompilationTestSupport {
 
-    @Override @NotYetImplemented
+    @Override
+    @NotYetImplemented
     void testInstanceOf9() {
-        super.testInstanceOf9()
-    }
-
-    @Override @NotYetImplemented
-    void testMultipleInstanceOf1() {
-        super.testMultipleInstanceOf1()
-    }
-
-    @Override @NotYetImplemented
-    void testMultipleInstanceOf2() {
-        super.testMultipleInstanceOf2()
-    }
-
-    @Override @NotYetImplemented
-    void testMultipleInstanceOf3() {
-        super.testMultipleInstanceOf3()
-    }
-
-    @Override @NotYetImplemented
-    void testMultipleInstanceOf4() {
-        super.testMultipleInstanceOf4()
-    }
-
-    @Override @NotYetImplemented
-    void testMultipleInstanceOf5() {
-        super.testMultipleInstanceOf5()
+        super.testInstanceOf9() // GROOVY-7971
     }
 }
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/ReproducibleBytecodeBugs.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/ReproducibleBytecodeBugs.groovy
index 7ca44be0f8..c4586791c0 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/ReproducibleBytecodeBugs.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/ReproducibleBytecodeBugs.groovy
@@ -16,35 +16,34 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
-
 package org.codehaus.groovy.classgen.asm.sc.bugs
 
 import groovy.transform.stc.StaticTypeCheckingTestCase
 import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
 
 class ReproducibleBytecodeBugs extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+
     // GROOVY-8142
-    void testShouldNotProduceDeterministicBytecode() {
+    void testShouldProduceDeterministicBytecode() {
         100.times {
             assertScript '''
-            interface Project {
-                File file()
-            }
-            interface FileOperations {
-                File file()
-            }
-            interface ProjectInternal extends Project, FileOperations {
-            }
+                interface Project {
+                    File file()
+                }
+                interface FileOperations {
+                    File file()
+                }
+                interface ProjectInternal extends Project, FileOperations {
+                }
 
-            class Check {
-                void test(ProjectInternal p) {
-                    def f = p.file()
+                class Check {
+                    void test(ProjectInternal p) {
+                        def f = p.file()
+                    }
                 }
-            }
 
-            def c = new Check()
-        '''
+                def c = new Check()
+            '''
 
             assert astTrees['Check'][1].contains('INVOKEINTERFACE FileOperations.file ()Ljava/io/File;') : "Incorrect bytecode found in iteration $it"
         }
@@ -54,20 +53,20 @@ class ReproducibleBytecodeBugs extends StaticTypeCheckingTestCase implements Sta
     void testShouldAlwaysAddClosureSharedVariablesInSameOrder() {
         100.times {
             assertScript '''
-            class Check {
-                void test() {
-                    def xx = true
-                    def moot = "bar"
-                    def kr = [:]
-                    def zorg = []
-                    def cl = {
-                        def (x,y,z,t) = [xx, moot, kr , zorg]
+                class Check {
+                    void test() {
+                        def xx = true
+                        def moot = "bar"
+                        def kr = [:]
+                        def zorg = []
+                        def cl = {
+                            def (x,y,z,t) = [xx, moot, kr , zorg]
+                        }
                     }
                 }
-            }
 
-            def c = new Check()
-        '''
+                def c = new Check()
+            '''
 
             def bytecode = astTrees['Check$_test_closure1'][1]
             assertOrdered it, bytecode,
@@ -75,17 +74,15 @@ class ReproducibleBytecodeBugs extends StaticTypeCheckingTestCase implements Sta
                     'PUTFIELD Check$_test_closure1.moot',
                     'PUTFIELD Check$_test_closure1.kr',
                     'PUTFIELD Check$_test_closure1.zorg'
-
         }
     }
 
-
-    private static void assertOrdered(int iteration, String bytecode, String... elements) {
+    private static void assertOrdered(int iteration, String bytecode, String... strings) {
         int start = 0
-        elements.eachWithIndex { it, i ->
-            start = bytecode.indexOf(it, start)
+        strings.eachWithIndex { string, index ->
+            start = bytecode.indexOf(string, start)
             if (start == -1) {
-                throw new AssertionError("Iteration $iteration - Element [$it] not found in order (expected to find it at index $i)")
+                throw new AssertionError("Iteration $iteration - Element [$string] not found in order (expected to find it at index $index)")
             }
         }
     }