You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2026/06/08 04:01:38 UTC

(groovy) branch master updated: GROOVY-12066: @Invariant on a static nested class without an explicit constructor fails compilation with "BUG! exception in 'instruction selection'

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

paulk-asert 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 96ab17aee5 GROOVY-12066: @Invariant on a static nested class without an explicit constructor fails compilation with "BUG! exception in 'instruction selection'
96ab17aee5 is described below

commit 96ab17aee5d15c64ea6215ac4228d9f8a1a12bb8
Author: Paul King <pa...@asert.com.au>
AuthorDate: Mon Jun 8 11:35:57 2026 +1000

    GROOVY-12066: @Invariant on a static nested class without an explicit constructor fails compilation with "BUG! exception in 'instruction selection'
---
 .../generation/ClassInvariantGenerator.java        |  6 +++++-
 .../generation/PreconditionGenerator.java          |  4 +++-
 .../tests/inv/SimpleClassInvariantTests.groovy     | 25 ++++++++++++++++++++++
 3 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/subprojects/groovy-contracts/src/main/java/org/apache/groovy/contracts/generation/ClassInvariantGenerator.java b/subprojects/groovy-contracts/src/main/java/org/apache/groovy/contracts/generation/ClassInvariantGenerator.java
index 8d5cfc883a..89f63ef62e 100644
--- a/subprojects/groovy-contracts/src/main/java/org/apache/groovy/contracts/generation/ClassInvariantGenerator.java
+++ b/subprojects/groovy-contracts/src/main/java/org/apache/groovy/contracts/generation/ClassInvariantGenerator.java
@@ -118,7 +118,11 @@ public class ClassInvariantGenerator extends BaseGenerator {
         } else if (statement instanceof BlockStatement blockStatement) {
             blockStatement.addStatement(invariantMethodCall);
         } else {
-            final BlockStatement assertionBlock = block(statement, invariantMethodCall);
+            // statement may be null, e.g. the synthetic default constructor of a
+            // static nested class still has a null body at this phase (GROOVY-12066)
+            final BlockStatement assertionBlock = statement == null
+                    ? block(invariantMethodCall)
+                    : block(statement, invariantMethodCall);
             method.setCode(assertionBlock);
         }
     }
diff --git a/subprojects/groovy-contracts/src/main/java/org/apache/groovy/contracts/generation/PreconditionGenerator.java b/subprojects/groovy-contracts/src/main/java/org/apache/groovy/contracts/generation/PreconditionGenerator.java
index 76e86386fd..c6b06c0c4a 100644
--- a/subprojects/groovy-contracts/src/main/java/org/apache/groovy/contracts/generation/PreconditionGenerator.java
+++ b/subprojects/groovy-contracts/src/main/java/org/apache/groovy/contracts/generation/PreconditionGenerator.java
@@ -114,7 +114,9 @@ public class PreconditionGenerator extends BaseGenerator {
                     modifiedMethodCode.getStatements().add(statement);
                 }
             }
-        } else {
+        } else if (method.getCode() != null) {
+            // guard against a null method body (e.g. a synthetic default
+            // constructor whose code is not yet populated) - GROOVY-12066
             modifiedMethodCode.addStatement(method.getCode());
         }
 
diff --git a/subprojects/groovy-contracts/src/test/groovy/org/apache/groovy/contracts/tests/inv/SimpleClassInvariantTests.groovy b/subprojects/groovy-contracts/src/test/groovy/org/apache/groovy/contracts/tests/inv/SimpleClassInvariantTests.groovy
index 8272db6157..e20960812f 100644
--- a/subprojects/groovy-contracts/src/test/groovy/org/apache/groovy/contracts/tests/inv/SimpleClassInvariantTests.groovy
+++ b/subprojects/groovy-contracts/src/test/groovy/org/apache/groovy/contracts/tests/inv/SimpleClassInvariantTests.groovy
@@ -276,6 +276,31 @@ class Rocket {
         }
     }
 
+    // GROOVY-12066
+    @Test
+    void class_invariant_on_static_nested_class_without_explicit_constructor() {
+
+        def c = add_class_to_classpath """
+            import groovy.contracts.*
+
+            class Outer {
+                @Invariant({ value >= 0 })
+                static class Inner {
+                    int value = 1
+                    def decrease() { value -= 2 }
+                }
+            }
+        """
+
+        def inner = c.getDeclaredClasses().find { it.simpleName == 'Inner' }
+        def instance = inner.newInstance()
+
+        // and the invariant is actually enforced on the nested class
+        shouldFail ClassInvariantViolation, {
+            instance.decrease()
+        }
+    }
+
     @Test
     void private_field_access_in_descendant_class() {