Wrong receiver is generated for variable-as-function call on object.
Move 'generateExpressionForReferencedDescriptor' to CallGenerator, use it in 'generateCall', add PSI-free versions of some utility methods so that call elements can be generated when we're already deep in ResolvedCall generation and have forgotten about PSI.
This commit is contained in:
+11
-11
@@ -41,9 +41,12 @@ import java.lang.AssertionError
|
||||
fun StatementGenerator.generateReceiverOrNull(ktDefaultElement: KtElement, receiver: ReceiverValue?): IntermediateValue? =
|
||||
receiver?.let { generateReceiver(ktDefaultElement, receiver) }
|
||||
|
||||
fun StatementGenerator.generateReceiver(ktDefaultElement: KtElement, receiver: ReceiverValue): IntermediateValue {
|
||||
fun StatementGenerator.generateReceiver(ktDefaultElement: KtElement, receiver: ReceiverValue): IntermediateValue =
|
||||
generateReceiver(ktDefaultElement.startOffset, ktDefaultElement.endOffset, receiver)
|
||||
|
||||
fun StatementGenerator.generateReceiver(startOffset: Int, endOffset: Int, receiver: ReceiverValue): IntermediateValue {
|
||||
if (receiver is TransientReceiver) {
|
||||
return TransientReceiverValue(ktDefaultElement.text, receiver.type)
|
||||
return TransientReceiverValue(receiver.type)
|
||||
}
|
||||
|
||||
val receiverExpression = when (receiver) {
|
||||
@@ -51,11 +54,10 @@ fun StatementGenerator.generateReceiver(ktDefaultElement: KtElement, receiver: R
|
||||
if (receiver.classDescriptor.kind.isSingleton &&
|
||||
this.scopeOwner != receiver.classDescriptor && //For anonymous initializers
|
||||
this.scopeOwner.containingDeclaration != receiver.classDescriptor) {
|
||||
IrGetObjectValueImpl(ktDefaultElement.startOffset, ktDefaultElement.endOffset, receiver.type,
|
||||
receiver.classDescriptor)
|
||||
IrGetObjectValueImpl(startOffset, endOffset, receiver.type, receiver.classDescriptor)
|
||||
}
|
||||
else {
|
||||
IrGetValueImpl(ktDefaultElement.startOffset, ktDefaultElement.endOffset, receiver.classDescriptor.thisAsReceiverParameter)
|
||||
IrGetValueImpl(startOffset, endOffset, receiver.classDescriptor.thisAsReceiverParameter)
|
||||
}
|
||||
}
|
||||
is ThisClassReceiver ->
|
||||
@@ -68,8 +70,7 @@ fun StatementGenerator.generateReceiver(ktDefaultElement: KtElement, receiver: R
|
||||
IrGetObjectValueImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type,
|
||||
receiver.classQualifier.descriptor as ClassDescriptor)
|
||||
is ExtensionReceiver ->
|
||||
IrGetValueImpl(ktDefaultElement.startOffset, ktDefaultElement.startOffset,
|
||||
receiver.declarationDescriptor.extensionReceiverParameter!!)
|
||||
IrGetValueImpl(startOffset, startOffset, receiver.declarationDescriptor.extensionReceiverParameter!!)
|
||||
else ->
|
||||
TODO("Receiver: ${receiver.javaClass.simpleName}")
|
||||
}
|
||||
@@ -88,14 +89,13 @@ private fun generateThisOrSuperReceiver(receiver: ReceiverValue, classDescriptor
|
||||
}
|
||||
|
||||
fun StatementGenerator.generateBackingFieldReceiver(
|
||||
ktDefaultElement: KtElement,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
resolvedCall: ResolvedCall<*>?,
|
||||
fieldDescriptor: SyntheticFieldDescriptor
|
||||
): IntermediateValue? {
|
||||
|
||||
val receiver = resolvedCall?.dispatchReceiver ?: fieldDescriptor.getDispatchReceiverForBackend() ?: return null
|
||||
|
||||
return this.generateReceiver(ktDefaultElement, receiver)
|
||||
return this.generateReceiver(startOffset, endOffset, receiver)
|
||||
}
|
||||
|
||||
fun StatementGenerator.generateCallReceiver(
|
||||
|
||||
+2
-5
@@ -108,11 +108,8 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
|
||||
|
||||
return when (descriptor) {
|
||||
is SyntheticFieldDescriptor -> {
|
||||
val receiverValue = statementGenerator.generateBackingFieldReceiver(ktLeft, resolvedCall, descriptor)
|
||||
|
||||
BackingFieldLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor.propertyDescriptor,
|
||||
receiverValue, origin)
|
||||
|
||||
val receiverValue = statementGenerator.generateBackingFieldReceiver(ktLeft.startOffset, ktLeft.endOffset, resolvedCall, descriptor)
|
||||
BackingFieldLValue(ktLeft.startOffset, ktLeft.endOffset, descriptor.propertyDescriptor, receiverValue, origin)
|
||||
}
|
||||
is LocalVariableDescriptor ->
|
||||
@Suppress("DEPRECATION")
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
@@ -26,8 +27,12 @@ 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.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import java.util.*
|
||||
|
||||
@@ -38,21 +43,61 @@ class CallGenerator(statementGenerator: StatementGenerator): StatementGeneratorE
|
||||
return when (descriptor) {
|
||||
is PropertyDescriptor ->
|
||||
generatePropertyGetterCall(descriptor, startOffset, endOffset, call)
|
||||
is VariableDescriptor ->
|
||||
call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
generateGetVariable(startOffset, endOffset, descriptor, getTypeArguments(call.original), origin)
|
||||
}
|
||||
is FunctionDescriptor ->
|
||||
generateFunctionCall(descriptor, startOffset, endOffset, origin, call)
|
||||
else ->
|
||||
TODO("Unexpected callable descriptor: $descriptor ${descriptor.javaClass.simpleName}")
|
||||
call.callReceiver.call { _, _ ->
|
||||
generateValueReference(startOffset, endOffset, descriptor, call.original, origin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun generateGetVariable(startOffset: Int, endOffset: Int,
|
||||
descriptor: VariableDescriptor,
|
||||
typeArguments: Map<TypeParameterDescriptor, KotlinType>?,
|
||||
origin: IrStatementOrigin? = null) =
|
||||
fun generateValueReference(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
descriptor: DeclarationDescriptor,
|
||||
resolvedCall: ResolvedCall<*>?,
|
||||
origin: IrStatementOrigin?
|
||||
): IrExpression =
|
||||
when (descriptor) {
|
||||
is FakeCallableDescriptorForObject ->
|
||||
generateValueReference(startOffset, endOffset, descriptor.getReferencedDescriptor(), resolvedCall, origin)
|
||||
is TypeAliasDescriptor ->
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
is PropertyDescriptor -> {
|
||||
generateCall(startOffset, endOffset, statementGenerator.pregenerateCall(resolvedCall!!))
|
||||
}
|
||||
is SyntheticFieldDescriptor -> {
|
||||
val receiver = statementGenerator.generateBackingFieldReceiver(startOffset, endOffset, resolvedCall, descriptor)
|
||||
IrGetFieldImpl(startOffset, endOffset, descriptor.propertyDescriptor, receiver?.load())
|
||||
}
|
||||
is VariableDescriptor ->
|
||||
generateGetVariable(startOffset, endOffset, descriptor, getTypeArguments(resolvedCall), origin)
|
||||
else ->
|
||||
TODO("Unexpected callable descriptor: $descriptor ${descriptor.javaClass.simpleName}")
|
||||
}
|
||||
|
||||
private fun generateGetVariable(
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
descriptor: VariableDescriptor,
|
||||
typeArguments: Map<TypeParameterDescriptor, KotlinType>?,
|
||||
origin: IrStatementOrigin? = null
|
||||
) =
|
||||
@Suppress("DEPRECATION")
|
||||
if (descriptor is LocalVariableDescriptor && descriptor.isDelegated)
|
||||
IrCallImpl(startOffset, endOffset, descriptor.type, descriptor.getter!!, typeArguments, origin ?: IrStatementOrigin.GET_LOCAL_PROPERTY)
|
||||
|
||||
+8
-39
@@ -16,8 +16,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.assertCast
|
||||
import org.jetbrains.kotlin.ir.builders.Scope
|
||||
@@ -35,13 +37,10 @@ import org.jetbrains.kotlin.psi2ir.intermediate.createTemporaryVariableInBlock
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||
import org.jetbrains.kotlin.resolve.constants.*
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
import java.lang.AssertionError
|
||||
|
||||
@@ -262,40 +261,10 @@ class StatementGenerator(
|
||||
expression: KtExpression,
|
||||
resolvedCall: ResolvedCall<*>?
|
||||
): IrExpression =
|
||||
when (descriptor) {
|
||||
is FakeCallableDescriptorForObject ->
|
||||
generateExpressionForReferencedDescriptor(descriptor.getReferencedDescriptor(), expression, resolvedCall)
|
||||
is TypeAliasDescriptor ->
|
||||
generateExpressionForReferencedDescriptor(descriptor.classDescriptor!!, expression, null)
|
||||
is ClassDescriptor -> {
|
||||
val classValueType = descriptor.classValueType!!
|
||||
when {
|
||||
DescriptorUtils.isObject(descriptor) ->
|
||||
IrGetObjectValueImpl(expression.startOffset, expression.endOffset, classValueType, descriptor)
|
||||
DescriptorUtils.isEnumEntry(descriptor) ->
|
||||
IrGetEnumValueImpl(expression.startOffset, expression.endOffset, classValueType, descriptor)
|
||||
else -> {
|
||||
IrGetObjectValueImpl(expression.startOffset, expression.endOffset, classValueType,
|
||||
descriptor.companionObjectDescriptor ?: throw AssertionError("Class value without companion object: $descriptor"))
|
||||
}
|
||||
}
|
||||
}
|
||||
is PropertyDescriptor -> {
|
||||
CallGenerator(this).generateCall(expression.startOffset, expression.endOffset, pregenerateCall(resolvedCall!!))
|
||||
}
|
||||
is SyntheticFieldDescriptor -> {
|
||||
val receiver = generateBackingFieldReceiver(expression, resolvedCall, descriptor)
|
||||
IrGetFieldImpl(expression.startOffset, expression.endOffset, descriptor.propertyDescriptor, receiver?.load())
|
||||
}
|
||||
is VariableDescriptor ->
|
||||
CallGenerator(this).generateGetVariable(expression.startOffset, expression.endOffset, descriptor,
|
||||
getTypeArguments(resolvedCall))
|
||||
else ->
|
||||
IrErrorExpressionImpl(
|
||||
expression.startOffset, expression.endOffset, getInferredTypeWithImplicitCastsOrFail(expression),
|
||||
expression.text + ": ${descriptor.name} ${descriptor.javaClass.simpleName}"
|
||||
)
|
||||
}
|
||||
CallGenerator(this).generateValueReference(
|
||||
expression.startOffset, expression.endOffset,
|
||||
descriptor, resolvedCall, null
|
||||
)
|
||||
|
||||
override fun visitCallExpression(expression: KtCallExpression, data: Nothing?): IrStatement {
|
||||
val resolvedCall = getResolvedCall(expression) ?:
|
||||
|
||||
+2
-2
@@ -19,8 +19,8 @@ package org.jetbrains.kotlin.psi2ir.intermediate
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class TransientReceiverValue(val description: String, override val type: KotlinType): IntermediateValue {
|
||||
class TransientReceiverValue(override val type: KotlinType): IntermediateValue {
|
||||
override fun load(): IrExpression {
|
||||
throw AssertionError("Transient receiver should not be instantiated: $description")
|
||||
throw AssertionError("Transient receiver should not be instantiated")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
object A
|
||||
|
||||
enum class En { X }
|
||||
|
||||
operator fun A.invoke(i: Int) = i
|
||||
operator fun En.invoke(i: Int) = i
|
||||
|
||||
val test1 = A(42)
|
||||
val test2 = En.X(42)
|
||||
@@ -0,0 +1,45 @@
|
||||
FILE /objectAsCallable.kt
|
||||
CLASS OBJECT A
|
||||
CONSTRUCTOR private constructor A()
|
||||
BLOCK_BODY
|
||||
DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='A'
|
||||
CLASS ENUM_CLASS En
|
||||
CONSTRUCTOR private constructor En()
|
||||
BLOCK_BODY
|
||||
ENUM_CONSTRUCTOR_CALL 'constructor Enum(String, Int)'
|
||||
INSTANCE_INITIALIZER_CALL classDescriptor='En'
|
||||
ENUM_ENTRY enum entry X
|
||||
init: ENUM_CONSTRUCTOR_CALL 'constructor En()'
|
||||
FUN ENUM_CLASS_SPECIAL_MEMBER public final fun values(): kotlin.Array<En>
|
||||
SYNTHETIC_BODY kind=ENUM_VALUES
|
||||
FUN ENUM_CLASS_SPECIAL_MEMBER public final fun valueOf(value: kotlin.String): En
|
||||
SYNTHETIC_BODY kind=ENUM_VALUEOF
|
||||
FUN public operator fun A.invoke(i: kotlin.Int): kotlin.Int
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='invoke(Int) on A: Int'
|
||||
GET_VAR 'value-parameter i: Int' type=kotlin.Int origin=null
|
||||
FUN public operator fun En.invoke(i: kotlin.Int): kotlin.Int
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='invoke(Int) on En: Int'
|
||||
GET_VAR 'value-parameter i: Int' type=kotlin.Int origin=null
|
||||
PROPERTY public val test1: kotlin.Int
|
||||
FIELD PROPERTY_BACKING_FIELD public val test1: kotlin.Int
|
||||
EXPRESSION_BODY
|
||||
CALL 'invoke(Int) on A: Int' type=kotlin.Int origin=INVOKE
|
||||
$receiver: GET_OBJECT 'A' type=A
|
||||
i: CONST Int type=kotlin.Int value='42'
|
||||
FUN DEFAULT_PROPERTY_ACCESSOR public fun <get-test1>(): kotlin.Int
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='<get-test1>(): Int'
|
||||
GET_FIELD 'test1: Int' type=kotlin.Int origin=null
|
||||
PROPERTY public val test2: kotlin.Int
|
||||
FIELD PROPERTY_BACKING_FIELD public val test2: kotlin.Int
|
||||
EXPRESSION_BODY
|
||||
CALL 'invoke(Int) on En: Int' type=kotlin.Int origin=INVOKE
|
||||
$receiver: GET_ENUM 'X' type=En
|
||||
i: CONST Int type=kotlin.Int value='42'
|
||||
FUN DEFAULT_PROPERTY_ACCESSOR public fun <get-test2>(): kotlin.Int
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='<get-test2>(): Int'
|
||||
GET_FIELD 'test2: Int' type=kotlin.Int origin=null
|
||||
@@ -590,6 +590,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("objectAsCallable.kt")
|
||||
public void testObjectAsCallable() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/objectAsCallable.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("objectClassReference.kt")
|
||||
public void testObjectClassReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/objectClassReference.kt");
|
||||
|
||||
Reference in New Issue
Block a user