Skip to content

Commit 0179f9b

Browse files
committed
GROOVY-11907: SC: trait static field helper generates invalid bytecode when method-level DYNAMIC_RESOLUTION is present (GROOVY-11817 regression)
1 parent 9941325 commit 0179f9b

2 files changed

Lines changed: 45 additions & 2 deletions

File tree

src/main/java/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ private Expression transformBinaryExpression(final BinaryExpression exp, final C
220220
private Expression transformFieldReference(final Expression exp, final FieldNode fn, final boolean isStatic) {
221221
Expression receiver = createFieldHelperReceiver();
222222
if (isStatic) {
223-
receiver = asClass(receiver);
223+
receiver = asClass(receiver, fn); // GROOVY-11907
224224
}
225225

226226
MethodCallExpression mce = callX(receiver, Traits.helperGetterName(fn));
@@ -352,7 +352,17 @@ private Expression createFieldHelperReceiver() {
352352
}
353353

354354
private Expression asClass(final Expression e) {
355+
return asClass(e, null);
356+
}
357+
358+
private Expression asClass(final Expression e, final FieldNode fn) {
355359
ClassNode rawClass = ClassHelper.CLASS_Type.getPlainNodeReference();
356-
return ternaryX(isInstanceOfX(e, rawClass), e, callX(e, "getClass"));
360+
MethodCallExpression getClassCall = callX(e, "getClass");
361+
if (fn != null && fn.isStatic()) {
362+
// GROOVY-11907: mark sub-expression for dynamic dispatch so that
363+
// GROOVY-11817's per-expression DYNAMIC_RESOLUTION check handles it
364+
getClassCall.putNodeMetaData(org.codehaus.groovy.transform.stc.StaticTypesMarker.DYNAMIC_RESOLUTION, rawClass);
365+
}
366+
return ternaryX(isInstanceOfX(e, rawClass), e, getClassCall);
357367
}
358368
}

src/test/groovy/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4053,4 +4053,37 @@ final class TraitASTTransformationTest {
40534053
new C().test()
40544054
'''
40554055
}
4056+
4057+
// GROOVY-11907
4058+
@Test
4059+
void testTraitStaticFieldWithCompileStaticAndConfigScript() {
4060+
def config = shell.getClass().getDeclaredField('config')
4061+
.tap { accessible = true }.get(shell) as org.codehaus.groovy.control.CompilerConfiguration
4062+
groovy.ui.GroovyMain.processConfigScriptText('''
4063+
withConfig(configuration) {
4064+
inline(phase: 'CONVERSION') { source, context, classNode ->
4065+
classNode.putNodeMetaData('test', 'true')
4066+
}
4067+
}
4068+
''', config)
4069+
4070+
try {
4071+
assertScript shell, '''
4072+
@CompileStatic
4073+
trait MyTrait {
4074+
static String myField
4075+
}
4076+
4077+
@CompileStatic
4078+
class MyClass implements MyTrait {
4079+
}
4080+
4081+
MyClass.myField = 'test'
4082+
assert MyClass.myField == 'test'
4083+
'''
4084+
} finally {
4085+
// clean up: remove the customizer we added
4086+
config.compilationCustomizers.removeIf { it.class.simpleName == 'InlinedASTCustomizer' }
4087+
}
4088+
}
40564089
}

0 commit comments

Comments
 (0)