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]) {
|
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,
|
||||||
|
|||||||
+10
-1
@@ -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)
|
||||||
|
}
|
||||||
|
|||||||
+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.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
|
||||||
|
|||||||
+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.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() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user