This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 5b62bf5846 GROOVY-11889: STC: instanceof check rejects
UnionTypeClassNode members as incompatible types
5b62bf5846 is described below
commit 5b62bf58461010f886bd81993af2a11043e33945
Author: Paul King <[email protected]>
AuthorDate: Wed Apr 1 21:08:29 2026 +1000
GROOVY-11889: STC: instanceof check rejects UnionTypeClassNode members as
incompatible types
---
.../transform/stc/StaticTypeCheckingVisitor.java | 11 ++++-
.../transform/stc/TypeInferenceSTCTest.groovy | 50 +++++++++++++++++++++-
2 files changed, 58 insertions(+), 3 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 fb35f16fce..5e2eaa5a65 100644
---
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -982,7 +982,16 @@ public class StaticTypeCheckingVisitor extends
ClassCodeVisitorSupport {
} else if (op == KEYWORD_INSTANCEOF) {
rType = rightExpression.getType();
if (lType instanceof
WideningCategories.LowestUpperBoundClassNode) lType =
lType.getUnresolvedSuperClass();
- if (!lType.isInterface() && !rType.isInterface() &&
!(lType.isDerivedFrom(rType) || rType.isDerivedFrom(lType))) {
+ if (lType instanceof UnionTypeClassNode union) {
+ boolean compatible = rType.isInterface();
+ for (int i = 0; !compatible && i <
union.getDelegates().length; i += 1) {
+ ClassNode delegate = union.getDelegates()[i];
+ compatible = delegate.isInterface() ||
delegate.isDerivedFrom(rType) || rType.isDerivedFrom(delegate);
+ }
+ if (!compatible) {
+ addError("Incompatible instanceof types: " +
prettyPrintTypeName(lType) + " and " + prettyPrintTypeName(rType), expression);
+ }
+ } else if (!lType.isInterface() && !rType.isInterface() &&
!(lType.isDerivedFrom(rType) || rType.isDerivedFrom(lType))) {
addError("Incompatible instanceof types: " +
prettyPrintTypeName(lType) + " and " + prettyPrintTypeName(rType), expression);
}
pushInstanceOfTypeInfo(leftExpression, rightExpression);
diff --git a/src/test/groovy/groovy/transform/stc/TypeInferenceSTCTest.groovy
b/src/test/groovy/groovy/transform/stc/TypeInferenceSTCTest.groovy
index 4adea4b051..4a3ddf16da 100644
--- a/src/test/groovy/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -537,8 +537,8 @@ class TypeInferenceSTCTest extends
StaticTypeCheckingTestCase {
'''
}
- // GROOVY-7971: negated || instanceof — re-check instanceof in else branch
- @Test @org.junit.jupiter.api.Disabled('requires instanceof compatibility
fix for UnionTypeClassNode')
+ // GROOVY-11889: negated || instanceof — re-check instanceof in else branch
+ @Test
void testInstanceOf25() {
assertScript '''
void test(Object x) {
@@ -569,6 +569,52 @@ class TypeInferenceSTCTest extends
StaticTypeCheckingTestCase {
'''
}
+ // GROOVY-11889: instanceof interface check on union type
+ @Test
+ void testInstanceOf27() {
+ assertScript '''
+ void test(Object x) {
+ if (x instanceof String || x instanceof Integer) {
+ if (x instanceof Serializable) {
+ assert true
+ }
+ }
+ }
+ test('hello')
+ test(42)
+ '''
+ }
+
+ // GROOVY-11889: union containing interface delegate
+ @Test
+ void testInstanceOf28() {
+ assertScript '''
+ void test(Object x) {
+ if (x instanceof Serializable || x instanceof String) {
+ if (x instanceof String) {
+ assert true
+ }
+ }
+ }
+ test('hello')
+ '''
+ }
+
+ // GROOVY-11889: incompatible instanceof on union type should produce error
+ @Test
+ void testInstanceOf29() {
+ shouldFailWithMessages '''
+ void test(Object x) {
+ if (x instanceof String || x instanceof Integer) {
+ if (x instanceof Long) {
+ // unreachable - neither String nor Integer is related
to Long
+ }
+ }
+ }
+ ''',
+ 'Incompatible instanceof types'
+ }
+
// GROOVY-5226
@Test
void testNestedInstanceOf1() {