Use captured instance in interface companion object initializer
Similar to enum entry initialization, when we have a companion object in an interface, its constructor (or clinit) initializes its state before the instance field in corresponding interface is initialized. So, interface companion object must be accessed via a captured object reference (#0, or #0.this$0 for inner anonymous objects).
This commit is contained in:
@@ -104,6 +104,7 @@ import java.util.*;
|
||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt;
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.CodegenUtilKt.extractReificationArgument;
|
||||
import static org.jetbrains.kotlin.codegen.CodegenUtilKt.isPossiblyUninitializedSingleton;
|
||||
import static org.jetbrains.kotlin.codegen.CodegenUtilKt.unwrapInitialSignatureDescriptor;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
|
||||
@@ -1737,16 +1738,14 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
|
||||
if (isPossiblyUninitializedSingleton(classDescriptor) && isInsideSingleton(classDescriptor)) {
|
||||
return generateThisOrOuterFromContext(classDescriptor, false, false);
|
||||
}
|
||||
if (isObject(classDescriptor)) {
|
||||
return StackValue.singleton(classDescriptor, typeMapper);
|
||||
}
|
||||
if (isEnumEntry(classDescriptor)) {
|
||||
if (isInsideEnumEntry(classDescriptor)) {
|
||||
return generateThisOrOuterFromContext(classDescriptor, false, false);
|
||||
}
|
||||
else {
|
||||
return StackValue.enumEntry(classDescriptor, typeMapper);
|
||||
}
|
||||
return StackValue.enumEntry(classDescriptor, typeMapper);
|
||||
}
|
||||
ClassDescriptor companionObjectDescriptor = classDescriptor.getCompanionObjectDescriptor();
|
||||
if (companionObjectDescriptor != null) {
|
||||
@@ -2488,6 +2487,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
if (contextDescriptor instanceof FunctionDescriptor && receiverDescriptor == contextDescriptor.getContainingDeclaration()) {
|
||||
return StackValue.LOCAL_0;
|
||||
}
|
||||
else if (isPossiblyUninitializedSingleton(receiverDescriptor) && isInsideSingleton(receiverDescriptor)) {
|
||||
return generateThisOrOuterFromContext(receiverDescriptor, false, false);
|
||||
}
|
||||
else {
|
||||
return StackValue.singleton(receiverDescriptor, typeMapper);
|
||||
}
|
||||
@@ -2572,13 +2574,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
return generateThisOrOuter(calleeContainingClass, isSuper, false);
|
||||
}
|
||||
|
||||
private boolean isInsideEnumEntry(@NotNull ClassDescriptor enumEntryDescriptor) {
|
||||
assert DescriptorUtils.isEnumEntry(enumEntryDescriptor) :
|
||||
"Enum entry reference expected: " + enumEntryDescriptor;
|
||||
private boolean isInsideSingleton(@NotNull ClassDescriptor singletonClassDescriptor) {
|
||||
assert singletonClassDescriptor.getKind().isSingleton() :
|
||||
"Singleton expected: " + singletonClassDescriptor;
|
||||
|
||||
DeclarationDescriptor descriptor = context.getContextDescriptor();
|
||||
while (descriptor != null) {
|
||||
if (descriptor == enumEntryDescriptor) return true;
|
||||
if (descriptor == singletonClassDescriptor) return true;
|
||||
|
||||
if (descriptor instanceof ClassDescriptor &&
|
||||
!(((ClassDescriptor) descriptor).isInner() || DescriptorUtils.isAnonymousObject(descriptor))) {
|
||||
@@ -2593,24 +2595,23 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
@NotNull
|
||||
public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper, boolean forceOuter) {
|
||||
boolean isSingleton = calleeContainingClass.getKind().isSingleton();
|
||||
if (isSingleton) {
|
||||
if (calleeContainingClass.equals(context.getThisDescriptor()) &&
|
||||
!CodegenUtilKt.isJvmStaticInObjectOrClass(context.getFunctionDescriptor())) {
|
||||
return StackValue.local(0, typeMapper.mapType(calleeContainingClass));
|
||||
}
|
||||
else if (isEnumEntry(calleeContainingClass)) {
|
||||
if (!isInsideEnumEntry(calleeContainingClass)) {
|
||||
return StackValue.enumEntry(calleeContainingClass, typeMapper);
|
||||
}
|
||||
// else fall-through
|
||||
}
|
||||
else {
|
||||
return StackValue.singleton(calleeContainingClass, typeMapper);
|
||||
}
|
||||
if (!calleeContainingClass.getKind().isSingleton()) {
|
||||
return generateThisOrOuterFromContext(calleeContainingClass, isSuper, forceOuter);
|
||||
}
|
||||
|
||||
return generateThisOrOuterFromContext(calleeContainingClass, isSuper, forceOuter);
|
||||
if (calleeContainingClass.equals(context.getThisDescriptor()) &&
|
||||
!CodegenUtilKt.isJvmStaticInObjectOrClass(context.getFunctionDescriptor())) {
|
||||
return StackValue.local(0, typeMapper.mapType(calleeContainingClass));
|
||||
}
|
||||
else if (CodegenUtilKt.isPossiblyUninitializedSingleton(calleeContainingClass) && isInsideSingleton(calleeContainingClass)) {
|
||||
return generateThisOrOuterFromContext(calleeContainingClass, isSuper, forceOuter);
|
||||
}
|
||||
else if (isEnumEntry(calleeContainingClass)) {
|
||||
return StackValue.enumEntry(calleeContainingClass, typeMapper);
|
||||
}
|
||||
else {
|
||||
return StackValue.singleton(calleeContainingClass, typeMapper);
|
||||
}
|
||||
}
|
||||
|
||||
private StackValue generateThisOrOuterFromContext(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper, boolean forceOuter) {
|
||||
|
||||
@@ -419,4 +419,8 @@ fun ExpressionCodegen.generateCallReceiver(rangeCall: ResolvedCall<out CallableD
|
||||
generateReceiverValue(rangeCall.extensionReceiver ?: rangeCall.dispatchReceiver!!, false)
|
||||
|
||||
fun ExpressionCodegen.generateCallSingleArgument(rangeCall: ResolvedCall<out CallableDescriptor>): StackValue =
|
||||
gen(ExpressionCodegen.getSingleArgumentExpression(rangeCall)!!)
|
||||
gen(ExpressionCodegen.getSingleArgumentExpression(rangeCall)!!)
|
||||
|
||||
fun ClassDescriptor.isPossiblyUninitializedSingleton() =
|
||||
DescriptorUtils.isEnumEntry(this) ||
|
||||
DescriptorUtils.isCompanionObject(this) && DescriptorUtils.isInterface(this.containingDeclaration)
|
||||
@@ -0,0 +1,37 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
interface Test {
|
||||
companion object {
|
||||
val x = "OK"
|
||||
|
||||
val y1 = Test.x
|
||||
|
||||
val y2 = 42.let { x }
|
||||
|
||||
val y3: String
|
||||
init {
|
||||
fun localFun() = x
|
||||
y3 = localFun()
|
||||
}
|
||||
|
||||
fun method() = x
|
||||
val y4 = method()
|
||||
|
||||
val anonObject = object {
|
||||
override fun toString() = x
|
||||
}
|
||||
val y5 = anonObject.toString()
|
||||
|
||||
init {
|
||||
assertEquals(x, y1)
|
||||
assertEquals(x, y2)
|
||||
assertEquals(x, y3)
|
||||
assertEquals(x, y4)
|
||||
assertEquals(x, y5)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box() = Test.x
|
||||
+6
@@ -11846,6 +11846,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceCompanionObjectReference.kt")
|
||||
public void testInterfaceCompanionObjectReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/interfaceCompanionObjectReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt1047.kt")
|
||||
public void testKt1047() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/kt1047.kt");
|
||||
|
||||
@@ -11846,6 +11846,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceCompanionObjectReference.kt")
|
||||
public void testInterfaceCompanionObjectReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/interfaceCompanionObjectReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt1047.kt")
|
||||
public void testKt1047() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/kt1047.kt");
|
||||
|
||||
@@ -11846,6 +11846,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceCompanionObjectReference.kt")
|
||||
public void testInterfaceCompanionObjectReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/interfaceCompanionObjectReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt1047.kt")
|
||||
public void testKt1047() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/kt1047.kt");
|
||||
|
||||
@@ -13106,6 +13106,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("interfaceCompanionObjectReference.kt")
|
||||
public void testInterfaceCompanionObjectReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/interfaceCompanionObjectReference.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt1047.kt")
|
||||
public void testKt1047() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/objects/kt1047.kt");
|
||||
|
||||
Reference in New Issue
Block a user