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/06/29 20:24:46 UTC
[groovy] branch GROOVY_3_0_X updated: GROOVY-10180, GROOVY-10668: STC: check declared type before `instanceof`
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
new a867bbb108 GROOVY-10180, GROOVY-10668: STC: check declared type before `instanceof`
a867bbb108 is described below
commit a867bbb108ac507418d7dfc10b40e385be6d1bbe
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Jun 29 14:54:22 2022 -0500
GROOVY-10180, GROOVY-10668: STC: check declared type before `instanceof`
3_0_X rollback
---
.../transform/stc/StaticTypeCheckingVisitor.java | 26 +--
.../stc/ClosureParamTypeInferenceSTCTest.groovy | 3 +
.../transform/stc/TypeInferenceSTCTest.groovy | 184 ++++++++++++++-------
3 files changed, 142 insertions(+), 71 deletions(-)
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 03db7b99a2..183b9e63fe 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -3776,19 +3776,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
Receiver.make(typeCheckingContext.getEnclosingClassNode()));
addReceivers(owners, enclosingClass, typeCheckingContext.delegationMetadata.getParent(), "owner.");
} else {
- if (!typeCheckingContext.temporaryIfBranchTypeInformation.isEmpty()) { // GROOVY-10180, et al.
- List<ClassNode> instanceofTypes = getTemporaryTypesForExpression(objectExpression);
- if (instanceofTypes != null && !instanceofTypes.isEmpty()) {
- ClassNode instanceofType = instanceofTypes.size() == 1 ? instanceofTypes.get(0)
- : new UnionTypeClassNode(instanceofTypes.toArray(ClassNode.EMPTY_ARRAY));
- owners.add(Receiver.make(instanceofType));
- }
- }
- if (typeCheckingContext.lastImplicitItType != null
- && objectExpression instanceof VariableExpression
- && ((Variable) objectExpression).getName().equals("it")) {
- owners.add(Receiver.make(typeCheckingContext.lastImplicitItType));
- }
if (isClassClassNodeWrappingConcreteType(receiver)) {
ClassNode staticType = receiver.getGenericsTypes()[0].getType();
owners.add(Receiver.make(staticType)); // Type from Class<Type>
@@ -3802,6 +3789,19 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
owners.add(Receiver.make(OBJECT_TYPE));
}
}
+ if (typeCheckingContext.lastImplicitItType != null
+ && objectExpression instanceof VariableExpression
+ && ((Variable) objectExpression).getName().equals("it")) {
+ owners.add(Receiver.make(typeCheckingContext.lastImplicitItType));
+ }
+ if (!typeCheckingContext.temporaryIfBranchTypeInformation.isEmpty()) {
+ List<ClassNode> instanceofTypes = getTemporaryTypesForExpression(objectExpression);
+ if (instanceofTypes != null && !instanceofTypes.isEmpty()) {
+ ClassNode instanceofType = instanceofTypes.size() == 1 ? instanceofTypes.get(0)
+ : new UnionTypeClassNode(instanceofTypes.toArray(ClassNode.EMPTY_ARRAY));
+ owners.add(Receiver.make(instanceofType));
+ }
+ }
}
return owners;
}
diff --git a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
index d2d86a9cd4..9bd1c17085 100644
--- a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
@@ -18,6 +18,8 @@
*/
package groovy.transform.stc
+import groovy.test.NotYetImplemented
+
/**
* Unit tests for static type checking : closure parameter type inference.
*/
@@ -1487,6 +1489,7 @@ method()
'''
}
+ @NotYetImplemented
void testGroovy10180() {
assertScript '''
void test(args) {
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index 27e2e50277..02113fe08f 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -18,6 +18,7 @@
*/
package groovy.transform.stc
+import groovy.test.NotYetImplemented
import org.codehaus.groovy.ast.ClassHelper
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.ast.MethodNode
@@ -91,25 +92,16 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testInstanceOf() {
+ void testInstanceOf1() {
assertScript '''
Object o
- if (o instanceof String) o.toUpperCase()
- '''
- }
-
- void testEmbeddedInstanceOf() {
- assertScript '''
- Object o
- if (o instanceof Object) {
- if (o instanceof String) {
- o.toUpperCase()
- }
+ if (o instanceof String) {
+ o.toUpperCase()
}
'''
}
- void testEmbeddedInstanceOf2() {
+ void testInstanceOf2() {
assertScript '''
Object o
if (o instanceof String) {
@@ -120,40 +112,55 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testEmbeddedInstanceOf3() {
+ void testInstanceOf3() {
shouldFailWithMessages '''
Object o
if (o instanceof String) {
- if (o instanceof Object) { // causes the inferred type of 'o' to be overwritten
- o.toUpperCase()
- }
+ o.toUpperCase()
}
- ''', 'Cannot find matching method java.lang.Object#toUpperCase()'
+ o.toUpperCase() // ensure that type information is reset
+ ''',
+ 'Cannot find matching method java.lang.Object#toUpperCase()'
}
- void testInstanceOfAfterEach() {
+ void testInstanceOf4() {
shouldFailWithMessages '''
Object o
if (o instanceof String) {
o.toUpperCase()
+ } else {
+ o.toUpperCase() // ensure that type information is reset
}
- o.toUpperCase() // ensure that type information is lost after if()
- ''', 'Cannot find matching method java.lang.Object#toUpperCase()'
+ ''',
+ 'Cannot find matching method java.lang.Object#toUpperCase()'
}
- void testInstanceOfInElseBranch() {
- shouldFailWithMessages '''
- Object o
- if (o instanceof String) {
- o.toUpperCase()
- } else {
- o.toUpperCase() // ensure that type information is lost in else
+ void testInstanceOf5() {
+ assertScript '''
+ class A {
+ void bar() {
+ }
}
- ''', 'Cannot find matching method java.lang.Object#toUpperCase()'
+ class B {
+ void bar() {
+ }
+ }
+
+ def foo(o) {
+ if (o instanceof A) {
+ o.bar()
+ }
+ if (o instanceof B) {
+ o.bar()
+ }
+ }
+ foo(new A())
+ foo(new B())
+ '''
}
// GROOVY-9454
- void testInstanceOfOnGenericProperty() {
+ void testInstanceOf6() {
assertScript '''
interface Face {
}
@@ -179,32 +186,73 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'''
}
- void testMultipleInstanceOf() {
+ // GROOVY-10667
+ void testInstanceOf7() {
assertScript '''
- class A {
- void bar() { }
+ trait Tagged {
+ String tag
}
- class B {
- void bar() { }
+ class TaggedException extends Exception implements Tagged {
}
- def foo(o) {
- if (o instanceof A) {
- o.bar()
+ static void doSomething1(Exception e) {
+ if (e instanceof Tagged) {
+ //println e.tag
+ doSomething2(e) // Cannot find matching method #doSomething2(Tagged)
}
- if (o instanceof B) {
- o.bar()
+ }
+ static void doSomething2(Exception e) {
+ }
+
+ doSomething1(new TaggedException(tag:'Test'))
+ '''
+ }
+
+ void testNestedInstanceOf1() {
+ assertScript '''
+ Object o
+ if (o instanceof Object) {
+ if (o instanceof String) {
+ o.toUpperCase()
}
}
- foo(new A())
- foo(new B())
'''
+ }
+
+ void testNestedInstanceOf2() {
shouldFailWithMessages '''
+ Object o
+ if (o instanceof String) {
+ if (o instanceof Object) { // causes the inferred type of 'o' to be overwritten
+ o.toUpperCase()
+ }
+ }
+ ''',
+ 'Cannot find matching method java.lang.Object#toUpperCase()'
+ }
+
+ void testNestedInstanceOf3() {
+ assertScript '''
class A {
- void bar() { }
+ int foo() { 1 }
}
class B {
- void bar() { }
+ int foo2() { 2 }
+ }
+ def o = new A()
+ int result = o instanceof A ? o.foo() : (o instanceof B ? o.foo2() : 3)
+ '''
+ }
+
+ void testMultipleInstanceOf1() {
+ shouldFailWithMessages '''
+ class A {
+ void bar() {
+ }
+ }
+ class B {
+ void bar() {
+ }
}
def foo(o) {
@@ -241,16 +289,22 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'Reference to method is ambiguous. Cannot choose between [float java.lang.Integer#floatValue(), float java.lang.Double#floatValue()]'
}
- void testInstanceOfInTernaryOp() {
+ // GROOVY-10668
+ void testMultipleInstanceOf3() {
assertScript '''
- class A {
- int foo() { 1 }
- }
- class B {
- int foo2() { 2 }
- }
- def o = new A()
- int result = o instanceof A?o.foo():(o instanceof B?o.foo2():3)
+ def toArray(Object value) {
+ def result
+ if (value instanceof List)
+ result = value.toArray()
+ else if (value instanceof String || value instanceof GString)
+ result = value.toString().split(',')
+ else
+ throw new Exception('not supported')
+
+ return result
+ }
+ toArray([1,2,3])
+ toArray('1,2,3')
'''
}
@@ -387,11 +441,18 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
''', 'Cannot find matching method java.lang.Object#toUpperCase()'
}
- void testShouldNotAllowDynamicVariable() {
- shouldFailWithMessages '''
- String name = 'Guillaume'
- println naamme
- ''', 'The variable [naamme] is undeclared'
+ @NotYetImplemented // GROOVY-10217
+ void testInstanceOfThenSubscriptOperator() {
+ assertScript '''
+ void test(Object o) {
+ if (o instanceof List) {
+ assert o[0] == 1
+ def x = (List) o
+ assert x[0] == 1
+ }
+ }
+ test([1])
+ '''
}
void testInstanceOfInferenceWithImplicitIt() {
@@ -522,6 +583,13 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
'''
}
+ void testShouldNotAllowDynamicVariable() {
+ shouldFailWithMessages '''
+ String name = 'Guillaume'
+ println naamme
+ ''', 'The variable [naamme] is undeclared'
+ }
+
void testShouldNotFailWithWith() {
assertScript '''
class A {