You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Reference to field or property with explicit this in then block #2343
Making a reference to the spec's field or property using explicit-this in the then block produces an STC error. No error shows for this.myField in the when block.
this.myField in the then is written as $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(0), this).myField in the feature method. record returns Object, so as far as STC is concerned, it can't find the property "myField" in java.lang.Object.
Spock 2.4
Groovy 5.0.5
To Reproduce
@groovy.transform.TypeCheckedclassSomeSpecextendsSpecification {
String myField
voidtestField() {
when:
this.myField ='test'then:
this.myField =='test'// [Static type checking] - No such property: myField for class: java.lang.Object
}
}
Expected behavior
this.myField checks properly or is exempted from STC in when, then, expect, etc.
Actual behavior
"[Static type checking] - No such property: myField for class: java.lang.Object"
I don't think we support @TypeChecked or @CompileStatic but afair too much rely on Groovy duck-typing for this to work.
Otherwise, I guess we probably need to sprinkle in type-casts in various places or make some methods generic instead of Object.
Not sure how record works, but if it was T <T> record(int i, T t) instead of Object record(int i, Object o) then you should get inferencing. Also, I'd need to look further to understand why the when block is okay. Might be a source position thing.
That's what I meant with "make some methods generic instead of Object", yes.
But I somehow doubt that the record method is the only problematic part.
In the when it is not a problem because it is not rewritten to be an assertion.
It is just an assignment and stays like that.
If you in the when write assert this.myField == 'test' you get the same problem there.
I'm not saying we should not make the record generic.
I'm just saying that there will most probably quite some other parts that are not compatible with STC.
Condition rewriting wraps the receiver in ValueRecorder.record, whose declared return type was Object. That signature discarded the receiver's static type, preventing the type checker from resolving its members.
ValueRecorder.record now uses a type parameter for its argument and return value, preserving the recorded expression's static type without changing the recording logic. Regression coverage exercises properties and public fields across then, expect, and explicit assertions in when.
Activity
Vampire commentedon Apr 21, 2026
I don't think we support
@TypeCheckedor@CompileStaticbut afair too much rely on Groovy duck-typing for this to work.Otherwise, I guess we probably need to sprinkle in type-casts in various places or make some methods generic instead of
Object.eric-milles commentedon Apr 21, 2026
Not sure how
recordworks, but if it wasT <T> record(int i, T t)instead ofObject record(int i, Object o)then you should get inferencing. Also, I'd need to look further to understand why thewhenblock is okay. Might be a source position thing.Vampire commentedon Apr 21, 2026
That's what I meant with "make some methods generic instead of
Object", yes.But I somehow doubt that the
recordmethod is the only problematic part.In the
whenit is not a problem because it is not rewritten to be an assertion.It is just an assignment and stays like that.
If you in the
whenwriteassert this.myField == 'test'you get the same problem there.I'm not saying we should not make the
recordgeneric.I'm just saying that there will most probably quite some other parts that are not compatible with STC.
mvanhorn commentedon Oct 10, 2026
Condition rewriting wraps the receiver in ValueRecorder.record, whose declared return type was Object. That signature discarded the receiver's static type, preventing the type checker from resolving its members.
ValueRecorder.record now uses a type parameter for its argument and return value, preserving the recorded expression's static type without changing the recording logic. Regression coverage exercises properties and public fields across then, expect, and explicit assertions in when.
#2435