Added type checks for special bridges (Collection, Map, List)
This commit is contained in:
+3
-3
@@ -118,20 +118,20 @@ internal class SpecialDeclarationsFactory(val context: Context) {
|
||||
val returnType = when (bridgeDirections[0]) {
|
||||
BridgeDirection.TO_VALUE_TYPE -> descriptor.returnType!!
|
||||
BridgeDirection.NOT_NEEDED -> descriptor.returnType
|
||||
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.anyType
|
||||
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.nullableAnyType
|
||||
}
|
||||
|
||||
val extensionReceiverType = when (bridgeDirections[1]) {
|
||||
BridgeDirection.TO_VALUE_TYPE -> descriptor.extensionReceiverParameter!!.type
|
||||
BridgeDirection.NOT_NEEDED -> descriptor.extensionReceiverParameter?.type
|
||||
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.anyType
|
||||
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.nullableAnyType
|
||||
}
|
||||
|
||||
val valueParameters = descriptor.valueParameters.mapIndexed { index, valueParameterDescriptor ->
|
||||
val outType = when (bridgeDirections[index + 2]) {
|
||||
BridgeDirection.TO_VALUE_TYPE -> valueParameterDescriptor.type
|
||||
BridgeDirection.NOT_NEEDED -> valueParameterDescriptor.type
|
||||
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.anyType
|
||||
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.nullableAnyType
|
||||
}
|
||||
ValueParameterDescriptorImpl(
|
||||
containingDeclaration = valueParameterDescriptor.containingDeclaration,
|
||||
|
||||
+10
-1
@@ -86,4 +86,13 @@ tailrec fun KotlinType.notNullableIsRepresentedAs(valueType: ValueType): Boolean
|
||||
return firstSupertype.notNullableIsRepresentedAs(valueType)
|
||||
}
|
||||
|
||||
internal fun KotlinType.isValueType() = ValueType.values().any { this.isRepresentedAs(it) }
|
||||
fun KotlinType.isValueType() = ValueType.values().any { this.isRepresentedAs(it) }
|
||||
|
||||
/**
|
||||
* @return the [ValueType] given type represented in generated code as,
|
||||
* or `null` if represented as object reference.
|
||||
*/
|
||||
val KotlinType.correspondingValueType: ValueType?
|
||||
get() = ValueType.values().firstOrNull {
|
||||
isRepresentedAs(it)
|
||||
}
|
||||
|
||||
+3
-16
@@ -19,11 +19,8 @@ package org.jetbrains.kotlin.backend.konan.lower
|
||||
import org.jetbrains.kotlin.backend.common.AbstractValueUsageTransformer
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.isSuspend
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.ValueType
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.backend.konan.notNullableIsRepresentedAs
|
||||
import org.jetbrains.kotlin.backend.konan.isRepresentedAs
|
||||
import org.jetbrains.kotlin.backend.konan.util.atMostOne
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
@@ -116,16 +113,6 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the [ValueType] given type represented in generated code as,
|
||||
* or `null` if represented as object reference.
|
||||
*/
|
||||
private fun getValueType(type: KotlinType): ValueType? {
|
||||
return ValueType.values().firstOrNull {
|
||||
type.isRepresentedAs(it)
|
||||
}
|
||||
}
|
||||
|
||||
private var currentFunctionDescriptor: FunctionDescriptor? = null
|
||||
|
||||
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||
@@ -188,8 +175,8 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
|
||||
}
|
||||
|
||||
private fun IrExpression.adaptIfNecessary(actualType: KotlinType, expectedType: KotlinType): IrExpression {
|
||||
val actualValueType = getValueType(actualType)
|
||||
val expectedValueType = getValueType(expectedType)
|
||||
val actualValueType = actualType.correspondingValueType
|
||||
val expectedValueType = expectedType.correspondingValueType
|
||||
|
||||
return when {
|
||||
actualValueType == expectedValueType -> this
|
||||
|
||||
+84
-5
@@ -18,24 +18,29 @@ package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.backend.common.lower.irIfThen
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.ValueType
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
|
||||
import org.jetbrains.kotlin.ir.util.type
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPass {
|
||||
@@ -79,6 +84,19 @@ internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPa
|
||||
}
|
||||
|
||||
internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
|
||||
|
||||
private fun IrBuilderWithScope.returnIfBadType(value: IrExpression,
|
||||
type: KotlinType,
|
||||
returnValueOnFail: IrExpression)
|
||||
= irIfThen(irNotIs(value, type), irReturn(returnValueOnFail))
|
||||
|
||||
private fun IrBuilderWithScope.irConst(value: Any?) = when (value) {
|
||||
null -> irNull()
|
||||
is Int -> irInt(value)
|
||||
is Boolean -> if (value) irTrue() else irFalse()
|
||||
else -> TODO()
|
||||
}
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
val functions = mutableSetOf<FunctionDescriptor?>()
|
||||
irClass.declarations.forEach {
|
||||
@@ -93,6 +111,7 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
|
||||
|
||||
irClass.descriptor.contributedMethods.forEach { functions.add(it) }
|
||||
|
||||
val builtBridges = mutableSetOf<FunctionDescriptor>()
|
||||
functions.filterNotNull()
|
||||
.filterNot { it.modality == Modality.ABSTRACT }
|
||||
.forEach { function ->
|
||||
@@ -104,17 +123,76 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
|
||||
.distinctBy { it.bridgeDirections }
|
||||
.forEach {
|
||||
buildBridge(it, irClass)
|
||||
builtBridges += it.descriptor
|
||||
}
|
||||
}
|
||||
irClass.transformChildrenVoid(object: IrElementTransformerVoid() {
|
||||
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||
declaration.transformChildrenVoid(this)
|
||||
|
||||
val descriptor = declaration.descriptor
|
||||
val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor)
|
||||
if (typeSafeBarrierDescription == null || builtBridges.contains(descriptor))
|
||||
return declaration
|
||||
|
||||
val body = declaration.body as? IrBlockBody
|
||||
?: return declaration
|
||||
val irBuilder = context.createIrBuilder(declaration.symbol, declaration.startOffset, declaration.endOffset)
|
||||
declaration.body = irBuilder.irBlockBody(declaration) {
|
||||
val valueParameters = declaration.valueParameters
|
||||
for (i in valueParameters.indices) {
|
||||
if (!typeSafeBarrierDescription.checkParameter(i))
|
||||
continue
|
||||
val type = valueParameters[i].type
|
||||
if (type != context.builtIns.nullableAnyType) {
|
||||
+returnIfBadType(irGet(valueParameters[i].symbol), type,
|
||||
if (typeSafeBarrierDescription == BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT)
|
||||
irGet(valueParameters[2].symbol)
|
||||
else irConst(typeSafeBarrierDescription.defaultValue)
|
||||
)
|
||||
}
|
||||
body.statements.forEach { +it }
|
||||
}
|
||||
}
|
||||
return declaration
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private object DECLARATION_ORIGIN_BRIDGE_METHOD :
|
||||
IrDeclarationOriginImpl("BRIDGE_METHOD")
|
||||
|
||||
private val ValueType.shortName
|
||||
get() = this.classFqName.shortName()
|
||||
|
||||
private fun getBoxType(valueType: ValueType) =
|
||||
context.builtIns.getKonanInternalClass("${valueType.shortName}Box").defaultType
|
||||
|
||||
private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) {
|
||||
val bridgeDescriptor = context.specialDeclarationsFactory.getBridgeDescriptor(descriptor)
|
||||
val target = descriptor.descriptor.target
|
||||
|
||||
val statements = mutableListOf<IrExpression>()
|
||||
val irBuilder = context.createIrBuilder(bridgeDescriptor, irClass.startOffset, irClass.endOffset)
|
||||
irBuilder.run {
|
||||
val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor.overriddenDescriptor)
|
||||
if (typeSafeBarrierDescription != null) {
|
||||
val valueParameters = bridgeDescriptor.valueParameters
|
||||
for (i in valueParameters.indices) {
|
||||
if (!typeSafeBarrierDescription.checkParameter(i))
|
||||
continue
|
||||
val type = target.valueParameters[i].type
|
||||
if (type != context.builtIns.nullableAnyType) {
|
||||
statements += returnIfBadType(irGet(valueParameters[i]), type,
|
||||
if (typeSafeBarrierDescription == BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT)
|
||||
irGet(valueParameters[2])
|
||||
else irConst(typeSafeBarrierDescription.defaultValue)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val delegatingCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, target,
|
||||
superQualifierDescriptor = target.containingDeclaration as ClassDescriptor /* Call non-virtually */
|
||||
).apply {
|
||||
@@ -133,9 +211,10 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
|
||||
IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, bridgeDescriptor, delegatingCall)
|
||||
else
|
||||
delegatingCall
|
||||
statements += bridgeBody
|
||||
irClass.declarations.add(
|
||||
IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, DECLARATION_ORIGIN_BRIDGE_METHOD,
|
||||
bridgeDescriptor, IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, listOf(bridgeBody))
|
||||
bridgeDescriptor, IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, statements)
|
||||
).apply { createParameterDeclarations() }
|
||||
)
|
||||
}
|
||||
|
||||
+2
@@ -55,6 +55,8 @@ fun IrBuilderWithScope.irContinue(loop: IrLoop) =
|
||||
|
||||
fun IrBuilderWithScope.irTrue() = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType, true)
|
||||
|
||||
fun IrBuilderWithScope.irFalse() = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType, false)
|
||||
|
||||
@Deprecated("Creates unbound symbol")
|
||||
fun IrBuilderWithScope.irGet(value: ValueDescriptor) =
|
||||
IrGetValueImpl(startOffset, endOffset, value)
|
||||
|
||||
Reference in New Issue
Block a user