psi2ir: fix nullability assertion generation for platform types

Incorporate PR from Steven Schäfer into IrType-based implicit cast
insertion (commit 17b925636e8717e7648c5d7b792c6ab4d18f776d).

NB this still uses originalKotlinType to determine if the type was
nullability flexible. It is somewhat error-prone and something we want
to get rid of. However, it boils down to some design questions related
to implicit null checks in Kotlin - e.g., it might be Ok to just treat
nullability flexible type `T!` as `T?` in IR, generate null checks for
all usages of type `T?` where a non-null type is expected, and later
eliminate the null checks that are redundant according to the (quite
conservative) criterion in the redundant null check elimination.
This commit is contained in:
Dmitry Petrov
2019-04-16 12:01:22 +03:00
parent ab38430ded
commit 1d9cb39915
14 changed files with 276 additions and 31 deletions
@@ -26,6 +26,7 @@ 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.impl.originalKotlinType
import org.jetbrains.kotlin.ir.util.TypeTranslator
@@ -37,7 +38,6 @@ import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.kotlin.types.isNullabilityFlexible
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
fun insertImplicitCasts(element: IrElement, context: GeneratorContext) {
element.transformChildren(
@@ -111,10 +111,12 @@ open class InsertImplicitCasts(
val dTypeParameters = getDeclarationSideTypeParameters(declaration)
val cTypeParameters = getTypeSideTypeParameters(declaration)
val typeArguments = getTypeArguments(expression, dTypeParameters)
val dispatchReceiver = declaration.dispatchReceiverParameter
val extensionReceiver = declaration.extensionReceiverParameter
this.dispatchReceiver = this.dispatchReceiver?.cast(dispatchReceiver?.type?.substitute(dTypeParameters + cTypeParameters, typeArguments))
this.extensionReceiver = this.extensionReceiver?.cast(extensionReceiver?.type?.substitute(dTypeParameters + cTypeParameters, typeArguments))
dispatchReceiver = dispatchReceiver?.cast(
declaration.dispatchReceiverParameter?.type?.substitute(dTypeParameters + cTypeParameters, typeArguments)
)
extensionReceiver = extensionReceiver?.cast(
declaration.extensionReceiverParameter?.type?.substitute(dTypeParameters + cTypeParameters, typeArguments)
)
}
}
@@ -123,8 +125,12 @@ open class InsertImplicitCasts(
val dTypeParameters = getDeclarationSideTypeParameters(declaration)
val cTypeParameters = getTypeSideTypeParameters(declaration)
val typeArguments = getTypeArguments(this, dTypeParameters)
dispatchReceiver = dispatchReceiver?.cast(declaration.dispatchReceiverParameter?.type?.substitute(dTypeParameters + cTypeParameters, typeArguments))
extensionReceiver = extensionReceiver?.cast(declaration.extensionReceiverParameter?.type?.substitute(dTypeParameters + cTypeParameters, typeArguments))
dispatchReceiver = dispatchReceiver?.cast(
declaration.dispatchReceiverParameter?.type?.substitute(dTypeParameters + cTypeParameters, typeArguments)
)
extensionReceiver = extensionReceiver?.cast(
declaration.extensionReceiverParameter?.type?.substitute(dTypeParameters + cTypeParameters, typeArguments)
)
}
override fun visitMemberAccess(expression: IrMemberAccessExpression): IrExpression =
@@ -314,7 +320,7 @@ open class InsertImplicitCasts(
}
private fun IrExpression.implicitNonNull(valueType: IrType, expectedType: IrType): IrExpression {
val notNullValueType = valueType.makeNotNull()
val notNullValueType = valueType.getRepresentableUpperBound().makeNotNull()
return implicitCast(notNullValueType, IrTypeOperator.IMPLICIT_NOTNULL).cast(expectedType)
}
@@ -352,9 +358,13 @@ open class InsertImplicitCasts(
private fun IrType.isBuiltInIntegerType(): Boolean =
isByte() || isShort() || isInt() || isLong() ||
isUByte() ||
isUShort() ||
isUInt() ||
isULong()
isUByte() || isUShort() || isUInt() || isULong()
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)
}
}
@@ -57,11 +57,11 @@ class TypeTranslator(
typeParametersResolver.resolveScopedTypeParameter(typeParameterDescriptor)
?: symbolTable.referenceTypeParameter(typeParameterDescriptor)
fun translateType(ktType: KotlinType): IrType =
translateType(ktType, Variance.INVARIANT).type
fun translateType(kotlinType: KotlinType): IrType =
translateType(kotlinType, kotlinType, Variance.INVARIANT).type
private fun translateType(ktType: KotlinType, variance: Variance): IrTypeProjection {
val approximatedType = LegacyTypeApproximation().approximate(ktType)
private fun translateType(originalKotlinType: KotlinType, kotlinType: KotlinType, variance: Variance): IrTypeProjection {
val approximatedType = LegacyTypeApproximation().approximate(kotlinType)
when {
approximatedType.isError ->
@@ -69,7 +69,7 @@ class TypeTranslator(
approximatedType.isDynamic() ->
return IrDynamicTypeImpl(approximatedType, translateTypeAnnotations(approximatedType.annotations), variance)
approximatedType.isFlexible() ->
return translateType(approximatedType.upperIfFlexible(), variance)
return translateType(originalKotlinType, approximatedType.upperIfFlexible(), variance)
}
val ktTypeConstructor = approximatedType.constructor
@@ -77,7 +77,7 @@ class TypeTranslator(
?: throw AssertionError("No descriptor for type $approximatedType")
return IrSimpleTypeBuilder().apply {
kotlinType = approximatedType
this.kotlinType = originalKotlinType
hasQuestionMark = approximatedType.isMarkedNullable
this.variance = variance
when (ktTypeDescriptor) {
@@ -140,6 +140,6 @@ class TypeTranslator(
if (it.isStarProjection)
IrStarProjectionImpl
else
translateType(it.type, it.projectionKind)
translateType(it.type, it.type, it.projectionKind)
}
}