diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt index 2c2b29aa9a7..63b125f197e 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt @@ -22,17 +22,16 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor +import org.jetbrains.kotlin.ir.expressions.IrDeclarationReference import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpressionWithCopy -import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrSpreadElementImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl +import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi2ir.intermediate.* import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getSuperCallExpression import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall @@ -54,14 +53,11 @@ fun StatementGenerator.generateReceiver(startOffset: Int, endOffset: Int, receiv val receiverExpression = when (receiver) { is ImplicitClassReceiver -> { - if (receiver.classDescriptor.kind.isSingleton && - this.scopeOwner != receiver.classDescriptor && //For anonymous initializers - this.scopeOwner.containingDeclaration != receiver.classDescriptor) { - IrGetObjectValueImpl(startOffset, endOffset, receiver.type, receiver.classDescriptor) - } - else { - IrGetValueImpl(startOffset, endOffset, receiver.classDescriptor.thisAsReceiverParameter) - } + val receiverClassDescriptor = receiver.classDescriptor + if (shouldGenerateReceiverAsSingletonReference(receiverClassDescriptor)) + generateSingletonReference(receiverClassDescriptor, startOffset, endOffset, receiver.type) + else + IrGetValueImpl(startOffset, endOffset, receiverClassDescriptor.thisAsReceiverParameter) } is ThisClassReceiver -> generateThisOrSuperReceiver(receiver, receiver.classDescriptor) @@ -84,6 +80,25 @@ fun StatementGenerator.generateReceiver(startOffset: Int, endOffset: Int, receiv OnceExpressionValue(receiverExpression) } +fun generateSingletonReference(descriptor: ClassDescriptor, startOffset: Int, endOffset: Int, type: KotlinType): IrDeclarationReference = + when { + DescriptorUtils.isObject(descriptor) -> + IrGetObjectValueImpl(startOffset, endOffset, type, descriptor) + DescriptorUtils.isEnumEntry(descriptor) -> + IrGetEnumValueImpl(startOffset, endOffset, type, descriptor) + else -> { + val companionObjectDescriptor = descriptor.companionObjectDescriptor + ?: throw java.lang.AssertionError("Class value without companion object: $descriptor") + IrGetObjectValueImpl(startOffset, endOffset, type, companionObjectDescriptor) + } + } + +private fun StatementGenerator.shouldGenerateReceiverAsSingletonReference(receiverClassDescriptor: ClassDescriptor): Boolean { + return receiverClassDescriptor.kind.isSingleton && + this.scopeOwner != receiverClassDescriptor && //For anonymous initializers + this.scopeOwner.containingDeclaration != receiverClassDescriptor +} + private fun generateThisOrSuperReceiver(receiver: ReceiverValue, classDescriptor: ClassDescriptor): IrExpression { val expressionReceiver = receiver as? ExpressionReceiver ?: throw AssertionError("'this' or 'super' receiver should be an expression receiver") diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt index 62f2a0c602a..7cc709f519d 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt @@ -66,17 +66,7 @@ class CallGenerator(statementGenerator: StatementGenerator): StatementGeneratorE generateValueReference(startOffset, endOffset, descriptor.classDescriptor!!, null, origin) is ClassDescriptor -> { val classValueType = descriptor.classValueType!! - when { - DescriptorUtils.isObject(descriptor) -> - IrGetObjectValueImpl(startOffset, endOffset, classValueType, descriptor) - DescriptorUtils.isEnumEntry(descriptor) -> - IrGetEnumValueImpl(startOffset, endOffset, classValueType, descriptor) - else -> { - val companionObjectDescriptor = descriptor.companionObjectDescriptor - ?: throw java.lang.AssertionError("Class value without companion object: $descriptor") - IrGetObjectValueImpl(startOffset, endOffset, classValueType, companionObjectDescriptor) - } - } + generateSingletonReference(descriptor, startOffset, endOffset, classValueType) } is PropertyDescriptor -> { generateCall(startOffset, endOffset, statementGenerator.pregenerateCall(resolvedCall!!)) diff --git a/compiler/testData/ir/irText/expressions/enumEntryAsReceiver.kt b/compiler/testData/ir/irText/expressions/enumEntryAsReceiver.kt new file mode 100644 index 00000000000..096316ed24b --- /dev/null +++ b/compiler/testData/ir/irText/expressions/enumEntryAsReceiver.kt @@ -0,0 +1,13 @@ +enum class X { + + B { + val value2 = "OK" + override val value = { value2 } + }; + + abstract val value: () -> String +} + +fun box(): String { + return X.B.value() +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/enumEntryAsReceiver.txt b/compiler/testData/ir/irText/expressions/enumEntryAsReceiver.txt new file mode 100644 index 00000000000..fdf7fcac547 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/enumEntryAsReceiver.txt @@ -0,0 +1,53 @@ +FILE /enumEntryAsReceiver.kt + CLASS ENUM_CLASS X + CONSTRUCTOR private constructor X() + BLOCK_BODY + ENUM_CONSTRUCTOR_CALL 'constructor Enum(String, Int)' + INSTANCE_INITIALIZER_CALL classDescriptor='X' + ENUM_ENTRY enum entry B + init: ENUM_CONSTRUCTOR_CALL 'constructor B()' + class: CLASS ENUM_ENTRY B + CONSTRUCTOR private constructor B() + BLOCK_BODY + ENUM_CONSTRUCTOR_CALL 'constructor X()' + INSTANCE_INITIALIZER_CALL classDescriptor='B' + PROPERTY public final val value2: kotlin.String = "OK" + FIELD PROPERTY_BACKING_FIELD public final val value2: kotlin.String = "OK" + EXPRESSION_BODY + CONST String type=kotlin.String value='OK' + FUN DEFAULT_PROPERTY_ACCESSOR public final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + GET_FIELD 'value2: String' type=kotlin.String origin=null + receiver: GET_VAR '' type=X.B origin=null + PROPERTY public open override val value: () -> kotlin.String + FIELD PROPERTY_BACKING_FIELD public open override val value: () -> kotlin.String + EXPRESSION_BODY + BLOCK type=() -> kotlin.String origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA local final fun (): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): String' + CALL '(): String' type=kotlin.String origin=GET_PROPERTY + $this: GET_ENUM 'B' type=X.B + CALLABLE_REFERENCE '(): String' type=() -> kotlin.String origin=LAMBDA + FUN DEFAULT_PROPERTY_ACCESSOR public open override fun (): () -> kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): () -> String' + GET_FIELD 'value: () -> String' type=() -> kotlin.String origin=null + receiver: GET_VAR '' type=X.B origin=null + PROPERTY public abstract val value: () -> kotlin.String + FUN DEFAULT_PROPERTY_ACCESSOR public abstract fun (): () -> kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='(): () -> String' + GET_FIELD 'value: () -> String' type=() -> kotlin.String origin=null + receiver: GET_VAR '' type=X origin=null + FUN ENUM_CLASS_SPECIAL_MEMBER public final fun values(): kotlin.Array + SYNTHETIC_BODY kind=ENUM_VALUES + FUN ENUM_CLASS_SPECIAL_MEMBER public final fun valueOf(value: kotlin.String): X + SYNTHETIC_BODY kind=ENUM_VALUEOF + FUN public fun box(): kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='box(): String' + CALL 'invoke(): String' type=kotlin.String origin=INVOKE + $this: CALL '(): () -> String' type=() -> kotlin.String origin=GET_PROPERTY + $this: GET_ENUM 'B' type=X diff --git a/compiler/testData/ir/irText/singletons/enumEntry.txt b/compiler/testData/ir/irText/singletons/enumEntry.txt index 47c4458069b..777d911f482 100644 --- a/compiler/testData/ir/irText/singletons/enumEntry.txt +++ b/compiler/testData/ir/irText/singletons/enumEntry.txt @@ -21,7 +21,7 @@ FILE /enumEntry.kt FUN public final fun test2(): kotlin.Unit BLOCK_BODY CALL 'test(): Unit' type=kotlin.Unit origin=null - $this: GET_OBJECT 'ENTRY' type=Z.ENTRY + $this: GET_ENUM 'ENTRY' type=Z.ENTRY FUN ENUM_CLASS_SPECIAL_MEMBER public final fun values(): kotlin.Array SYNTHETIC_BODY kind=ENUM_VALUES FUN ENUM_CLASS_SPECIAL_MEMBER public final fun valueOf(value: kotlin.String): Z diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 6a249e40f2c..df532121ee2 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -524,6 +524,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("enumEntryAsReceiver.kt") + public void testEnumEntryAsReceiver() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/enumEntryAsReceiver.kt"); + doTest(fileName); + } + @TestMetadata("equality.kt") public void testEquality() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/equality.kt");