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