Make InsertImplicitCasts work with Descriptors and KotlinTypes again

This is a temporary change to make sure IrType infrastructure work is in
master.

It causes some of irText tests to work incorrectly (as in master).
This commit is contained in:
Dmitry Petrov
2019-06-24 16:48:59 +03:00
parent 8da5f6b955
commit b3b7e26985
31 changed files with 464 additions and 399 deletions
@@ -65,11 +65,18 @@ class Psi2IrTranslator(
): GeneratorContext =
GeneratorContext(configuration, moduleDescriptor, bindingContext, languageVersionSettings, symbolTable, extensions)
fun generateModuleFragment(context: GeneratorContext, ktFiles: Collection<KtFile>, deserializer: IrDeserializer? = null): IrModuleFragment {
fun generateModuleFragment(
context: GeneratorContext,
ktFiles: Collection<KtFile>,
deserializer: IrDeserializer? = null
): IrModuleFragment {
val moduleGenerator = ModuleGenerator(context)
val irModule = moduleGenerator.generateModuleFragmentWithoutDependencies(ktFiles)
// This is required for implicit casts insertion on IrTypes (work-in-progress).
moduleGenerator.generateUnboundSymbolsAsDependencies(irModule, deserializer)
irModule.patchDeclarationParents()
postprocess(context, irModule)
moduleGenerator.generateUnboundSymbolsAsDependencies(irModule, deserializer)
return irModule
@@ -16,168 +16,67 @@
package org.jetbrains.kotlin.psi2ir.transformations
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.makeTypeIntersection
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
import org.jetbrains.kotlin.ir.util.TypeTranslator
import org.jetbrains.kotlin.ir.util.coerceToUnitIfNeeded
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.psi2ir.containsNull
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.types.isNullabilityFlexible
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
fun insertImplicitCasts(element: IrElement, context: GeneratorContext) {
element.transformChildren(
InsertImplicitCasts(context.irBuiltIns, context.typeTranslator),
InsertImplicitCasts(context.builtIns, context.irBuiltIns, context.typeTranslator, context.extensions.samConversion),
null
)
}
open class InsertImplicitCasts(
private val builtIns: KotlinBuiltIns,
private val irBuiltIns: IrBuiltIns,
private val typeTranslator: TypeTranslator
private val typeTranslator: TypeTranslator,
private val samConversion: GeneratorExtensions.SamConversion
) : IrElementTransformerVoid() {
private fun getDeclarationTypeParameters(declaration: IrFunction): List<IrTypeParameterSymbol> {
return (declaration.typeParameters + if (declaration is IrConstructor) declaration.parentAsClass.typeParameters else emptyList())
.map { it.symbol }
}
private fun KotlinType.toIrType() = typeTranslator.translateType(this)
private fun getDispatchReceiverTypeParameters(declaration: IrDeclaration): List<IrTypeParameterSymbol> {
val classWithTypeParameters =
if (declaration.isNonStaticMemberDeclaration())
declaration.parentAsClass
else
return emptyList()
return extractTypeParameters(classWithTypeParameters).map { it.symbol }
}
private fun IrDeclaration.isNonStaticMemberDeclaration() =
this is IrFunction && dispatchReceiverParameter != null ||
this is IrField && !isStatic
private fun getTypeArguments(
expression: IrExpression,
declarationTypeParameters: List<IrTypeParameterSymbol>
): List<IrTypeArgument> =
when (expression) {
is IrMemberAccessExpression -> {
val expressionTypeArguments = declarationTypeParameters.map { p ->
makeTypeProjection(expression.getTypeArgument(p.owner.index)!!, p.owner.variance)
}
val receiverTypeArguments = expression.dispatchReceiver.getTypeArgumentsForReceiver()
expressionTypeArguments + receiverTypeArguments
}
is IrFieldAccessExpression -> {
expression.receiver.getTypeArgumentsForReceiver()
}
else -> {
throw AssertionError("Unexpected expression: ${expression.render()}")
}
}
private fun IrExpression?.getTypeArgumentsForReceiver(): List<IrTypeArgument> {
if (this == null) return emptyList()
val expressionType = type as? IrSimpleType ?: return emptyList()
return expressionType.arguments
}
private fun IrType.substitute(typeParameters: List<IrTypeParameterSymbol>, typeArguments: List<IrTypeArgument>): IrType =
IrTypeSubstitutor(typeParameters.distinct(), typeArguments, irBuiltIns).substitute(this)
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression =
override fun visitCallableReference(expression: IrCallableReference): IrExpression =
expression.transformPostfix {
val declaration = symbol.owner
val declarationTypeParameters = getDeclarationTypeParameters(declaration)
val dispatchReceiverTypeParameters = getDispatchReceiverTypeParameters(declaration)
val typeParameters = declarationTypeParameters + dispatchReceiverTypeParameters
val typeArguments = getTypeArguments(expression, declarationTypeParameters)
dispatchReceiver = dispatchReceiver?.cast(
declaration.dispatchReceiverParameter?.type?.substitute(typeParameters, typeArguments)
)
extensionReceiver = extensionReceiver?.cast(
declaration.extensionReceiverParameter?.type?.substitute(typeParameters, typeArguments)
)
}
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression =
expression.transformPostfix {
val dispatchReceiver = expression.run {
getter?.owner?.dispatchReceiverParameter
?: setter?.owner?.dispatchReceiverParameter
}
val extensionReceiver = expression.run {
getter?.owner?.extensionReceiverParameter
?: setter?.owner?.extensionReceiverParameter
}
this.dispatchReceiver = this.dispatchReceiver?.cast(dispatchReceiver?.type)
this.extensionReceiver = this.extensionReceiver?.cast(extensionReceiver?.type)
}
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression =
expression.transformPostfix {
val declaration = expression.getter.owner
val declarationTypeParameters = getDeclarationTypeParameters(declaration)
val receiverTypeParameters = getDispatchReceiverTypeParameters(declaration)
val typeParameters = declarationTypeParameters + receiverTypeParameters
val typeArguments = getTypeArguments(expression, declarationTypeParameters)
dispatchReceiver = dispatchReceiver?.cast(
declaration.dispatchReceiverParameter?.run {
type.substitute(typeParameters, typeArguments)
}
)
extensionReceiver = extensionReceiver?.cast(
declaration.extensionReceiverParameter?.run {
type.substitute(typeParameters, typeArguments)
}
)
transformReceiverArguments()
}
private fun IrMemberAccessExpression.transformReceiverArguments() {
val declaration = (this as IrFunctionAccessExpression).symbol.owner
val declarationTypeParameters = getDeclarationTypeParameters(declaration)
val receiverTypeParameters = getDispatchReceiverTypeParameters(declaration)
val typeParameters = declarationTypeParameters + receiverTypeParameters
val typeArguments = getTypeArguments(this, declarationTypeParameters)
dispatchReceiver = dispatchReceiver?.cast(
declaration.dispatchReceiverParameter?.run {
type.substitute(typeParameters, typeArguments)
}
)
extensionReceiver = extensionReceiver?.cast(
declaration.extensionReceiverParameter?.run {
type.substitute(typeParameters, typeArguments)
}
)
dispatchReceiver = dispatchReceiver?.cast(descriptor.dispatchReceiverParameter?.type)
extensionReceiver = extensionReceiver?.cast(descriptor.extensionReceiverParameter?.type)
}
override fun visitMemberAccess(expression: IrMemberAccessExpression): IrExpression =
with(expression as IrFunctionAccessExpression) {
val declaration = symbol.owner
val declarationTypeParameters = getDeclarationTypeParameters(declaration)
val receiverTypeParameters = getDispatchReceiverTypeParameters(declaration)
val typeArguments = getTypeArguments(expression, declarationTypeParameters)
val typeParameters = declarationTypeParameters + receiverTypeParameters
transformPostfix {
transformReceiverArguments()
for (index in declaration.valueParameters.indices) {
val argument = getValueArgument(index) ?: continue
val parameterType = declaration.valueParameters[index].type.substitute(typeParameters, typeArguments)
putValueArgument(index, argument.cast(parameterType))
}
expression.transformPostfix {
transformReceiverArguments()
for (index in descriptor.valueParameters.indices) {
val argument = getValueArgument(index) ?: continue
val parameterType = descriptor.valueParameters[index].type
putValueArgument(index, argument.cast(parameterType))
}
}
@@ -211,55 +110,35 @@ open class InsertImplicitCasts(
value = if (expression.returnTargetSymbol is IrConstructorSymbol) {
value.coerceToUnit()
} else {
value.cast(with(expression.returnTargetSymbol.owner as IrFunction) { returnType })
value.cast(expression.returnTarget.returnType)
}
}
override fun visitSetVariable(expression: IrSetVariable): IrExpression =
expression.transformPostfix {
value = value.cast(expression.symbol.owner.type)
}
override fun visitGetField(expression: IrGetField): IrExpression =
expression.transformPostfix {
val declaration = expression.symbol.owner
val receiverTypeParameters = getDispatchReceiverTypeParameters(declaration)
val typeArguments = getTypeArguments(expression, receiverTypeParameters)
receiver = receiver?.cast(
declaration.parentAsClass.thisReceiver?.run {
type.substitute(receiverTypeParameters, typeArguments)
}
)
value = value.cast(expression.descriptor.type)
}
override fun visitSetField(expression: IrSetField): IrExpression =
expression.transformPostfix {
val declaration = expression.symbol.owner
val receiverTypeParameters = getDispatchReceiverTypeParameters(declaration)
val typeArguments = getTypeArguments(expression, receiverTypeParameters)
receiver = receiver?.cast(
declaration.parentAsClass.thisReceiver?.run {
type.substitute(receiverTypeParameters, typeArguments)
}
)
value = value.cast(expression.symbol.owner.type.substitute(receiverTypeParameters, typeArguments))
value = value.cast(expression.descriptor.type)
}
override fun visitVariable(declaration: IrVariable): IrVariable =
declaration.transformPostfix {
initializer = initializer?.cast(declaration.symbol.owner.type)
initializer = initializer?.cast(declaration.descriptor.type)
}
override fun visitField(declaration: IrField): IrStatement =
declaration.transformPostfix {
initializer?.coerceInnerExpression(symbol.owner.type)
initializer?.coerceInnerExpression(descriptor.type)
}
override fun visitFunction(declaration: IrFunction): IrStatement =
typeTranslator.buildWithScope(declaration) {
declaration.transformPostfix {
valueParameters.forEach {
it.defaultValue?.coerceInnerExpression(it.type)
it.defaultValue?.coerceInnerExpression(it.descriptor.type)
}
}
}
@@ -272,20 +151,20 @@ open class InsertImplicitCasts(
override fun visitWhen(expression: IrWhen): IrExpression =
expression.transformPostfix {
for (irBranch in branches) {
irBranch.condition = irBranch.condition.cast(irBuiltIns.booleanType)
irBranch.condition = irBranch.condition.cast(builtIns.booleanType)
irBranch.result = irBranch.result.cast(type)
}
}
override fun visitLoop(loop: IrLoop): IrExpression =
loop.transformPostfix {
condition = condition.cast(irBuiltIns.booleanType)
condition = condition.cast(builtIns.booleanType)
body = body?.coerceToUnit()
}
override fun visitThrow(expression: IrThrow): IrExpression =
expression.transformPostfix {
value = value.cast(irBuiltIns.throwableType)
value = value.cast(builtIns.throwable.defaultType)
}
override fun visitTry(aTry: IrTry): IrExpression =
@@ -299,15 +178,28 @@ open class InsertImplicitCasts(
finallyExpression = finallyExpression?.coerceToUnit()
}
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
expression.transformChildren()
return when (expression.operator) {
IrTypeOperator.IMPLICIT_CAST ->
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression =
when (expression.operator) {
IrTypeOperator.SAM_CONVERSION -> expression.transformPostfix {
val targetClassDescriptor = typeOperandClassifier.descriptor as? ClassDescriptor
?: throw AssertionError("Target type of $operator should be a class: ${render()}")
argument = argument.cast(samConversion.getFunctionTypeForSAMClass(targetClassDescriptor))
}
IrTypeOperator.IMPLICIT_CAST -> {
// This branch is required for handling specific ambiguous cases in implicit cast insertion,
// such as SAM conversion VS smart cast.
// Here IMPLICIT_CAST serves as a type hint.
// Replace IrTypeOperatorCall(IMPLICIT_CAST, ...) with an argument cast to the required type
// (possibly generating another IrTypeOperatorCall(IMPLICIT_CAST, ...), if required).
expression.transformChildrenVoid()
expression.argument.cast(expression.typeOperand)
}
else ->
super.visitTypeOperator(expression)
}
}
override fun visitVararg(expression: IrVararg): IrExpression =
expression.transformPostfix {
@@ -321,49 +213,44 @@ open class InsertImplicitCasts(
}
}
private fun IrExpressionBody.coerceInnerExpression(expectedType: IrType) {
private fun IrExpressionBody.coerceInnerExpression(expectedType: KotlinType) {
expression = expression.cast(expectedType)
}
private fun IrExpression.cast(expectedType: IrType?): IrExpression {
private fun IrExpression.cast(irType: IrType): IrExpression =
cast(irType.originalKotlinType)
private fun IrExpression.cast(expectedType: KotlinType?): IrExpression {
if (expectedType == null) return this
if (expectedType is IrErrorType) return this
if (expectedType.isError) return this
val notNullableExpectedType = expectedType.makeNotNull()
// TODO here we can have non-denotable KotlinTypes (both in 'this@cast.type' and 'expectedType').
val valueType = this.type
val valueKotlinType = valueType.originalKotlinType!!
val notNullableExpectedType = expectedType.makeNotNullable()
val valueType = this.type.originalKotlinType!!
return when {
expectedType.isUnit() -> {
expectedType.originalKotlinType?.let { require(it.isUnit()) }
expectedType.isUnit() ->
coerceToUnit()
}
valueType is IrDynamicType && expectedType !is IrDynamicType -> {
if (expectedType.isNullableAny()) {
valueType.isDynamic() && !expectedType.isDynamic() ->
if (expectedType.isNullableAny())
this
} else {
else
implicitCast(expectedType, IrTypeOperator.IMPLICIT_DYNAMIC_CAST)
}
}
valueKotlinType.isNullabilityFlexible() && valueType.containsNull() && !expectedType.containsNull() -> {
valueType.isNullabilityFlexible() && valueType.containsNull() && !expectedType.containsNull() ->
implicitNonNull(valueType, expectedType)
}
valueType.isSubtypeOf(expectedType.makeNullable(), irBuiltIns) -> {
KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType.makeNullable()) ->
this
}
valueType.isInt() && notNullableExpectedType.isBuiltInIntegerType() -> {
KotlinBuiltIns.isInt(valueType) && notNullableExpectedType.isBuiltInIntegerType() ->
implicitCast(notNullableExpectedType, IrTypeOperator.IMPLICIT_INTEGER_COERCION)
}
valueType.isSubtypeOf(expectedType, irBuiltIns) -> {
require(valueType.isSubtypeOf(expectedType, irBuiltIns))
KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, expectedType) ->
this
}
else -> {
val targetType = if (!valueType.containsNull()) notNullableExpectedType else expectedType
@@ -372,38 +259,42 @@ open class InsertImplicitCasts(
}
}
private fun IrExpression.implicitNonNull(valueType: IrType, expectedType: IrType): IrExpression {
val notNullValueType = valueType.getRepresentableUpperBound().makeNotNull()
return implicitCast(notNullValueType, IrTypeOperator.IMPLICIT_NOTNULL).cast(expectedType)
private fun IrExpression.implicitNonNull(valueType: KotlinType, expectedType: KotlinType): IrExpression {
val nonNullValueType = valueType.upperIfFlexible().makeNotNullable()
return implicitCast(nonNullValueType, IrTypeOperator.IMPLICIT_NOTNULL).cast(expectedType)
}
private fun IrExpression.implicitCast(
targetType: IrType,
targetType: KotlinType,
typeOperator: IrTypeOperator
): IrExpression {
val irType = targetType.toIrType()
return IrTypeOperatorCallImpl(
startOffset,
endOffset,
targetType,
irType,
typeOperator,
targetType,
irType,
this
)
}
protected open fun IrExpression.coerceToUnit(): IrExpression {
return coerceToUnitIfNeeded(type, irBuiltIns)
val valueType = getKotlinType(this)
return coerceToUnitIfNeeded(valueType, irBuiltIns)
}
private fun IrType.isBuiltInIntegerType(): Boolean =
isByte() || isShort() || isInt() || isLong() ||
isUByte() || isUShort() || isUInt() || isULong()
protected fun getKotlinType(irExpression: IrExpression) =
irExpression.type.originalKotlinType!!
private fun IrType.getRepresentableUpperBound(): IrType {
if (this !is IrSimpleType) return this
val classifier = this.classifier as? IrTypeParameterSymbol ?: return this
val superTypes = classifier.owner.superTypes
return makeTypeIntersection(superTypes)
}
private fun KotlinType.isBuiltInIntegerType(): Boolean =
KotlinBuiltIns.isByte(this) ||
KotlinBuiltIns.isShort(this) ||
KotlinBuiltIns.isInt(this) ||
KotlinBuiltIns.isLong(this) ||
KotlinBuiltIns.isUByte(this) ||
KotlinBuiltIns.isUShort(this) ||
KotlinBuiltIns.isUInt(this) ||
KotlinBuiltIns.isULong(this)
}