Recapture shared variables when calling local class constructor
When a local function or class A creates an instance of a local class B capturing an outer variable 'x', it should use ref for 'x', but not the value of 'x'.
This commit is contained in:
@@ -1086,11 +1086,15 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<DeclarationDescriptor, EnclosedValueDescriptor> entry : closure.getCaptureVariables().entrySet()) {
|
for (Map.Entry<DeclarationDescriptor, EnclosedValueDescriptor> entry : closure.getCaptureVariables().entrySet()) {
|
||||||
Type sharedVarType = typeMapper.getSharedVarType(entry.getKey());
|
DeclarationDescriptor declarationDescriptor = entry.getKey();
|
||||||
|
EnclosedValueDescriptor valueDescriptor = entry.getValue();
|
||||||
|
|
||||||
|
Type sharedVarType = typeMapper.getSharedVarType(declarationDescriptor);
|
||||||
|
boolean asSharedVar = sharedVarType != null;
|
||||||
if (sharedVarType == null) {
|
if (sharedVarType == null) {
|
||||||
sharedVarType = typeMapper.mapType((VariableDescriptor) entry.getKey());
|
sharedVarType = typeMapper.mapType((VariableDescriptor) declarationDescriptor);
|
||||||
}
|
}
|
||||||
StackValue capturedVar = lookupOuterValue(entry.getValue());
|
StackValue capturedVar = lookupOuterValue(valueDescriptor, asSharedVar);
|
||||||
callGenerator.putCapturedValueOnStack(capturedVar, sharedVarType, paramIndex++);
|
callGenerator.putCapturedValueOnStack(capturedVar, sharedVarType, paramIndex++);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1144,11 +1148,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public StackValue lookupOuterValue(EnclosedValueDescriptor d) {
|
private StackValue lookupOuterValue(EnclosedValueDescriptor d, boolean asSharedVar) {
|
||||||
DeclarationDescriptor descriptor = d.getDescriptor();
|
DeclarationDescriptor descriptor = d.getDescriptor();
|
||||||
for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
|
for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
|
||||||
if (aCase.isCase(descriptor)) {
|
if (aCase.isCase(descriptor)) {
|
||||||
return aCase.outerValue(d, this);
|
StackValue outerValue = aCase.outerValue(d, this);
|
||||||
|
if (asSharedVar && outerValue instanceof StackValue.FieldForSharedVar) {
|
||||||
|
StackValue.FieldForSharedVar fieldForSharedVar = (StackValue.FieldForSharedVar) outerValue;
|
||||||
|
return fieldForSharedVar.receiver;
|
||||||
|
}
|
||||||
|
return outerValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new IllegalStateException("Can't get outer value in " + this + " for " + d);
|
throw new IllegalStateException("Can't get outer value in " + this + " for " + d);
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
fun box(): String {
|
||||||
|
var x = ""
|
||||||
|
|
||||||
|
class CapturesX {
|
||||||
|
override fun toString() = x
|
||||||
|
}
|
||||||
|
|
||||||
|
fun localFun() = CapturesX()
|
||||||
|
|
||||||
|
x = "OK"
|
||||||
|
return localFun().toString()
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
fun box(): String {
|
||||||
|
var x = ""
|
||||||
|
|
||||||
|
class CapturesX {
|
||||||
|
override fun toString() = x
|
||||||
|
}
|
||||||
|
|
||||||
|
fun outerFun1(): CapturesX {
|
||||||
|
fun localFun() = CapturesX()
|
||||||
|
return localFun()
|
||||||
|
}
|
||||||
|
|
||||||
|
x = "OK"
|
||||||
|
return outerFun1().toString()
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
fun box(): String {
|
||||||
|
var x = ""
|
||||||
|
|
||||||
|
class CapturesX {
|
||||||
|
override fun toString() = x
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocalClass {
|
||||||
|
fun foo() = CapturesX()
|
||||||
|
}
|
||||||
|
|
||||||
|
x = "OK"
|
||||||
|
return LocalClass().foo().toString()
|
||||||
|
}
|
||||||
+18
@@ -11306,6 +11306,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("recaptureVarCapturedInLocalClass1.kt")
|
||||||
|
public void testRecaptureVarCapturedInLocalClass1() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/recaptureVarCapturedInLocalClass1.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("recaptureVarCapturedInLocalClass2.kt")
|
||||||
|
public void testRecaptureVarCapturedInLocalClass2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/recaptureVarCapturedInLocalClass2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("recaptureVarCapturedInLocalClass3.kt")
|
||||||
|
public void testRecaptureVarCapturedInLocalClass3() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/recaptureVarCapturedInLocalClass3.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("subclassingExtensionReceiverClass.kt")
|
@TestMetadata("subclassingExtensionReceiverClass.kt")
|
||||||
public void testSubclassingExtensionReceiverClass() throws Exception {
|
public void testSubclassingExtensionReceiverClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/subclassingExtensionReceiverClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/subclassingExtensionReceiverClass.kt");
|
||||||
|
|||||||
@@ -11306,6 +11306,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("recaptureVarCapturedInLocalClass1.kt")
|
||||||
|
public void testRecaptureVarCapturedInLocalClass1() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/recaptureVarCapturedInLocalClass1.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("recaptureVarCapturedInLocalClass2.kt")
|
||||||
|
public void testRecaptureVarCapturedInLocalClass2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/recaptureVarCapturedInLocalClass2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("recaptureVarCapturedInLocalClass3.kt")
|
||||||
|
public void testRecaptureVarCapturedInLocalClass3() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/recaptureVarCapturedInLocalClass3.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("subclassingExtensionReceiverClass.kt")
|
@TestMetadata("subclassingExtensionReceiverClass.kt")
|
||||||
public void testSubclassingExtensionReceiverClass() throws Exception {
|
public void testSubclassingExtensionReceiverClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/subclassingExtensionReceiverClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/subclassingExtensionReceiverClass.kt");
|
||||||
|
|||||||
@@ -11318,6 +11318,24 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("recaptureVarCapturedInLocalClass1.kt")
|
||||||
|
public void testRecaptureVarCapturedInLocalClass1() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/recaptureVarCapturedInLocalClass1.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("recaptureVarCapturedInLocalClass2.kt")
|
||||||
|
public void testRecaptureVarCapturedInLocalClass2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/recaptureVarCapturedInLocalClass2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("recaptureVarCapturedInLocalClass3.kt")
|
||||||
|
public void testRecaptureVarCapturedInLocalClass3() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/recaptureVarCapturedInLocalClass3.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("withclosure.kt")
|
@TestMetadata("withclosure.kt")
|
||||||
public void testWithclosure() throws Exception {
|
public void testWithclosure() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/withclosure.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/withclosure.kt");
|
||||||
|
|||||||
+18
@@ -12512,6 +12512,24 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("recaptureVarCapturedInLocalClass1.kt")
|
||||||
|
public void testRecaptureVarCapturedInLocalClass1() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/recaptureVarCapturedInLocalClass1.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("recaptureVarCapturedInLocalClass2.kt")
|
||||||
|
public void testRecaptureVarCapturedInLocalClass2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/recaptureVarCapturedInLocalClass2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("recaptureVarCapturedInLocalClass3.kt")
|
||||||
|
public void testRecaptureVarCapturedInLocalClass3() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/recaptureVarCapturedInLocalClass3.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("subclassingExtensionReceiverClass.kt")
|
@TestMetadata("subclassingExtensionReceiverClass.kt")
|
||||||
public void testSubclassingExtensionReceiverClass() throws Exception {
|
public void testSubclassingExtensionReceiverClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/subclassingExtensionReceiverClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/localClasses/subclassingExtensionReceiverClass.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user