Fix IR types in JVM_IR BridgeLowering

Properly implement the java erasure rules on IrTypes and fix the types
for dispatch and extension receivers.
This commit is contained in:
Steven Schäfer
2019-05-10 10:41:31 +02:00
committed by max-kammerer
parent c885cadde4
commit 2da0315d2e
2 changed files with 47 additions and 26 deletions
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.jvm.ir
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.classifierOrNull
/**
* Computes the erased class for this type parameter according to the java erasure rules.
*/
val IrTypeParameter.erasedUpperBound: IrClass
get() {
// Pick the (necessarily unique) non-interface upper bound if it exists
for (type in superTypes) {
val irClass = type.classOrNull?.owner ?: continue
if (!irClass.isJvmInterface) return irClass
}
// Otherwise, choose either the first IrClass supertype or recurse.
// In the first case, all supertypes are interface types and the choice was arbitrary.
// In the second case, there is only a single supertype.
return superTypes.first().erasedUpperBound
}
val IrType.erasedUpperBound: IrClass
get() = when (val classifier = classifierOrNull) {
is IrClassSymbol -> classifier.owner
is IrTypeParameterSymbol -> classifier.owner.erasedUpperBound
else -> throw IllegalStateException()
}
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.backend.common.lower.irNot
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
@@ -30,20 +31,14 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrErrorType
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.commons.Method
@@ -278,9 +273,9 @@ private class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass
superQualifierSymbol = if (invokeStatically) maybeOrphanedTarget.parentAsClass.symbol else null
).apply {
passTypeArgumentsFrom(this@createBridgeBody)
dispatchReceiver = irImplicitCast(irGet(dispatchReceiverParameter!!), dispatchReceiverParameter!!.type)
dispatchReceiver = irGet(dispatchReceiverParameter!!)
extensionReceiverParameter?.let {
extensionReceiver = irImplicitCast(irGet(it), extensionReceiverParameter!!.type)
extensionReceiver = irImplicitCast(irGet(it), maybeOrphanedTarget.extensionReceiverParameter!!.type)
}
valueParameters.forEach {
putValueArgument(it.index, irImplicitCast(irGet(it), maybeOrphanedTarget.valueParameters[it.index].type))
@@ -341,36 +336,23 @@ private class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass
// TODO: should be a type mapper functionality.
private fun IrType.eraseTypeParameters() = when (this) {
is IrErrorType -> this
is IrSimpleType -> {
val owner = classifier.owner
when (owner) {
is IrSimpleType ->
when (val owner = classifier.owner) {
is IrClass -> this
is IrTypeParameter -> {
val upperBound = owner.upperBoundClass()
val upperBound = owner.erasedUpperBound
IrSimpleTypeImpl(
upperBound.symbol,
hasQuestionMark,
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 IrTypeParameter.upperBoundClass(): IrClass {
val simpleSuperClassifiers = superTypes.asSequence().filterIsInstance<IrSimpleType>().map { it.classifier }
return simpleSuperClassifiers
.filterIsInstance<IrClassSymbol>()
.let {
it.firstOrNull { !it.owner.isInterface } ?: it.firstOrNull()
}?.owner ?:
simpleSuperClassifiers.filterIsInstance<IrTypeParameterSymbol>().map { it.owner.upperBoundClass() }.firstOrNull() ?:
context.irBuiltIns.anyClass.owner
}
private fun IrSimpleFunction.findAllReachableDeclarations() =
findAllReachableDeclarations(FunctionHandleForIrFunction(this)).map { it.irFunction }