Scott Murphy Heiberg created GROOVY-12742:
---------------------------------------------
Summary: groovy-contracts: a class invariant makes the trait
forwarders and trait property accessors of the class return null
Key: GROOVY-12742
URL: https://issues.apache.org/jira/browse/GROOVY-12742
Project: Groovy
Issue Type: Bug
Components: groovy-contracts
Affects Versions: 6.0.0
Reporter: Scott Murphy Heiberg
h3. Problem
A class-level {{@Invariant}} on a class that implements a trait makes every
method the trait contributes return {{null}}; a primitive return fails with a
cast exception:
{code:groovy}
import groovy.contracts.*
trait Named {
String name = 'x'
String greet() { "hi $name" }
int one() { 1 }
}
@Invariant({ count >= 0 })
class Counter implements Named {
int count
}
def c = new Counter()
assert c.greet() == 'hi x' // greet() returns null
c.one() // GroovyCastException: Cannot cast 'null' to
class 'int'
{code}
Trait properties are affected too ({{getSize()}} of a trait property {{int
size}} fails the same way). The interface equivalent, where the class writes
the method bodies itself, is fine. Reproduced on Groovy 6.0.0 and on master
(df1fe66ed1).
h3. Cause
{{ClassInvariantGenerator.addInvariantAssertionStatement}} weaves the invariant
call before each {{return}} only when the method body is a block. The
forwarders and property accessors that {{TraitComposer}} generates in the
implementing class have a bare expression or return statement as body, so the
generator fell back to appending the (void) invariant call after it, and the
forwarder's implicit return value was lost. The same fallback left a
{{@Synchronized}} body unwrapped, so an explicit {{return}} inside it skipped
the invariant.
h3. Fix
Normalise the body to a block first (the {{ensureBlockBody}} step the
postcondition path already performs since GROOVY-12084), so the implicit return
is made explicit and the invariant is checked before each return. Trait
forwarders and property accessors keep their values and are checked; the
{{@Synchronized}} explicit-return case is checked as well. Pull request to
follow.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)