Fix capturing outer this in some cases in JVM codegen
When property initializer of some inner entity (e.g. anonymous object) contains a reference to some outer entity (say, a property of the outer class), we need to make sure we called "lookupInContext" on this entity's owner class, so that "setCaptureThis" was called on the appropriate closure #KT-4176 Fixed
This commit is contained in:
@@ -18,7 +18,6 @@ package org.jetbrains.jet.codegen;
|
|||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.protobuf.ExtensionRegistry;
|
|
||||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||||
import com.intellij.openapi.util.Pair;
|
import com.intellij.openapi.util.Pair;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
@@ -42,8 +41,6 @@ import org.jetbrains.jet.descriptors.serialization.ClassData;
|
|||||||
import org.jetbrains.jet.descriptors.serialization.DescriptorSerializer;
|
import org.jetbrains.jet.descriptors.serialization.DescriptorSerializer;
|
||||||
import org.jetbrains.jet.descriptors.serialization.ProtoBuf;
|
import org.jetbrains.jet.descriptors.serialization.ProtoBuf;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
|
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||||
@@ -1328,27 +1325,24 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
@Override
|
@Override
|
||||||
public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expr) {
|
public void visitSimpleNameExpression(@NotNull JetSimpleNameExpression expr) {
|
||||||
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expr);
|
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expr);
|
||||||
if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
|
|
||||||
|
DeclarationDescriptor toLookup;
|
||||||
|
if (isLocalNamedFun(descriptor)) {
|
||||||
|
toLookup = descriptor;
|
||||||
|
}
|
||||||
|
else if (descriptor instanceof CallableMemberDescriptor) {
|
||||||
|
toLookup = descriptor.getContainingDeclaration();
|
||||||
|
}
|
||||||
|
else if (descriptor instanceof VariableDescriptor) {
|
||||||
ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) constructorContext.getContextDescriptor();
|
ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) constructorContext.getContextDescriptor();
|
||||||
for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
|
for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) {
|
||||||
//noinspection ConstantConditions
|
if (descriptor.equals(parameterDescriptor)) return;
|
||||||
if (descriptor.equals(parameterDescriptor)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
constructorContext.lookupInContext(descriptor, null, state, true);
|
toLookup = descriptor;
|
||||||
} else if (isLocalNamedFun(descriptor)) {
|
|
||||||
assert descriptor != null;
|
|
||||||
MutableClassDescriptor classDescriptor =
|
|
||||||
(MutableClassDescriptor) constructorContext.getParentContext().getContextDescriptor();
|
|
||||||
|
|
||||||
for (CallableMemberDescriptor memberDescriptor : classDescriptor.getAllCallableMembers()) {
|
|
||||||
if (descriptor.equals(memberDescriptor)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
constructorContext.lookupInContext(descriptor, null, state, true);
|
|
||||||
}
|
}
|
||||||
|
else return;
|
||||||
|
|
||||||
|
constructorContext.lookupInContext(toLookup, null, state, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
trait T {
|
||||||
|
fun result(): String
|
||||||
|
}
|
||||||
|
|
||||||
|
class A(val x: String) {
|
||||||
|
fun getx() = x
|
||||||
|
|
||||||
|
fun foo() = object : T {
|
||||||
|
val bar = getx()
|
||||||
|
|
||||||
|
override fun result() = bar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = A("OK").foo().result()
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
trait T {
|
||||||
|
fun result(): String
|
||||||
|
}
|
||||||
|
|
||||||
|
class A(val x: String) {
|
||||||
|
fun foo() = object : T {
|
||||||
|
fun bar() = x
|
||||||
|
|
||||||
|
override fun result() = bar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = A("OK").foo().result()
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
trait T {
|
||||||
|
fun result(): String
|
||||||
|
}
|
||||||
|
|
||||||
|
class A(val x: String) {
|
||||||
|
fun foo() = object : T {
|
||||||
|
val bar = x
|
||||||
|
|
||||||
|
override fun result() = bar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = A("OK").foo().result()
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
trait T {
|
||||||
|
fun result(): String
|
||||||
|
}
|
||||||
|
|
||||||
|
class A(val x: String) {
|
||||||
|
fun foo() = object : T {
|
||||||
|
fun bar() = object : T {
|
||||||
|
fun baz() = object : T {
|
||||||
|
val y = x
|
||||||
|
override fun result() = y
|
||||||
|
}
|
||||||
|
override fun result() = baz().result()
|
||||||
|
}
|
||||||
|
override fun result() = bar().result()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = A("OK").foo().result()
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
trait T {
|
||||||
|
fun result(): String
|
||||||
|
}
|
||||||
|
|
||||||
|
open class B(val x: String)
|
||||||
|
|
||||||
|
class A : B("OK") {
|
||||||
|
fun foo() = object : T {
|
||||||
|
val bar = x
|
||||||
|
|
||||||
|
override fun result() = bar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = A().foo().result()
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
trait T {
|
||||||
|
fun result(): String
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class A<Z>(val x: Z)
|
||||||
|
|
||||||
|
open class B : A<String>("OK")
|
||||||
|
|
||||||
|
class C : B() {
|
||||||
|
fun foo() = object : T {
|
||||||
|
val bar = x
|
||||||
|
|
||||||
|
override fun result() = bar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = C().foo().result()
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
open class Z(val s: Int) {
|
||||||
|
open fun a() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B(val x: Int) {
|
||||||
|
fun foo() {
|
||||||
|
class X : Z(x) {
|
||||||
|
|
||||||
|
}
|
||||||
|
X()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
B(1).foo()
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
import kotlin.support.*
|
||||||
|
|
||||||
|
trait Stream<T> {
|
||||||
|
fun iterator(): Iterator<T>
|
||||||
|
}
|
||||||
|
|
||||||
|
class ZippingStream<T1, T2>(val stream1: Stream<T1>, val stream2: Stream<T2>) : Stream<Pair<T1,T2>> {
|
||||||
|
override fun iterator(): Iterator<Pair<T1,T2>> = object : AbstractIterator<Pair<T1,T2>>() {
|
||||||
|
val iterator1 = stream1.iterator()
|
||||||
|
val iterator2 = stream2.iterator()
|
||||||
|
override fun computeNext() {
|
||||||
|
if (iterator1.hasNext() && iterator2.hasNext()) {
|
||||||
|
setNext(iterator1.next() to iterator2.next())
|
||||||
|
} else {
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object EmptyStream : Stream<Nothing> {
|
||||||
|
override fun iterator() = listOf<Nothing>().iterator()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
ZippingStream(EmptyStream, EmptyStream).iterator().hasNext()
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+45
-1
@@ -1384,7 +1384,7 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/closures")
|
@TestMetadata("compiler/testData/codegen/box/closures")
|
||||||
@InnerTestClasses({Closures.ClosureInsideClosure.class})
|
@InnerTestClasses({Closures.CaptureOuterProperty.class, Closures.ClosureInsideClosure.class})
|
||||||
public static class Closures extends AbstractBlackBoxCodegenTest {
|
public static class Closures extends AbstractBlackBoxCodegenTest {
|
||||||
public void testAllFilesPresentInClosures() throws Exception {
|
public void testAllFilesPresentInClosures() throws Exception {
|
||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/box/closures"), Pattern.compile("^(.+)\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/box/closures"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
@@ -1510,6 +1510,49 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest("compiler/testData/codegen/box/closures/simplestClosureAndBoxing.kt");
|
doTest("compiler/testData/codegen/box/closures/simplestClosureAndBoxing.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/box/closures/captureOuterProperty")
|
||||||
|
public static class CaptureOuterProperty extends AbstractBlackBoxCodegenTest {
|
||||||
|
public void testAllFilesPresentInCaptureOuterProperty() throws Exception {
|
||||||
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/box/closures/captureOuterProperty"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("captureFunctionInProperty.kt")
|
||||||
|
public void testCaptureFunctionInProperty() throws Exception {
|
||||||
|
doTest("compiler/testData/codegen/box/closures/captureOuterProperty/captureFunctionInProperty.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inFunction.kt")
|
||||||
|
public void testInFunction() throws Exception {
|
||||||
|
doTest("compiler/testData/codegen/box/closures/captureOuterProperty/inFunction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inProperty.kt")
|
||||||
|
public void testInProperty() throws Exception {
|
||||||
|
doTest("compiler/testData/codegen/box/closures/captureOuterProperty/inProperty.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inPropertyDeepObjectChain.kt")
|
||||||
|
public void testInPropertyDeepObjectChain() throws Exception {
|
||||||
|
doTest("compiler/testData/codegen/box/closures/captureOuterProperty/inPropertyDeepObjectChain.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inPropertyFromSuperClass.kt")
|
||||||
|
public void testInPropertyFromSuperClass() throws Exception {
|
||||||
|
doTest("compiler/testData/codegen/box/closures/captureOuterProperty/inPropertyFromSuperClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inPropertyFromSuperSuperClass.kt")
|
||||||
|
public void testInPropertyFromSuperSuperClass() throws Exception {
|
||||||
|
doTest("compiler/testData/codegen/box/closures/captureOuterProperty/inPropertyFromSuperSuperClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt4176.kt")
|
||||||
|
public void testKt4176() throws Exception {
|
||||||
|
doTest("compiler/testData/codegen/box/closures/captureOuterProperty/kt4176.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/closures/closureInsideClosure")
|
@TestMetadata("compiler/testData/codegen/box/closures/closureInsideClosure")
|
||||||
public static class ClosureInsideClosure extends AbstractBlackBoxCodegenTest {
|
public static class ClosureInsideClosure extends AbstractBlackBoxCodegenTest {
|
||||||
public void testAllFilesPresentInClosureInsideClosure() throws Exception {
|
public void testAllFilesPresentInClosureInsideClosure() throws Exception {
|
||||||
@@ -1551,6 +1594,7 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
public static Test innerSuite() {
|
public static Test innerSuite() {
|
||||||
TestSuite suite = new TestSuite("Closures");
|
TestSuite suite = new TestSuite("Closures");
|
||||||
suite.addTestSuite(Closures.class);
|
suite.addTestSuite(Closures.class);
|
||||||
|
suite.addTestSuite(CaptureOuterProperty.class);
|
||||||
suite.addTestSuite(ClosureInsideClosure.class);
|
suite.addTestSuite(ClosureInsideClosure.class);
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -1018,6 +1018,11 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
|||||||
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/regressions/kt864.kt");
|
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/regressions/kt864.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("objectCaptureOuterConstructorProperty.kt")
|
||||||
|
public void testObjectCaptureOuterConstructorProperty() throws Exception {
|
||||||
|
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/regressions/objectCaptureOuterConstructorProperty.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("referenceToSelfInLocal.kt")
|
@TestMetadata("referenceToSelfInLocal.kt")
|
||||||
public void testReferenceToSelfInLocal() throws Exception {
|
public void testReferenceToSelfInLocal() throws Exception {
|
||||||
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/regressions/referenceToSelfInLocal.kt");
|
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/regressions/referenceToSelfInLocal.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user