Rework nullability in IR

This commit is contained in:
Pavel Kunyavskiy
2022-03-18 13:40:20 +03:00
committed by Space
parent 000165b12b
commit 7ba4d9e1f0
108 changed files with 1679 additions and 469 deletions
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.SimpleTypeNullability
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.types.impl.*
@@ -289,7 +290,7 @@ internal class BuiltInFictitiousFunctionIrClassFactory(
val kotlinType = wrapped.unwrap()
return with(IrSimpleTypeBuilder()) {
classifier = symbolTable.referenceClassifier(kotlinType.constructor.declarationDescriptor ?: error("No classifier for type $kotlinType"))
hasQuestionMark = kotlinType.isMarkedNullable
nullability = SimpleTypeNullability.fromHasQuestionMark(kotlinType.isMarkedNullable)
arguments = kotlinType.arguments.map {
if (it.isStarProjection) IrStarProjectionImpl
else makeTypeProjection(toIrType(it.type), it.projectionKind)
@@ -23,9 +23,8 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
internal fun IrType.isCEnumType(): Boolean {
val simpleType = this as? IrSimpleType ?: return false
if (simpleType.hasQuestionMark) return false
val enumClass = simpleType.classifier.owner as? IrClass ?: return false
if (isNullable()) return false
val enumClass = classOrNull?.owner ?: return false
if (!enumClass.isEnumClass) return false
return enumClass.superTypes
@@ -53,11 +52,10 @@ internal fun IrSimpleFunction.objCReturnsRetained() = hasCCallAnnotation("Return
internal fun IrClass.getCStructSpelling(): String? =
getAnnotationArgumentValue(FqName("kotlinx.cinterop.internal.CStruct"), "spelling")
internal fun IrType.isTypeOfNullLiteral(): Boolean = this is IrSimpleType && hasQuestionMark
&& classifier.isClassWithFqName(StandardNames.FqNames.nothing)
internal fun IrType.isTypeOfNullLiteral(): Boolean = isNullableNothing()
internal fun IrType.isVector(): Boolean {
if (this is IrSimpleType && !this.hasQuestionMark) {
if (this is IrSimpleType && !this.isNullable()) {
return classifier.isClassWithFqName(KonanFqNames.Vector128.toUnsafe())
}
return false
@@ -1515,8 +1515,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
!this.isChar()
}
private fun IrType.isUnsignedInteger(): Boolean =
this is IrSimpleType && !this.hasQuestionMark &&
private fun IrType.isUnsignedInteger(): Boolean = !isNullable() &&
UnsignedType.values().any { it.classId == this.getClass()?.descriptor?.classId }
private fun evaluateIntegerCoercion(value: IrTypeOperatorCall): LLVMValueRef {
@@ -16,8 +16,8 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.isNullable
import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
internal class DataClassOperatorsLowering(val context: Context) : FileLoweringPass, IrElementTransformer<IrFunction?> {
@@ -56,7 +56,7 @@ internal class DataClassOperatorsLowering(val context: Context) : FileLoweringPa
// TODO: use more precise type arguments.
val typeArguments = (0 until newCallee.typeParameters.size).map { irBuiltins.anyNType }
if (!argument.type.isSimpleTypeWithQuestionMark) {
if (!argument.type.isNullable()) {
irCall(newCallee, typeArguments).apply {
extensionReceiver = argument
}
@@ -1114,8 +1114,9 @@ private class InteropTransformer(val context: Context, override val irFile: IrFi
val receiverType = expression.symbol.owner.extensionReceiverParameter!!.type
val source = receiverType.classifierOrFail as IrClassSymbol
require(source in integerClasses) { renderCompilerError(expression) }
require(typeOperand is IrSimpleType && typeOperand.classifier in integerClasses
&& !typeOperand.hasQuestionMark) { renderCompilerError(expression) }
require(typeOperand is IrSimpleType && !typeOperand.isNullable() && typeOperand.classifier in integerClasses) {
renderCompilerError(expression)
}
val target = typeOperand.classifier as IrClassSymbol
val valueToConvert = expression.extensionReceiver!!
@@ -71,7 +71,7 @@ internal class KTypeGenerator(
return irKTypeImpl(
kClassifier = kClassifier,
irTypeArguments = type.arguments,
isMarkedNullable = type.hasQuestionMark,
isMarkedNullable = type.isMarkedNullable(),
leaveReifiedForLater = leaveReifiedForLater,
seenTypeParameters = seenTypeParameters,
type = type,
@@ -16,8 +16,8 @@ import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
import org.jetbrains.kotlin.ir.types.isNullable
import org.jetbrains.kotlin.ir.types.isNullableNothing
import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
@@ -39,7 +39,7 @@ internal class ReturnsInsertionLowering(val context: Context) : FileLoweringPass
context.createIrBuilder(declaration.symbol, declaration.endOffset, declaration.endOffset).run {
if (declaration is IrConstructor || declaration.returnType == context.irBuiltIns.unitType) {
body.statements += irReturn(irGetObject(symbols.unit))
} else if (declaration.returnType.isSimpleTypeWithQuestionMark) {
} else if (declaration.returnType.isNullable()) {
// this is a workaround for KT-42832
val typeOperatorCall = body.statements.lastOrNull() as? IrTypeOperatorCall
if (typeOperatorCall?.operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT
@@ -34,7 +34,7 @@ internal class SamSuperTypesChecker(private val context: Context,
if (this !is IrSimpleType) return this
return buildSimpleType {
this.classifier = this@eraseProjections.classifier
this.hasQuestionMark = this@eraseProjections.hasQuestionMark
this.nullability = this@eraseProjections.nullability
this.annotations = this@eraseProjections.annotations
this.arguments = this@eraseProjections.arguments.mapIndexed { index, argument ->
if (argument !is IrTypeProjection)
@@ -452,7 +452,7 @@ private class BackendChecker(val context: Context, val irFile: IrFile) : IrEleme
val typeOperand = expression.getTypeArgument(0)!!
val receiverType = expression.symbol.owner.extensionReceiverParameter!!.type
if (typeOperand !is IrSimpleType || typeOperand.classifier !in integerClasses || typeOperand.hasQuestionMark)
if (typeOperand !is IrSimpleType || typeOperand.classifier !in integerClasses || typeOperand.isNullable())
reportError(expression, "unable to convert ${receiverType.toKotlinType()} to ${typeOperand.toKotlinType()}")
}
IntrinsicType.WORKER_EXECUTE -> {
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
// TODO: Similar to IrType.erasedUpperBound from jvm.ir
internal fun IrType.erasure(): IrType {
if (this is IrDefinitelyNotNullType) return this.original.erasure().makeNotNull()
if (this !is IrSimpleType) return this
val upperBound = when (val classifier = classifier) {
@@ -40,10 +39,7 @@ internal fun IrType.erasure(): IrType {
else -> TODO(classifier.toString())
}
return if (this.hasQuestionMark)
upperBound.makeNullable()
else
upperBound
return upperBound.mergeNullability(this)
}
internal val IrType.erasedUpperBound get() = this.erasure().getClass() ?: error(this.render())
@@ -72,7 +68,7 @@ internal class TypeOperatorLowering(val context: CommonBackendContext) : FileLow
type = expression.type,
condition = irEqeqeq(irGet(argument.owner), irNull()),
thenPart = if (typeOperand.isSimpleTypeWithQuestionMark)
thenPart = if (typeOperand.isNullable())
irNull()
else
irCall(this@TypeOperatorLowering.context.ir.symbols.throwNullPointerException.owner),
@@ -83,7 +79,7 @@ internal class TypeOperatorLowering(val context: CommonBackendContext) : FileLow
}
}
typeOperand.isSimpleTypeWithQuestionMark -> builder.irAs(expression.argument, typeOperand.makeNotNull())
typeOperand.isMarkedNullable() -> builder.irAs(expression.argument, typeOperand.makeNotNull())
typeOperand == expression.typeOperand -> expression
@@ -192,9 +192,7 @@ fun IrType.substitute(map: Map<IrTypeParameterSymbol, IrType>): IrType {
val classifier = this.classifier
return when (classifier) {
is IrTypeParameterSymbol ->
map[classifier]?.let { if (this.hasQuestionMark) it.makeNullable() else it }
?: this
map[classifier]?.mergeNullability(this) ?: this
is IrClassSymbol -> if (this.arguments.isEmpty()) {
this // Fast path.
} else {
@@ -205,7 +203,7 @@ fun IrType.substitute(map: Map<IrTypeParameterSymbol, IrType>): IrType {
else -> error(it)
}
}
IrSimpleTypeImpl(classifier, hasQuestionMark, newArguments, annotations)
IrSimpleTypeImpl(classifier, nullability, newArguments, annotations)
}
else -> error(classifier)
}
@@ -368,9 +366,6 @@ fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter
)
}
val IrType.isSimpleTypeWithQuestionMark: Boolean
get() = this is IrSimpleType && this.hasQuestionMark
fun IrClass.defaultOrNullableType(hasQuestionMark: Boolean) =
if (hasQuestionMark) this.defaultType.makeNullable() else this.defaultType