Added type checks for special bridges (Collection, Map, List)

This commit is contained in:
Igor Chevdar
2017-05-22 19:32:59 +03:00
parent d1e248b8c3
commit 63e5aaecba
5 changed files with 102 additions and 25 deletions
@@ -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,
@@ -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)
}
@@ -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
@@ -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() }
)
}
@@ -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)