diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index bc090964f14..840793fe7cb 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -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 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 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 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 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) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt index 9ea01adde0c..92fd6ab471b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt @@ -419,4 +419,8 @@ fun ExpressionCodegen.generateCallReceiver(rangeCall: ResolvedCall): StackValue = - gen(ExpressionCodegen.getSingleArgumentExpression(rangeCall)!!) \ No newline at end of file + gen(ExpressionCodegen.getSingleArgumentExpression(rangeCall)!!) + +fun ClassDescriptor.isPossiblyUninitializedSingleton() = + DescriptorUtils.isEnumEntry(this) || + DescriptorUtils.isCompanionObject(this) && DescriptorUtils.isInterface(this.containingDeclaration) \ No newline at end of file diff --git a/compiler/testData/codegen/box/objects/interfaceCompanionObjectReference.kt b/compiler/testData/codegen/box/objects/interfaceCompanionObjectReference.kt new file mode 100644 index 00000000000..6624b0a2bc9 --- /dev/null +++ b/compiler/testData/codegen/box/objects/interfaceCompanionObjectReference.kt @@ -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 \ No newline at end of file diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 6ccc3c9c59d..46b3138f625 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 443fe770d7d..c18b96c8887 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -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"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 754b1b27663..a76879bc4cd 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -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"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 0cc7030b0c7..1195ec59b86 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -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");