PSI2IR: Infer smart cast on dispatch receiver of FAKE_OVERRIDE calls

NB here we have use derived class type with type arguments replaced
with star-projections. This emulates JVM erasure (to some degree),
but, unfortunately, that's best we can offer here at the moment.
This commit is contained in:
Dmitry Petrov
2019-12-18 16:04:11 +03:00
parent feda832eb7
commit 09c3279cc7
8 changed files with 493 additions and 8 deletions
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.psi2ir.transformations
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrClass
@@ -38,10 +40,7 @@ import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.typeUtil.isNullableAny
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.types.typeUtil.*
fun insertImplicitCasts(element: IrElement, context: GeneratorContext) {
element.transformChildren(
@@ -77,10 +76,27 @@ open class InsertImplicitCasts(
}
private fun IrMemberAccessExpression.transformReceiverArguments(substitutedDescriptor: CallableDescriptor) {
dispatchReceiver = dispatchReceiver?.cast(substitutedDescriptor.dispatchReceiverParameter?.type)
dispatchReceiver = dispatchReceiver?.cast(getEffectiveDispatchReceiverType(substitutedDescriptor))
extensionReceiver = extensionReceiver?.cast(substitutedDescriptor.extensionReceiverParameter?.type)
}
private fun getEffectiveDispatchReceiverType(descriptor: CallableDescriptor): KotlinType? =
when {
descriptor !is CallableMemberDescriptor ->
null
descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE -> {
val containingDeclaration = descriptor.containingDeclaration
if (containingDeclaration !is ClassDescriptor)
throw AssertionError("Containing declaration for $descriptor should be a class: $containingDeclaration")
else
containingDeclaration.defaultType.replaceArgumentsWithStarProjections()
}
else ->
descriptor.dispatchReceiverParameter?.type
}
override fun visitMemberAccess(expression: IrMemberAccessExpression): IrExpression {
val substitutedDescriptor = expression.substitutedDescriptor
return expression.transformPostfix {
@@ -132,8 +148,14 @@ open class InsertImplicitCasts(
value = value.cast(expression.symbol.descriptor.type)
}
override fun visitGetField(expression: IrGetField): IrExpression =
expression.transformPostfix {
receiver = receiver?.cast(getEffectiveDispatchReceiverType(expression.symbol.descriptor))
}
override fun visitSetField(expression: IrSetField): IrExpression =
expression.transformPostfix {
receiver = receiver?.cast(getEffectiveDispatchReceiverType(expression.symbol.descriptor))
value = value.cast(expression.symbol.descriptor.type)
}