psi2ir: handle 'this' as reference to a super companion object

In super class constructor arguments, 'this' can be resolved
as a reference to a companion object of a superclass.
This breaks an assumption in psi2ir that 'this' can only refer to some
receiver from the current scope.

If 'this' refers to an 'object' (including 'companion obejct'),
and we are not inside the corresponding class scope,
then 'this' represents a reference to a singleton instance "by name"
(represented as IrGetObjectValue).
This commit is contained in:
Dmitry Petrov
2019-01-17 13:45:28 +03:00
parent 9c8188002d
commit 202e992ae3
6 changed files with 148 additions and 19 deletions
@@ -134,14 +134,10 @@ private fun StatementGenerator.shouldGenerateReceiverAsSingletonReference(receiv
}
private fun StatementGenerator.generateThisOrSuperReceiver(receiver: ReceiverValue, classDescriptor: ClassDescriptor): IrExpression {
val expressionReceiver =
receiver as? ExpressionReceiver ?: throw AssertionError("'this' or 'super' receiver should be an expression receiver")
val expressionReceiver = receiver as? ExpressionReceiver
?: throw AssertionError("'this' or 'super' receiver should be an expression receiver")
val ktReceiver = expressionReceiver.expression
return IrGetValueImpl(
ktReceiver.startOffsetSkippingComments, ktReceiver.endOffset,
expressionReceiver.type.toIrType(),
context.symbolTable.referenceValueParameter(classDescriptor.thisAsReceiverParameter)
)
return generateThisReceiver(ktReceiver.startOffsetSkippingComments, ktReceiver.endOffset, expressionReceiver.type, classDescriptor)
}
fun StatementGenerator.generateBackingFieldReceiver(
@@ -38,6 +38,7 @@ 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.constants.CompileTimeConstant
@@ -364,28 +365,52 @@ class StatementGenerator(
override fun visitSafeQualifiedExpression(expression: KtSafeQualifiedExpression, data: Nothing?): IrStatement =
expression.selectorExpression!!.accept(this, data)
private fun isInsideClass(classDescriptor: ClassDescriptor): Boolean {
var scopeDescriptor: DeclarationDescriptor? = scopeOwner
while (scopeDescriptor != null) {
if (scopeDescriptor == classDescriptor) return true
scopeDescriptor = scopeDescriptor.containingDeclaration
}
return false
}
fun generateThisReceiver(startOffset: Int, endOffset: Int, kotlinType: KotlinType, classDescriptor: ClassDescriptor): IrExpression {
val thisAsReceiverParameter = classDescriptor.thisAsReceiverParameter
val thisType = kotlinType.toIrType()
return if (DescriptorUtils.isObject(classDescriptor) && !isInsideClass(classDescriptor)) {
IrGetObjectValueImpl(
startOffset, endOffset,
thisType,
context.symbolTable.referenceClass(classDescriptor)
)
} else {
IrGetValueImpl(
startOffset, endOffset,
thisType,
context.symbolTable.referenceValueParameter(thisAsReceiverParameter)
)
}
}
override fun visitThisExpression(expression: KtThisExpression, data: Nothing?): IrExpression {
val referenceTarget = getOrFail(BindingContext.REFERENCE_TARGET, expression.instanceReference) { "No reference target for this" }
val startOffset = expression.startOffsetSkippingComments
val endOffset = expression.endOffset
return when (referenceTarget) {
is ClassDescriptor -> {
val thisAsReceiverParameter = referenceTarget.thisAsReceiverParameter
val thisType = thisAsReceiverParameter.type.toIrType()
IrGetValueImpl(
expression.startOffsetSkippingComments, expression.endOffset,
thisType,
context.symbolTable.referenceValueParameter(thisAsReceiverParameter)
)
}
is ClassDescriptor ->
generateThisReceiver(startOffset, endOffset, referenceTarget.thisAsReceiverParameter.type, referenceTarget)
is CallableDescriptor -> {
val extensionReceiver = referenceTarget.extensionReceiverParameter ?: TODO("No extension receiver: $referenceTarget")
val extensionReceiverType = extensionReceiver.type.toIrType()
IrGetValueImpl(
expression.startOffsetSkippingComments, expression.endOffset,
startOffset, endOffset,
extensionReceiverType,
context.symbolTable.referenceValueParameter(extensionReceiver)
)
}
else ->
error("Expected this or receiver: $referenceTarget")
}