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]) { val returnType = when (bridgeDirections[0]) {
BridgeDirection.TO_VALUE_TYPE -> descriptor.returnType!! BridgeDirection.TO_VALUE_TYPE -> descriptor.returnType!!
BridgeDirection.NOT_NEEDED -> 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]) { val extensionReceiverType = when (bridgeDirections[1]) {
BridgeDirection.TO_VALUE_TYPE -> descriptor.extensionReceiverParameter!!.type BridgeDirection.TO_VALUE_TYPE -> descriptor.extensionReceiverParameter!!.type
BridgeDirection.NOT_NEEDED -> 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 valueParameters = descriptor.valueParameters.mapIndexed { index, valueParameterDescriptor ->
val outType = when (bridgeDirections[index + 2]) { val outType = when (bridgeDirections[index + 2]) {
BridgeDirection.TO_VALUE_TYPE -> valueParameterDescriptor.type BridgeDirection.TO_VALUE_TYPE -> valueParameterDescriptor.type
BridgeDirection.NOT_NEEDED -> valueParameterDescriptor.type BridgeDirection.NOT_NEEDED -> valueParameterDescriptor.type
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.anyType BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.nullableAnyType
} }
ValueParameterDescriptorImpl( ValueParameterDescriptorImpl(
containingDeclaration = valueParameterDescriptor.containingDeclaration, containingDeclaration = valueParameterDescriptor.containingDeclaration,
@@ -86,4 +86,13 @@ tailrec fun KotlinType.notNullableIsRepresentedAs(valueType: ValueType): Boolean
return firstSupertype.notNullableIsRepresentedAs(valueType) 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.AbstractValueUsageTransformer
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.isSuspend import org.jetbrains.kotlin.backend.common.descriptors.isSuspend
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.descriptors.* 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.backend.konan.util.atMostOne
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrStatement 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 private var currentFunctionDescriptor: FunctionDescriptor? = null
override fun visitFunction(declaration: IrFunction): IrStatement { 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 { private fun IrExpression.adaptIfNecessary(actualType: KotlinType, expectedType: KotlinType): IrExpression {
val actualValueType = getValueType(actualType) val actualValueType = actualType.correspondingValueType
val expectedValueType = getValueType(expectedType) val expectedValueType = expectedType.correspondingValueType
return when { return when {
actualValueType == expectedValueType -> this 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.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.ClassLoweringPass 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.Context
import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET 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.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.*
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.util.createParameterDeclarations 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.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
internal class DirectBridgesCallsLowering(val context: Context) : BodyLoweringPass { 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 { 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) { override fun lower(irClass: IrClass) {
val functions = mutableSetOf<FunctionDescriptor?>() val functions = mutableSetOf<FunctionDescriptor?>()
irClass.declarations.forEach { irClass.declarations.forEach {
@@ -93,6 +111,7 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
irClass.descriptor.contributedMethods.forEach { functions.add(it) } irClass.descriptor.contributedMethods.forEach { functions.add(it) }
val builtBridges = mutableSetOf<FunctionDescriptor>()
functions.filterNotNull() functions.filterNotNull()
.filterNot { it.modality == Modality.ABSTRACT } .filterNot { it.modality == Modality.ABSTRACT }
.forEach { function -> .forEach { function ->
@@ -104,17 +123,76 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
.distinctBy { it.bridgeDirections } .distinctBy { it.bridgeDirections }
.forEach { .forEach {
buildBridge(it, irClass) 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 : private object DECLARATION_ORIGIN_BRIDGE_METHOD :
IrDeclarationOriginImpl("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) { private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) {
val bridgeDescriptor = context.specialDeclarationsFactory.getBridgeDescriptor(descriptor) val bridgeDescriptor = context.specialDeclarationsFactory.getBridgeDescriptor(descriptor)
val target = descriptor.descriptor.target 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, val delegatingCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, target,
superQualifierDescriptor = target.containingDeclaration as ClassDescriptor /* Call non-virtually */ superQualifierDescriptor = target.containingDeclaration as ClassDescriptor /* Call non-virtually */
).apply { ).apply {
@@ -133,9 +211,10 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, bridgeDescriptor, delegatingCall) IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, bridgeDescriptor, delegatingCall)
else else
delegatingCall delegatingCall
statements += bridgeBody
irClass.declarations.add( irClass.declarations.add(
IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, DECLARATION_ORIGIN_BRIDGE_METHOD, 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() } ).apply { createParameterDeclarations() }
) )
} }
@@ -55,6 +55,8 @@ fun IrBuilderWithScope.irContinue(loop: IrLoop) =
fun IrBuilderWithScope.irTrue() = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType, true) 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") @Deprecated("Creates unbound symbol")
fun IrBuilderWithScope.irGet(value: ValueDescriptor) = fun IrBuilderWithScope.irGet(value: ValueDescriptor) =
IrGetValueImpl(startOffset, endOffset, value) IrGetValueImpl(startOffset, endOffset, value)