Skip to content

Commit

Permalink
GROOVY-9089: SC: no cast exception for implicit receiver
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-milles committed Oct 23, 2022
1 parent 29c4858 commit dac95ae
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ public class StaticInvocationWriter extends InvocationWriter {

private MethodCallExpression currentCall;

public MethodCallExpression getCurrentCall() {
return currentCall;
}

public StaticInvocationWriter(final WriterController wc) {
super(wc);
}
Expand Down Expand Up @@ -342,7 +346,7 @@ protected boolean writeDirectMethodCall(final MethodNode target, final boolean i
return true;
}

Expression fixedReceiver = null;
Expression fixedReceiver = receiver;
boolean fixedImplicitThis = implicitThis;
if (target.isProtected()) {
ClassNode node = receiver == null ? ClassHelper.OBJECT_TYPE : controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
Expand Down Expand Up @@ -377,8 +381,9 @@ protected boolean writeDirectMethodCall(final MethodNode target, final boolean i
}
}
if (receiver != null && !isSuperExpression(receiver)) {
// in order to avoid calls to castToType, which is the dynamic behaviour, we make sure that we call CHECKCAST instead then replace the top operand type
return super.writeDirectMethodCall(target, fixedImplicitThis, new CheckcastReceiverExpression(fixedReceiver != null ? fixedReceiver : receiver, target), args);
// in order to avoid calls to castToType, which is the dynamic behaviour, make sure that we call CHECKCAST instead then replace the top operand type
if (currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER) == null) fixedReceiver = new CheckcastReceiverExpression(fixedReceiver, target);
return super.writeDirectMethodCall(target, fixedImplicitThis, fixedReceiver, args);
}
return super.writeDirectMethodCall(target, implicitThis, receiver, args);
}
Expand Down Expand Up @@ -478,7 +483,7 @@ protected void loadArguments(final List<Expression> argumentList, final Paramete
} else {
controller.getSourceUnit().addFatalError("Binding failed" +
" for arguments [" + argumentList.stream().map(arg -> typeChooser.resolveType(arg, classNode).toString(false)).collect(Collectors.joining(", ")) + "]" +
" and parameters [" + Arrays.stream(parameters).map(prm -> prm.getType().toString(false)).collect(Collectors.joining(", ")) + "]", getCurrentCall());
" and parameters [" + Arrays.stream(parameters).map(prm -> prm.getType().toString(false)).collect(Collectors.joining(", ")) + "]", currentCall);
}
}
for (int i = 0; i < nArgs; i += 1) {
Expand Down Expand Up @@ -753,10 +758,6 @@ public ClassNode getType() {
}
}

public MethodCallExpression getCurrentCall() {
return currentCall;
}

@Override
protected boolean makeCachedCall(final Expression origin, final ClassExpression sender, final Expression receiver, final Expression message, final Expression arguments, final MethodCallerMultiAdapter adapter, final boolean safe, final boolean spreadSafe, final boolean implicitThis, final boolean containsSpreadExpression) {
return false;
Expand Down
52 changes: 46 additions & 6 deletions src/test/groovy/transform/stc/ClosuresSTCTest.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -904,21 +904,61 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
}

// GROOVY-6343
void testAccessStaticFieldFromNestedClosures() {
void testAccessStaticFieldFromNestedClosure() {
assertScript '''
class A {
public static final CONST = "a"
public static List doSomething() {
return (0..1).collect{ int x ->
(0..1).collect{ int y ->
static List doSomething() {
return (0..1).collect { int x ->
(0..1).collect { int y ->
return CONST
}
}
}
}
A.doSomething()
def result = A.doSomething()
assert result == [['a','a'],['a','a']]
'''
}

// GROOVY-9089
void testOwnerVersusDelegateFromNestedClosure() {
String declarations = '''
class A {
def p = 'outer delegate'
def m() { return this.p }
}
class B {
def p = 'inner delegate'
def m() { return this.p }
}
void outer(@DelegatesTo(value=A, strategy=Closure.DELEGATE_FIRST) Closure block) {
new A().with(block)
}
void inner(@DelegatesTo(value=B, strategy=Closure.DELEGATE_FIRST) Closure block) {
new B().with(block)
}
'''

assertScript declarations + '''
outer {
inner {
assert m() == 'inner delegate'
assert owner.m() == 'outer delegate'
assert delegate.m() == 'inner delegate'
}
}
'''

assertScript declarations + '''
outer {
inner {
assert p == 'inner delegate'
assert owner.p == 'outer delegate'
assert delegate.p == 'inner delegate'
}
}
'''
}

Expand Down

0 comments on commit dac95ae

Please sign in to comment.