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)")
}
}
}