Skip to content

Commit fe33fbe

Browse files
committed
Properly detect changing 'this' reference in tail calls to members
1 parent 9731980 commit fe33fbe

File tree

1 file changed

+36
-5
lines changed

1 file changed

+36
-5
lines changed

compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
4242
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
4343
import org.jetbrains.jet.lang.resolve.calls.tail.TailRecursionKind;
44+
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
45+
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
46+
import org.jetbrains.jet.lang.resolve.scopes.receivers.ThisReceiver;
4447
import org.jetbrains.jet.lang.types.JetType;
4548
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
4649
import org.jetbrains.jet.lexer.JetTokens;
@@ -55,9 +58,7 @@
5558
import static org.jetbrains.jet.lang.resolve.BindingContext.CAPTURED_IN_CLOSURE;
5659
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
5760
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
58-
import static org.jetbrains.jet.lang.resolve.calls.tail.TailRecursionKind.IN_TRY;
59-
import static org.jetbrains.jet.lang.resolve.calls.tail.TailRecursionKind.MIGHT_BE;
60-
import static org.jetbrains.jet.lang.resolve.calls.tail.TailRecursionKind.NON_TAIL;
61+
import static org.jetbrains.jet.lang.resolve.calls.tail.TailRecursionKind.*;
6162
import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType;
6263

6364
public class JetFlowInformationProvider {
@@ -653,7 +654,8 @@ public void execute(@NotNull Instruction instruction) {
653654
if (resolvedCall == null) return;
654655

655656
// is this a recursive call?
656-
if (!resolvedCall.getResultingDescriptor().getOriginal().equals(subroutineDescriptor)) return;
657+
CallableDescriptor functionDescriptor = resolvedCall.getResultingDescriptor();
658+
if (!functionDescriptor.getOriginal().equals(subroutineDescriptor)) return;
657659

658660
JetElement element = callInstruction.getElement();
659661
//noinspection unchecked
@@ -676,7 +678,9 @@ public void execute(@NotNull Instruction instruction) {
676678
new TailRecursionDetector(subroutine, callInstruction)
677679
);
678680

679-
TailRecursionKind kind = isTail ? MIGHT_BE : NON_TAIL;
681+
boolean sameThisObject = sameThisObject(resolvedCall);
682+
683+
TailRecursionKind kind = isTail && sameThisObject ? MIGHT_BE : NON_TAIL;
680684

681685
KindAndCall kindAndCall = calls.get(element);
682686
calls.put(element,
@@ -708,6 +712,33 @@ public void execute(@NotNull Instruction instruction) {
708712
}
709713
}
710714

715+
private boolean sameThisObject(ResolvedCall<?> resolvedCall) {
716+
// A tail call is not allowed to change dispatch receiver
717+
// class C {
718+
// fun foo(other: C) {
719+
// other.foo(this) // not a tail call
720+
// }
721+
// }
722+
ReceiverParameterDescriptor thisObject = resolvedCall.getResultingDescriptor().getExpectedThisObject();
723+
ReceiverValue thisObjectValue = resolvedCall.getThisObject();
724+
if (thisObject == null || !thisObjectValue.exists()) return true;
725+
726+
DeclarationDescriptor classDescriptor = null;
727+
if (thisObjectValue instanceof ThisReceiver) {
728+
// foo() -- implicit receiver
729+
classDescriptor = ((ThisReceiver) thisObjectValue).getDeclarationDescriptor();
730+
}
731+
else if (thisObjectValue instanceof ExpressionReceiver) {
732+
JetExpression expression = JetPsiUtil.deparenthesize(((ExpressionReceiver) thisObjectValue).getExpression());
733+
if (expression instanceof JetThisExpression) {
734+
// this.foo() -- explicit receiver
735+
JetThisExpression thisExpression = (JetThisExpression) expression;
736+
classDescriptor = trace.get(BindingContext.REFERENCE_TARGET, thisExpression.getInstanceReference());
737+
}
738+
}
739+
return thisObject.getContainingDeclaration() == classDescriptor;
740+
}
741+
711742
private static TailRecursionKind combineKinds(TailRecursionKind kind, @Nullable TailRecursionKind existingKind) {
712743
TailRecursionKind resultingKind;
713744
if (existingKind == null || existingKind == kind) {

0 commit comments

Comments
 (0)