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:
+22
-12
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user