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() {

Reply via email to