Move eraseTypeParameters to IrUtils and use it in PromisedValue.coerce
This commit is contained in:
committed by
Alexander Udalov
parent
3ce0c336bc
commit
41ce88cb9b
+27
-27
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.jvm.codegen
|
package org.jetbrains.kotlin.backend.jvm.codegen
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.ir.eraseTypeParameters
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
||||||
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
|
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||||
@@ -81,35 +82,34 @@ fun PromisedValue.discard(): PromisedValue {
|
|||||||
private val IrType.unboxed: IrType
|
private val IrType.unboxed: IrType
|
||||||
get() = InlineClassAbi.getUnderlyingType(erasedUpperBound)
|
get() = InlineClassAbi.getUnderlyingType(erasedUpperBound)
|
||||||
|
|
||||||
fun PromisedValue.coerceInlineClasses(type: Type, irType: IrType, target: Type, irTarget: IrType): PromisedValue? {
|
|
||||||
val isFromTypeInlineClass = irType.erasedUpperBound.isInline
|
|
||||||
val isToTypeInlineClass = irTarget.erasedUpperBound.isInline
|
|
||||||
if (!isFromTypeInlineClass && !isToTypeInlineClass) return null
|
|
||||||
|
|
||||||
val isFromTypeUnboxed = isFromTypeInlineClass && typeMapper.mapType(irType.unboxed) == type
|
|
||||||
val isToTypeUnboxed = isToTypeInlineClass && typeMapper.mapType(irTarget.unboxed) == target
|
|
||||||
|
|
||||||
return when {
|
|
||||||
isFromTypeUnboxed && !isToTypeUnboxed -> object : PromisedValue(codegen, target, irTarget) {
|
|
||||||
override fun materialize() {
|
|
||||||
this@coerceInlineClasses.materialize()
|
|
||||||
// TODO: This is broken for type parameters
|
|
||||||
StackValue.boxInlineClass(irType.toKotlinType(), mv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
!isFromTypeUnboxed && isToTypeUnboxed -> object : PromisedValue(codegen, target, irTarget) {
|
|
||||||
override fun materialize() {
|
|
||||||
val value = this@coerceInlineClasses.materialized
|
|
||||||
StackValue.unboxInlineClass(value.type, irTarget.toKotlinType(), mv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// On materialization, cast the value to a different type.
|
// On materialization, cast the value to a different type.
|
||||||
fun PromisedValue.coerce(target: Type, irTarget: IrType): PromisedValue {
|
fun PromisedValue.coerce(target: Type, irTarget: IrType): PromisedValue {
|
||||||
coerceInlineClasses(type, irType, target, irTarget)?.let { return it }
|
val erasedSourceType = irType.eraseTypeParameters()
|
||||||
|
val erasedTargetType = irTarget.eraseTypeParameters()
|
||||||
|
val isFromTypeInlineClass = erasedSourceType.classOrNull!!.owner.isInline
|
||||||
|
val isToTypeInlineClass = erasedTargetType.classOrNull!!.owner.isInline
|
||||||
|
|
||||||
|
// Coerce inline classes
|
||||||
|
if (isFromTypeInlineClass || isToTypeInlineClass) {
|
||||||
|
val isFromTypeUnboxed = isFromTypeInlineClass && typeMapper.mapType(erasedSourceType.unboxed) == type
|
||||||
|
val isToTypeUnboxed = isToTypeInlineClass && typeMapper.mapType(erasedTargetType.unboxed) == target
|
||||||
|
|
||||||
|
when {
|
||||||
|
isFromTypeUnboxed && !isToTypeUnboxed -> return object : PromisedValue(codegen, target, irTarget) {
|
||||||
|
override fun materialize() {
|
||||||
|
this@coerce.materialize()
|
||||||
|
StackValue.boxInlineClass(erasedSourceType.toKotlinType(), mv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
!isFromTypeUnboxed && isToTypeUnboxed -> return object : PromisedValue(codegen, target, irTarget) {
|
||||||
|
override fun materialize() {
|
||||||
|
val value = this@coerce.materialized
|
||||||
|
StackValue.unboxInlineClass(value.type, erasedTargetType.toKotlinType(), mv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return when (type) {
|
return when (type) {
|
||||||
// All unsafe coercions between irTypes should use the UnsafeCoerce intrinsic
|
// All unsafe coercions between irTypes should use the UnsafeCoerce intrinsic
|
||||||
target -> this
|
target -> this
|
||||||
|
|||||||
@@ -9,15 +9,46 @@ import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
|
|||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
|
||||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||||
import org.jetbrains.kotlin.ir.util.isFunction
|
import org.jetbrains.kotlin.ir.util.isFunction
|
||||||
import org.jetbrains.kotlin.ir.util.isNullable
|
import org.jetbrains.kotlin.ir.util.isNullable
|
||||||
import org.jetbrains.kotlin.ir.util.isSuspendFunctionTypeOrSubtype
|
import org.jetbrains.kotlin.ir.util.isSuspendFunctionTypeOrSubtype
|
||||||
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_DEFAULT_FQ_NAME
|
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_DEFAULT_FQ_NAME
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform as much type erasure as is significant for JVM signature generation.
|
||||||
|
* Class types are kept as is, while type parameters are replaced with their
|
||||||
|
* erased upper bounds, keeping the nullability information.
|
||||||
|
*
|
||||||
|
* For example, a type parameter `T?` where `T : Any`, `T : Comparable<T>` is
|
||||||
|
* erased to `Any?`.
|
||||||
|
*
|
||||||
|
* Type arguments to the erased upper bound are replaced by `*`, since
|
||||||
|
* recursive erasure could loop. For example, a type parameter
|
||||||
|
* `T : Comparable<T>` is replaced by `Comparable<*>`.
|
||||||
|
*/
|
||||||
|
fun IrType.eraseTypeParameters() = when (this) {
|
||||||
|
is IrErrorType -> this
|
||||||
|
is IrSimpleType ->
|
||||||
|
when (val owner = classifier.owner) {
|
||||||
|
is IrClass -> this
|
||||||
|
is IrTypeParameter -> {
|
||||||
|
val upperBound = owner.erasedUpperBound
|
||||||
|
IrSimpleTypeImpl(
|
||||||
|
upperBound.symbol,
|
||||||
|
isNullable(),
|
||||||
|
List(upperBound.typeParameters.size) { IrStarProjectionImpl }, // Should not affect JVM signature, but may result in an invalid type object
|
||||||
|
owner.annotations
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> error("Unknown IrSimpleType classifier kind: $owner")
|
||||||
|
}
|
||||||
|
else -> error("Unknown IrType kind: $this")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the erased class for this type parameter according to the java erasure rules.
|
* Computes the erased class for this type parameter according to the java erasure rules.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+5
-28
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.backend.common.lower.irNot
|
|||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
|
import org.jetbrains.kotlin.backend.jvm.ir.eraseTypeParameters
|
||||||
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
|
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
@@ -34,12 +34,10 @@ import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
|||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.types.IrErrorType
|
import org.jetbrains.kotlin.ir.util.defaultType
|
||||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.util.isInterface
|
||||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
|
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||||
@@ -339,27 +337,6 @@ private class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform type erasure as much as is significant for JVM signature generation. */
|
|
||||||
// TODO: should be a type mapper functionality.
|
|
||||||
private fun IrType.eraseTypeParameters() = when (this) {
|
|
||||||
is IrErrorType -> this
|
|
||||||
is IrSimpleType ->
|
|
||||||
when (val owner = classifier.owner) {
|
|
||||||
is IrClass -> this
|
|
||||||
is IrTypeParameter -> {
|
|
||||||
val upperBound = owner.erasedUpperBound
|
|
||||||
IrSimpleTypeImpl(
|
|
||||||
upperBound.symbol,
|
|
||||||
isNullable(),
|
|
||||||
List(upperBound.typeParameters.size) { IrStarProjectionImpl }, // Should not affect JVM signature, but may result in an invalid type object
|
|
||||||
owner.annotations
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else -> error("Unknown IrSimpleType classifier kind: $owner")
|
|
||||||
}
|
|
||||||
else -> error("Unknown IrType kind: $this")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun IrSimpleFunction.findAllReachableDeclarations() =
|
private fun IrSimpleFunction.findAllReachableDeclarations() =
|
||||||
findAllReachableDeclarations(FunctionHandleForIrFunction(this)).map { it.irFunction }
|
findAllReachableDeclarations(FunctionHandleForIrFunction(this)).map { it.irFunction }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user