References to enum entries should be always generated as GET_ENUM
This commit is contained in:
+27
-12
@@ -22,17 +22,16 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
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.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionWithCopy
|
import org.jetbrains.kotlin.ir.expressions.IrExpressionWithCopy
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
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.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
import org.jetbrains.kotlin.psi2ir.intermediate.*
|
import org.jetbrains.kotlin.psi2ir.intermediate.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
|
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getSuperCallExpression
|
import org.jetbrains.kotlin.resolve.calls.callResolverUtil.getSuperCallExpression
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||||
@@ -54,14 +53,11 @@ fun StatementGenerator.generateReceiver(startOffset: Int, endOffset: Int, receiv
|
|||||||
|
|
||||||
val receiverExpression = when (receiver) {
|
val receiverExpression = when (receiver) {
|
||||||
is ImplicitClassReceiver -> {
|
is ImplicitClassReceiver -> {
|
||||||
if (receiver.classDescriptor.kind.isSingleton &&
|
val receiverClassDescriptor = receiver.classDescriptor
|
||||||
this.scopeOwner != receiver.classDescriptor && //For anonymous initializers
|
if (shouldGenerateReceiverAsSingletonReference(receiverClassDescriptor))
|
||||||
this.scopeOwner.containingDeclaration != receiver.classDescriptor) {
|
generateSingletonReference(receiverClassDescriptor, startOffset, endOffset, receiver.type)
|
||||||
IrGetObjectValueImpl(startOffset, endOffset, receiver.type, receiver.classDescriptor)
|
else
|
||||||
}
|
IrGetValueImpl(startOffset, endOffset, receiverClassDescriptor.thisAsReceiverParameter)
|
||||||
else {
|
|
||||||
IrGetValueImpl(startOffset, endOffset, receiver.classDescriptor.thisAsReceiverParameter)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is ThisClassReceiver ->
|
is ThisClassReceiver ->
|
||||||
generateThisOrSuperReceiver(receiver, receiver.classDescriptor)
|
generateThisOrSuperReceiver(receiver, receiver.classDescriptor)
|
||||||
@@ -84,6 +80,25 @@ fun StatementGenerator.generateReceiver(startOffset: Int, endOffset: Int, receiv
|
|||||||
OnceExpressionValue(receiverExpression)
|
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 {
|
private fun generateThisOrSuperReceiver(receiver: ReceiverValue, classDescriptor: ClassDescriptor): IrExpression {
|
||||||
val expressionReceiver = receiver as? ExpressionReceiver ?:
|
val expressionReceiver = receiver as? ExpressionReceiver ?:
|
||||||
throw AssertionError("'this' or 'super' receiver should be an expression receiver")
|
throw AssertionError("'this' or 'super' receiver should be an expression receiver")
|
||||||
|
|||||||
@@ -66,17 +66,7 @@ class CallGenerator(statementGenerator: StatementGenerator): StatementGeneratorE
|
|||||||
generateValueReference(startOffset, endOffset, descriptor.classDescriptor!!, null, origin)
|
generateValueReference(startOffset, endOffset, descriptor.classDescriptor!!, null, origin)
|
||||||
is ClassDescriptor -> {
|
is ClassDescriptor -> {
|
||||||
val classValueType = descriptor.classValueType!!
|
val classValueType = descriptor.classValueType!!
|
||||||
when {
|
generateSingletonReference(descriptor, startOffset, endOffset, classValueType)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is PropertyDescriptor -> {
|
is PropertyDescriptor -> {
|
||||||
generateCall(startOffset, endOffset, statementGenerator.pregenerateCall(resolvedCall!!))
|
generateCall(startOffset, endOffset, statementGenerator.pregenerateCall(resolvedCall!!))
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
@@ -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 <get-value2>(): kotlin.String
|
||||||
|
BLOCK_BODY
|
||||||
|
RETURN type=kotlin.Nothing from='<get-value2>(): String'
|
||||||
|
GET_FIELD 'value2: String' type=kotlin.String origin=null
|
||||||
|
receiver: GET_VAR '<receiver: B>' 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 <anonymous>(): kotlin.String
|
||||||
|
BLOCK_BODY
|
||||||
|
RETURN type=kotlin.Nothing from='<anonymous>(): String'
|
||||||
|
CALL '<get-value2>(): String' type=kotlin.String origin=GET_PROPERTY
|
||||||
|
$this: GET_ENUM 'B' type=X.B
|
||||||
|
CALLABLE_REFERENCE '<anonymous>(): String' type=() -> kotlin.String origin=LAMBDA
|
||||||
|
FUN DEFAULT_PROPERTY_ACCESSOR public open override fun <get-value>(): () -> kotlin.String
|
||||||
|
BLOCK_BODY
|
||||||
|
RETURN type=kotlin.Nothing from='<get-value>(): () -> String'
|
||||||
|
GET_FIELD 'value: () -> String' type=() -> kotlin.String origin=null
|
||||||
|
receiver: GET_VAR '<receiver: B>' type=X.B origin=null
|
||||||
|
PROPERTY public abstract val value: () -> kotlin.String
|
||||||
|
FUN DEFAULT_PROPERTY_ACCESSOR public abstract fun <get-value>(): () -> kotlin.String
|
||||||
|
BLOCK_BODY
|
||||||
|
RETURN type=kotlin.Nothing from='<get-value>(): () -> String'
|
||||||
|
GET_FIELD 'value: () -> String' type=() -> kotlin.String origin=null
|
||||||
|
receiver: GET_VAR '<receiver: X>' type=X origin=null
|
||||||
|
FUN ENUM_CLASS_SPECIAL_MEMBER public final fun values(): kotlin.Array<X>
|
||||||
|
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 '<get-value>(): () -> String' type=() -> kotlin.String origin=GET_PROPERTY
|
||||||
|
$this: GET_ENUM 'B' type=X
|
||||||
+1
-1
@@ -21,7 +21,7 @@ FILE /enumEntry.kt
|
|||||||
FUN public final fun test2(): kotlin.Unit
|
FUN public final fun test2(): kotlin.Unit
|
||||||
BLOCK_BODY
|
BLOCK_BODY
|
||||||
CALL 'test(): Unit' type=kotlin.Unit origin=null
|
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<Z>
|
FUN ENUM_CLASS_SPECIAL_MEMBER public final fun values(): kotlin.Array<Z>
|
||||||
SYNTHETIC_BODY kind=ENUM_VALUES
|
SYNTHETIC_BODY kind=ENUM_VALUES
|
||||||
FUN ENUM_CLASS_SPECIAL_MEMBER public final fun valueOf(value: kotlin.String): Z
|
FUN ENUM_CLASS_SPECIAL_MEMBER public final fun valueOf(value: kotlin.String): Z
|
||||||
|
|||||||
@@ -524,6 +524,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("equality.kt")
|
||||||
public void testEquality() throws Exception {
|
public void testEquality() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/equality.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/equality.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user