PSI2IR: Don't generate IMPLICIT_INTEGER_COERCION
Generate integer coercion function calls and properly typed constant expressions instead.
This commit is contained in:
+78
-15
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
@@ -29,20 +30,26 @@ 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.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.ir.util.TypeTranslator
|
||||
import org.jetbrains.kotlin.ir.util.coerceToUnit
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi2ir.containsNull
|
||||
import org.jetbrains.kotlin.psi2ir.findSingleFunction
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
|
||||
import org.jetbrains.kotlin.psi2ir.generators.getSubstitutedFunctionTypeForSamType
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.typeUtil.*
|
||||
@@ -53,7 +60,8 @@ fun insertImplicitCasts(element: IrElement, context: GeneratorContext) {
|
||||
context.irBuiltIns,
|
||||
context.typeTranslator,
|
||||
context.callToSubstitutedDescriptorMap,
|
||||
context.extensions
|
||||
context.extensions,
|
||||
context.symbolTable
|
||||
).run(element)
|
||||
}
|
||||
|
||||
@@ -62,7 +70,8 @@ internal class InsertImplicitCasts(
|
||||
private val irBuiltIns: IrBuiltIns,
|
||||
private val typeTranslator: TypeTranslator,
|
||||
private val callToSubstitutedDescriptorMap: Map<IrDeclarationReference, CallableDescriptor>,
|
||||
private val generatorExtensions: GeneratorExtensions
|
||||
private val generatorExtensions: GeneratorExtensions,
|
||||
private val symbolTable: SymbolTable
|
||||
) : IrElementTransformerVoid() {
|
||||
|
||||
private val expectedFunctionExpressionReturnType = hashMapOf<FunctionDescriptor, IrType>()
|
||||
@@ -354,7 +363,7 @@ internal class InsertImplicitCasts(
|
||||
this
|
||||
|
||||
KotlinBuiltIns.isInt(valueType) && notNullableExpectedType.isBuiltInIntegerType() ->
|
||||
implicitCast(notNullableExpectedType, IrTypeOperator.IMPLICIT_INTEGER_COERCION)
|
||||
coerceIntToAnotherIntegerType(notNullableExpectedType)
|
||||
|
||||
else -> {
|
||||
val targetType = if (!valueType.containsNull()) notNullableExpectedType else expectedType
|
||||
@@ -389,19 +398,73 @@ internal class InsertImplicitCasts(
|
||||
return implicitCast(nonNullValueType, IrTypeOperator.IMPLICIT_NOTNULL).cast(expectedType)
|
||||
}
|
||||
|
||||
private fun IrExpression.implicitCast(
|
||||
targetType: KotlinType,
|
||||
typeOperator: IrTypeOperator
|
||||
): IrExpression {
|
||||
private fun IrExpression.implicitCast(targetType: KotlinType, typeOperator: IrTypeOperator): IrExpression {
|
||||
val irType = targetType.toIrType()
|
||||
return IrTypeOperatorCallImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
irType,
|
||||
typeOperator,
|
||||
irType,
|
||||
this
|
||||
)
|
||||
return IrTypeOperatorCallImpl(startOffset, endOffset, irType, typeOperator, irType, this)
|
||||
}
|
||||
|
||||
private fun IrExpression.coerceIntToAnotherIntegerType(targetType: KotlinType): IrExpression {
|
||||
if (!type.originalKotlinType!!.isInt()) throw AssertionError("Expression of type 'kotlin.Int' expected: $this")
|
||||
if (targetType.isInt()) return this
|
||||
return if (this is IrConst<*>) {
|
||||
val value = this.value as Int
|
||||
val irType = targetType.toIrType()
|
||||
when {
|
||||
targetType.isByte() -> IrConstImpl.byte(startOffset, endOffset, irType, value.toByte())
|
||||
targetType.isShort() -> IrConstImpl.short(startOffset, endOffset, irType, value.toShort())
|
||||
targetType.isLong() -> IrConstImpl.long(startOffset, endOffset, irType, value.toLong())
|
||||
KotlinBuiltIns.isUByte(targetType) -> IrConstImpl.byte(startOffset, endOffset, irType, value.toByte())
|
||||
KotlinBuiltIns.isUShort(targetType) -> IrConstImpl.short(startOffset, endOffset, irType, value.toShort())
|
||||
KotlinBuiltIns.isUInt(targetType) -> IrConstImpl.int(startOffset, endOffset, irType, value)
|
||||
KotlinBuiltIns.isULong(targetType) -> IrConstImpl.long(startOffset, endOffset, irType, value.toLong())
|
||||
else -> throw AssertionError("Unexpected target type for integer coercion: $targetType")
|
||||
}
|
||||
} else {
|
||||
when {
|
||||
targetType.isByte() -> invokeIntegerCoercionFunction(targetType, "toByte")
|
||||
targetType.isShort() -> invokeIntegerCoercionFunction(targetType, "toShort")
|
||||
targetType.isLong() -> invokeIntegerCoercionFunction(targetType, "toLong")
|
||||
KotlinBuiltIns.isUByte(targetType) -> invokeUnsignedIntegerCoercionFunction(targetType, "toUByte")
|
||||
KotlinBuiltIns.isUShort(targetType) -> invokeUnsignedIntegerCoercionFunction(targetType, "toUShort")
|
||||
KotlinBuiltIns.isUInt(targetType) -> invokeUnsignedIntegerCoercionFunction(targetType, "toUInt")
|
||||
KotlinBuiltIns.isULong(targetType) -> invokeUnsignedIntegerCoercionFunction(targetType, "toULong")
|
||||
else -> throw AssertionError("Unexpected target type for integer coercion: $targetType")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrExpression.invokeIntegerCoercionFunction(targetType: KotlinType, coercionFunName: String): IrExpression {
|
||||
val coercionFunction = builtIns.int.unsubstitutedMemberScope.findSingleFunction(Name.identifier(coercionFunName))
|
||||
return IrCallImpl(
|
||||
startOffset, endOffset,
|
||||
targetType.toIrType(),
|
||||
symbolTable.referenceSimpleFunction(coercionFunction),
|
||||
typeArgumentsCount = 0, valueArgumentsCount = 0
|
||||
).also { irCall ->
|
||||
irCall.dispatchReceiver = this
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrExpression.invokeUnsignedIntegerCoercionFunction(targetType: KotlinType, coercionFunName: String): IrExpression {
|
||||
// 'toUByte', 'toUShort', 'toUInt', 'toULong' are top-level extension functions in 'kotlin' package.
|
||||
// There are several such functions (one for each built-in integer type: Byte, Short, Int, Long),
|
||||
// we need one that takes Int.
|
||||
val coercionFunction = targetType.constructor.declarationDescriptor!!.module
|
||||
.getPackage(KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)
|
||||
.memberScope.getContributedFunctions(Name.identifier(coercionFunName), NoLookupLocation.FROM_BACKEND)
|
||||
.find {
|
||||
val extensionReceiver = it.extensionReceiverParameter
|
||||
extensionReceiver != null && extensionReceiver.type.isInt()
|
||||
}
|
||||
?: throw AssertionError("Coercion function '$coercionFunName' not found")
|
||||
return IrCallImpl(
|
||||
startOffset, endOffset,
|
||||
targetType.toIrType(),
|
||||
symbolTable.referenceSimpleFunction(coercionFunction),
|
||||
typeArgumentsCount = 0, valueArgumentsCount = 0
|
||||
).also { irCall ->
|
||||
irCall.extensionReceiver = this
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinType.isBuiltInIntegerType(): Boolean =
|
||||
|
||||
Reference in New Issue
Block a user