Migrate compiler to IR types

This commit is contained in:
Svyatoslav Scherbina
2018-04-26 17:37:49 +03:00
committed by SvyatoslavScherbina
parent fd016db33a
commit 9bbecf33d2
63 changed files with 2543 additions and 2818 deletions
@@ -16,17 +16,21 @@
package org.jetbrains.kotlin.backend.common
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.declarations.getDefault
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType
/**
@@ -40,45 +44,64 @@ import org.jetbrains.kotlin.types.KotlinType
*
* TODO: consider making this visitor non-recursive to make it more general.
*/
abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrElementTransformerVoid() {
internal abstract class AbstractValueUsageTransformer(
val builtIns: KotlinBuiltIns,
val symbols: KonanSymbols,
val irBuiltIns: IrBuiltIns
): IrElementTransformerVoid() {
protected open fun IrExpression.useAs(type: KotlinType): IrExpression = this
protected open fun IrExpression.useAs(type: IrType): IrExpression = this
protected open fun IrExpression.useAsStatement(): IrExpression = this
protected open fun IrExpression.useInTypeOperator(operator: IrTypeOperator, typeOperand: KotlinType): IrExpression =
protected open fun IrExpression.useInTypeOperator(operator: IrTypeOperator, typeOperand: IrType): IrExpression =
this
protected open fun IrExpression.useAsValue(value: ValueDescriptor): IrExpression = this.useAs(value.type)
protected open fun IrExpression.useAsValue(value: IrValueDeclaration): IrExpression = this.useAs(value.type)
protected open fun IrExpression.useAsArgument(parameter: ParameterDescriptor): IrExpression =
this.useAsValue(parameter)
protected open fun IrExpression.useAsDispatchReceiver(expression: IrMemberAccessExpression): IrExpression =
this.useAsArgument(expression.descriptor.dispatchReceiverParameter!!)
protected open fun IrExpression.useAsDispatchReceiver(expression: IrFunctionAccessExpression): IrExpression =
this.useAsArgument(expression.symbol.owner.dispatchReceiverParameter!!)
protected open fun IrExpression.useAsExtensionReceiver(expression: IrMemberAccessExpression): IrExpression =
this.useAsArgument(expression.descriptor.extensionReceiverParameter!!)
protected open fun IrExpression.useAsExtensionReceiver(expression: IrFunctionAccessExpression): IrExpression =
this.useAsArgument(expression.symbol.owner.extensionReceiverParameter!!)
protected open fun IrExpression.useAsValueArgument(expression: IrMemberAccessExpression,
protected open fun IrExpression.useAsValueArgument(expression: IrFunctionAccessExpression,
parameter: ValueParameterDescriptor): IrExpression =
this.useAsArgument(parameter)
protected open fun IrExpression.useForVariable(variable: VariableDescriptor): IrExpression =
private fun IrExpression.useForVariable(variable: VariableDescriptor): IrExpression =
this.useAsValue(variable)
protected open fun IrExpression.useForField(field: PropertyDescriptor): IrExpression =
this.useForVariable(field)
private fun IrExpression.useForField(field: IrField): IrExpression =
this.useAs(field.type)
protected open fun IrExpression.useAsReturnValue(returnTarget: CallableDescriptor): IrExpression {
val returnType = returnTarget.returnType ?: return this
return this.useAs(returnType)
}
protected open fun IrExpression.useAsReturnValue(returnTarget: IrReturnTargetSymbol): IrExpression =
when (returnTarget) {
is IrSimpleFunctionSymbol -> this.useAs(returnTarget.owner.returnType)
is IrConstructorSymbol -> this.useAs(irBuiltIns.unitType)
is IrReturnableBlockSymbol -> this.useAs(returnTarget.owner.type)
else -> error(returnTarget)
}
protected open fun IrExpression.useAsResult(enclosing: IrExpression): IrExpression =
this.useAs(enclosing.type)
override fun visitMemberAccess(expression: IrMemberAccessExpression): IrExpression {
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
TODO()
}
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression {
TODO()
}
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
TODO()
}
override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression {
expression.transformChildrenVoid(this)
with(expression) {
@@ -86,7 +109,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
extensionReceiver = extensionReceiver?.useAsExtensionReceiver(expression)
for (index in descriptor.valueParameters.indices) {
val argument = getValueArgument(index) ?: continue
val parameter = descriptor.valueParameters[index]
val parameter = symbol.owner.valueParameters[index]
putValueArgument(index, argument.useAsValueArgument(expression, parameter))
}
}
@@ -130,7 +153,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid(this)
expression.value = expression.value.useAsReturnValue(expression.returnTarget)
expression.value = expression.value.useAsReturnValue(expression.returnTargetSymbol)
return expression
}
@@ -138,7 +161,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
override fun visitSetVariable(expression: IrSetVariable): IrExpression {
expression.transformChildrenVoid(this)
expression.value = expression.value.useForVariable(expression.descriptor)
expression.value = expression.value.useForVariable(expression.symbol.owner)
return expression
}
@@ -146,7 +169,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
override fun visitSetField(expression: IrSetField): IrExpression {
expression.transformChildrenVoid(this)
expression.value = expression.value.useForField(expression.descriptor)
expression.value = expression.value.useForField(expression.symbol.owner)
return expression
}
@@ -155,7 +178,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
declaration.transformChildrenVoid(this)
declaration.initializer?.let {
it.expression = it.expression.useForField(declaration.descriptor)
it.expression = it.expression.useForField(declaration)
}
return declaration
@@ -164,7 +187,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
override fun visitVariable(declaration: IrVariable): IrVariable {
declaration.transformChildrenVoid(this)
declaration.initializer = declaration.initializer?.useForVariable(declaration.descriptor)
declaration.initializer = declaration.initializer?.useForVariable(declaration)
return declaration
}
@@ -173,7 +196,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
expression.transformChildrenVoid(this)
for (irBranch in expression.branches) {
irBranch.condition = irBranch.condition.useAs(builtIns.booleanType)
irBranch.condition = irBranch.condition.useAs(irBuiltIns.booleanType)
irBranch.result = irBranch.result.useAsResult(expression)
}
@@ -183,7 +206,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
override fun visitLoop(loop: IrLoop): IrExpression {
loop.transformChildrenVoid(this)
loop.condition = loop.condition.useAs(builtIns.booleanType)
loop.condition = loop.condition.useAs(irBuiltIns.booleanType)
loop.body = loop.body?.useAsStatement()
@@ -193,7 +216,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
override fun visitThrow(expression: IrThrow): IrExpression {
expression.transformChildrenVoid(this)
expression.value = expression.value.useAs(builtIns.throwable.defaultType)
expression.value = expression.value.useAs(symbols.throwable.owner.defaultType)
return expression
}
@@ -238,8 +261,8 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
override fun visitFunction(declaration: IrFunction): IrStatement {
declaration.transformChildrenVoid(this)
declaration.descriptor.valueParameters.forEach { parameter ->
val defaultValue = declaration.getDefault(parameter)
declaration.valueParameters.forEach { parameter ->
val defaultValue = parameter.defaultValue
if (defaultValue is IrExpressionBody) {
defaultValue.expression = defaultValue.expression.useAsArgument(parameter)
}
@@ -247,7 +270,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
declaration.body?.let {
if (it is IrExpressionBody) {
it.expression = it.expression.useAsReturnValue(declaration.descriptor)
it.expression = it.expression.useAsReturnValue(declaration.symbol)
}
}
@@ -21,6 +21,7 @@ import llvm.*
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.getPropertyGetter
import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -29,6 +30,9 @@ import org.jetbrains.kotlin.types.KotlinType
internal fun KonanSymbols.getTypeConversion(actualType: KotlinType, expectedType: KotlinType) =
getTypeConversion(actualType.correspondingValueType, expectedType.correspondingValueType)
internal fun KonanSymbols.getTypeConversion(actualType: IrType, expectedType: IrType) =
getTypeConversion(actualType.correspondingValueType, expectedType.correspondingValueType)
internal fun KonanSymbols.getTypeConversion(
actualValueType: ValueType?,
expectedValueType: ValueType?
@@ -18,18 +18,16 @@ package org.jetbrains.kotlin.backend.konan
import llvm.LLVMDumpModule
import llvm.LLVMModuleRef
import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor
import org.jetbrains.kotlin.backend.common.ReflectionTypes
import org.jetbrains.kotlin.backend.common.validateIrModule
import org.jetbrains.kotlin.backend.jvm.descriptors.initialize
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor
import org.jetbrains.kotlin.backend.common.descriptors.DescriptorsFactory
import org.jetbrains.kotlin.backend.konan.ir.KonanIr
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryWriter
import org.jetbrains.kotlin.backend.konan.library.LinkData
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_BRIDGE_METHOD
import org.jetbrains.kotlin.backend.konan.lower.bridgeTarget
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -42,23 +40,23 @@ import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.endOffsetOrUndefined
import org.jetbrains.kotlin.ir.util.startOffsetOrUndefined
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
import org.jetbrains.kotlin.metadata.KonanLinkData
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.types.KotlinType
import java.lang.System.out
import kotlin.LazyThreadSafetyMode.PUBLICATION
@@ -66,72 +64,49 @@ internal class SpecialDeclarationsFactory(val context: Context) {
private val enumSpecialDeclarationsFactory by lazy { EnumSpecialDeclarationsFactory(context) }
private val outerThisFields = mutableMapOf<ClassDescriptor, IrField>()
private val bridgesDescriptors = mutableMapOf<Pair<IrSimpleFunction, BridgeDirections>, IrSimpleFunction>()
private val loweredEnums = mutableMapOf<ClassDescriptor, LoweredEnum>()
private val ordinals = mutableMapOf<IrClass, Map<ClassDescriptor, Int>>()
private val loweredEnums = mutableMapOf<IrClass, LoweredEnum>()
private val ordinals = mutableMapOf<ClassDescriptor, Map<ClassDescriptor, Int>>()
object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS :
IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS")
fun getOuterThisField(innerClassDescriptor: ClassDescriptor): IrField =
if (!innerClassDescriptor.isInner) throw AssertionError("Class is not inner: $innerClassDescriptor")
else outerThisFields.getOrPut(innerClassDescriptor) {
val outerClassDescriptor = DescriptorUtils.getContainingClass(innerClassDescriptor) ?:
throw AssertionError("No containing class for inner class $innerClassDescriptor")
fun getOuterThisField(innerClass: IrClass): IrField =
if (!innerClass.descriptor.isInner) throw AssertionError("Class is not inner: ${innerClass.descriptor}")
else outerThisFields.getOrPut(innerClass.descriptor) {
val outerClass = innerClass.parent as? IrClass
?: throw AssertionError("No containing class for inner class ${innerClass.descriptor}")
val receiver = ReceiverParameterDescriptorImpl(innerClassDescriptor, ImplicitClassReceiver(innerClassDescriptor))
val receiver = ReceiverParameterDescriptorImpl(innerClass.descriptor, ImplicitClassReceiver(innerClass.descriptor))
val descriptor = PropertyDescriptorImpl.create(
innerClassDescriptor, Annotations.EMPTY, Modality.FINAL,
innerClass.descriptor, Annotations.EMPTY, Modality.FINAL,
Visibilities.PRIVATE, false, "this$0".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE, false, false, false, false, false, false
).initialize(outerClassDescriptor.defaultType, dispatchReceiverParameter = receiver)
).apply {
val receiverType: KotlinType? = null
this.setType(outerClass.descriptor.defaultType, emptyList(), receiver, receiverType)
initialize(null, null)
}
IrFieldImpl(
innerClassDescriptor.startOffsetOrUndefined,
innerClassDescriptor.endOffsetOrUndefined,
innerClass.descriptor.startOffsetOrUndefined,
innerClass.descriptor.endOffsetOrUndefined,
DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS,
descriptor
descriptor,
outerClass.defaultType
)
}
fun getBridgeDescriptor(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): IrSimpleFunction {
val irFunction = overriddenFunctionDescriptor.descriptor
val descriptor = irFunction.descriptor
assert(overriddenFunctionDescriptor.needBridge,
{ "Function $descriptor is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor.descriptor}" })
val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections
return bridgesDescriptors.getOrPut(irFunction to bridgeDirections) {
val bridgeDescriptor = SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ descriptor.containingDeclaration,
/* annotations = */ Annotations.EMPTY,
/* name = */ "<bridge-$bridgeDirections>${irFunction.functionName}".synthesizedName,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE).apply {
initializeBridgeDescriptor(this, descriptor, bridgeDirections.array)
}
IrFunctionImpl(
irFunction.startOffset,
irFunction.endOffset,
DECLARATION_ORIGIN_BRIDGE_METHOD(irFunction),
bridgeDescriptor
).apply {
createParameterDeclarations()
this.parent = overriddenFunctionDescriptor.descriptor.parent
}
fun getLoweredEnum(enumClass: IrClass): LoweredEnum {
assert(enumClass.kind == ClassKind.ENUM_CLASS, { "Expected enum class but was: ${enumClass.descriptor}" })
return loweredEnums.getOrPut(enumClass) {
enumSpecialDeclarationsFactory.createLoweredEnum(enumClass)
}
}
fun getLoweredEnum(enumClassDescriptor: ClassDescriptor): LoweredEnum {
assert(enumClassDescriptor.kind == ClassKind.ENUM_CLASS, { "Expected enum class but was: $enumClassDescriptor" })
return loweredEnums.getOrPut(enumClassDescriptor) {
enumSpecialDeclarationsFactory.createLoweredEnum(enumClassDescriptor)
}
}
private fun assignOrdinalsToEnumEntries(irClass: IrClass): Map<ClassDescriptor, Int> {
private fun assignOrdinalsToEnumEntries(classDescriptor: ClassDescriptor): Map<ClassDescriptor, Int> {
val enumEntryOrdinals = mutableMapOf<ClassDescriptor, Int>()
irClass.declarations.filterIsInstance<IrEnumEntry>().forEachIndexed { index, entry ->
enumEntryOrdinals[entry.descriptor] = index
classDescriptor.enumEntries.forEachIndexed { index, entry ->
enumEntryOrdinals[entry] = index
}
return enumEntryOrdinals
}
@@ -145,54 +120,130 @@ internal class SpecialDeclarationsFactory(val context: Context) {
.first { entryDescriptor.name == enumClassDescriptor.c.nameResolver.getName(it.name) }
.getExtension(KonanLinkData.enumEntryOrdinal)
}
val enumClass = context.ir.getEnum(enumClassDescriptor)
return ordinals.getOrPut(enumClass) { assignOrdinalsToEnumEntries(enumClass) }[entryDescriptor]!!
return ordinals.getOrPut(enumClassDescriptor) { assignOrdinalsToEnumEntries(enumClassDescriptor) }[entryDescriptor]!!
}
private fun initializeBridgeDescriptor(bridgeDescriptor: SimpleFunctionDescriptorImpl,
descriptor: FunctionDescriptor,
bridgeDirections: Array<BridgeDirection>) {
val returnType = when (bridgeDirections[0]) {
BridgeDirection.TO_VALUE_TYPE -> descriptor.returnType!!
BridgeDirection.NOT_NEEDED -> descriptor.returnType
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.nullableAnyType
fun getBridge(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): IrSimpleFunction {
val irFunction = overriddenFunctionDescriptor.descriptor
assert(overriddenFunctionDescriptor.needBridge,
{ "Function ${irFunction.descriptor} is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor.descriptor}" })
val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections
return bridgesDescriptors.getOrPut(irFunction to bridgeDirections) {
createBridge(irFunction, bridgeDirections)
}
}
private fun createBridge(function: IrFunction, bridgeDirections: BridgeDirections): IrFunctionImpl {
val returnType = when (bridgeDirections.array[0]) {
BridgeDirection.TO_VALUE_TYPE,
BridgeDirection.NOT_NEEDED -> function.returnType
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType
}
val extensionReceiverType = when (bridgeDirections[1]) {
BridgeDirection.TO_VALUE_TYPE -> descriptor.extensionReceiverParameter!!.type
BridgeDirection.NOT_NEEDED -> descriptor.extensionReceiverParameter?.type
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.nullableAnyType
val extensionReceiverType = when (bridgeDirections.array[1]) {
BridgeDirection.TO_VALUE_TYPE -> function.extensionReceiverParameter!!.type
BridgeDirection.NOT_NEEDED -> function.extensionReceiverParameter?.type
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType
}
val valueParameterTypes = function.valueParameters.mapIndexed { index, valueParameter ->
when (bridgeDirections.array[index + 2]) {
BridgeDirection.TO_VALUE_TYPE -> valueParameter.type
BridgeDirection.NOT_NEEDED -> valueParameter.type
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType
}
}
val bridgeDescriptor = createBridgeDescriptor(
function,
bridgeDirections,
returnType,
extensionReceiverType,
valueParameterTypes
)
val bridge = IrFunctionImpl(
function.startOffset,
function.endOffset,
DECLARATION_ORIGIN_BRIDGE_METHOD(function),
bridgeDescriptor
).apply {
this.returnType = returnType
this.parent = function.parent
}
bridge.createDispatchReceiverParameter()
extensionReceiverType?.let {
val extensionReceiverParameter = function.extensionReceiverParameter!!
bridge.extensionReceiverParameter = IrValueParameterImpl(
extensionReceiverParameter.startOffset,
extensionReceiverParameter.endOffset,
extensionReceiverParameter.origin,
bridge.descriptor.extensionReceiverParameter!!,
it, null
)
}
function.valueParameters.mapIndexedTo(bridge.valueParameters) { index, valueParameter ->
val type = valueParameterTypes[index]
IrValueParameterImpl(
valueParameter.startOffset,
valueParameter.endOffset,
valueParameter.origin,
bridge.descriptor.valueParameters[index],
type, valueParameter.varargElementType
)
}
function.typeParameters.mapTo(bridge.typeParameters) {
IrTypeParameterImpl(it.startOffset, it.endOffset, it.origin, it.descriptor).apply {
superTypes += it.superTypes
}
}
return bridge
}
private fun createBridgeDescriptor(
function: IrFunction,
bridgeDirections: BridgeDirections,
returnType: IrType,
extensionReceiverType: IrType?,
valueParameterTypes: List<IrType>
): SimpleFunctionDescriptor {
val descriptor = function.descriptor
val bridgeDescriptor = SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ descriptor.containingDeclaration,
/* annotations = */ Annotations.EMPTY,
/* name = */ "<bridge-$bridgeDirections>${function.functionName}".synthesizedName,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE)
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.nullableAnyType
}
ValueParameterDescriptorImpl(
ValueParameterDescriptorImpl(
containingDeclaration = valueParameterDescriptor.containingDeclaration,
original = null,
index = index,
annotations = Annotations.EMPTY,
name = valueParameterDescriptor.name,
outType = outType,
declaresDefaultValue = valueParameterDescriptor.declaresDefaultValue(),
isCrossinline = valueParameterDescriptor.isCrossinline,
isNoinline = valueParameterDescriptor.isNoinline,
varargElementType = valueParameterDescriptor.varargElementType,
source = SourceElement.NO_SOURCE)
original = null,
index = index,
annotations = Annotations.EMPTY,
name = valueParameterDescriptor.name,
outType = valueParameterTypes[index].toKotlinType(),
declaresDefaultValue = valueParameterDescriptor.declaresDefaultValue(),
isCrossinline = valueParameterDescriptor.isCrossinline,
isNoinline = valueParameterDescriptor.isNoinline,
varargElementType = valueParameterDescriptor.varargElementType,
source = SourceElement.NO_SOURCE)
}
bridgeDescriptor.initialize(
/* receiverParameterType = */ extensionReceiverType,
/* receiverParameterType = */ extensionReceiverType?.toKotlinType(),
/* dispatchReceiverParameter = */ descriptor.dispatchReceiverParameter,
/* typeParameters = */ descriptor.typeParameters,
/* unsubstitutedValueParameters = */ valueParameters,
/* unsubstitutedReturnType = */ returnType,
/* unsubstitutedReturnType = */ returnType.toKotlinType(),
/* modality = */ descriptor.modality,
/* visibility = */ descriptor.visibility).apply {
isSuspend = descriptor.isSuspend
isSuspend = descriptor.isSuspend
}
return bridgeDescriptor
}
}
@@ -16,10 +16,10 @@
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.jvm.descriptors.initialize
import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.ir.createSimpleDelegatingConstructorDescriptor
import org.jetbrains.kotlin.backend.konan.descriptors.enumEntries
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.*
@@ -31,10 +31,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.replace
import org.jetbrains.kotlin.types.*
internal object DECLARATION_ORIGIN_ENUM :
@@ -48,36 +45,45 @@ internal data class LoweredEnum(val implObject: IrClass,
val entriesMap: Map<Name, Int>)
internal class EnumSpecialDeclarationsFactory(val context: Context) {
fun createLoweredEnum(enumClassDescriptor: ClassDescriptor): LoweredEnum {
fun createLoweredEnum(enumClass: IrClass): LoweredEnum {
val enumClassDescriptor = enumClass.descriptor
val startOffset = enumClassDescriptor.startOffsetOrUndefined
val endOffset = enumClassDescriptor.endOffsetOrUndefined
val startOffset = enumClass.startOffset
val endOffset = enumClass.endOffset
val implObjectDescriptor = ClassDescriptorImpl(enumClassDescriptor, "OBJECT".synthesizedName, Modality.FINAL,
ClassKind.OBJECT, listOf(context.builtIns.anyType), SourceElement.NO_SOURCE, false, LockBasedStorageManager.NO_LOCKS)
val implObject = IrClassImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, implObjectDescriptor).apply {
createParameterDeclarations()
}
val valuesProperty = createEnumValuesField(enumClassDescriptor, implObjectDescriptor)
val valuesField = IrFieldImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, valuesProperty)
val valuesType = context.ir.symbols.array.typeWith(enumClass.defaultType)
val valuesField = IrFieldImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, valuesProperty, valuesType)
val valuesGetterDescriptor = createValuesGetterDescriptor(enumClassDescriptor, implObjectDescriptor)
val valuesGetter = IrFunctionImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, valuesGetterDescriptor).apply {
createParameterDeclarations()
val valuesGetter = IrFunctionImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, valuesGetterDescriptor).also {
it.returnType = valuesType
it.parent = implObject
it.createDispatchReceiverParameter()
}
val memberScope = MemberScope.Empty
val constructorOfAny = context.builtIns.any.constructors.first()
val constructorOfAny = context.irBuiltIns.anyClass.owner.constructors.first()
// TODO: why primary?
val constructorDescriptor = implObjectDescriptor.createSimpleDelegatingConstructorDescriptor(constructorOfAny, true)
val constructor = implObject.addSimpleDelegatingConstructor(
constructorOfAny,
context.irBuiltIns,
DECLARATION_ORIGIN_ENUM,
true
)
val constructorDescriptor = constructor.descriptor
implObjectDescriptor.initialize(memberScope, setOf(constructorDescriptor), constructorDescriptor)
val implObject = IrClassImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, implObjectDescriptor).apply {
createParameterDeclarations()
addFakeOverrides()
setSuperSymbols(listOf(context.ir.symbols.any.owner))
}
implObject.parent = context.ir.getEnum(enumClassDescriptor)
valuesGetter.parent = implObject
implObject.setSuperSymbolsAndAddFakeOverrides(listOf(context.irBuiltIns.anyType))
implObject.parent = enumClass
valuesField.parent = implObject
val (itemGetterSymbol, itemGetterDescriptor) = getEnumItemGetter(enumClassDescriptor)
@@ -115,7 +121,12 @@ internal class EnumSpecialDeclarationsFactory(val context: Context) {
val receiver = ReceiverParameterDescriptorImpl(implObjectDescriptor, ImplicitClassReceiver(implObjectDescriptor))
return PropertyDescriptorImpl.create(implObjectDescriptor, Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC,
false, "VALUES".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE,
false, false, false, false, false, false).initialize(valuesArrayType, dispatchReceiverParameter = receiver)
false, false, false, false, false, false).apply {
val receiverType: KotlinType? = null
this.setType(valuesArrayType, emptyList(), receiver, receiverType)
this.initialize(null, null)
}
}
private val genericArrayType = context.ir.symbols.array.descriptor
@@ -79,7 +79,7 @@ fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironme
context.irModule = module
context.ir.symbols = symbols
validateIrModule(context, module)
// validateIrModule(context, module)
}
phaser.phase(KonanPhase.SERIALIZER) {
markBackingFields(context)
@@ -18,13 +18,9 @@ package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.referenceAllTypeExternalClassifiers
import org.jetbrains.kotlin.backend.konan.lower.*
import org.jetbrains.kotlin.backend.konan.lower.DefaultArgumentStubGenerator
import org.jetbrains.kotlin.backend.konan.lower.DefaultParameterInjector
import org.jetbrains.kotlin.backend.konan.lower.InitializersLowering
import org.jetbrains.kotlin.backend.konan.lower.LateinitLowering
import org.jetbrains.kotlin.backend.konan.lower.LocalDeclarationsLowering
import org.jetbrains.kotlin.backend.konan.lower.SharedVariablesLowering
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
@@ -83,12 +79,10 @@ internal class KonanLower(val context: Context) {
}
val symbolTable = context.ir.symbols.symbolTable
irModule.referenceAllTypeExternalClassifiers(symbolTable)
do {
@Suppress("DEPRECATION")
irModule.replaceUnboundSymbols(context)
irModule.referenceAllTypeExternalClassifiers(symbolTable)
} while (symbolTable.unboundClasses.isNotEmpty())
irModule.patchDeclarationParents()
@@ -17,7 +17,14 @@
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
/**
@@ -96,3 +103,69 @@ val KotlinType.correspondingValueType: ValueType?
get() = ValueType.values().firstOrNull {
isRepresentedAs(it)
}
//////
private fun IrType.isConstructedFromGivenClass(fqName: FqNameUnsafe) =
(this.classifierOrNull as? IrClassSymbol)?.descriptor?.fqNameSafe?.toUnsafe() == fqName
private val IrClassifierSymbol.ownerSuperTypes: List<IrType>
get() = when (this) {
is IrClassSymbol -> this.owner.superTypes
is IrTypeParameterSymbol -> this.owner.superTypes
else -> error(this)
}
/**
* @return `true` if this type must be represented as given value type in generated code.
*/
tailrec fun IrType.isRepresentedAs(valueType: ValueType): Boolean {
if (this !is IrSimpleType) {
return false
}
if (this.hasQuestionMark && !valueType.isNullable) {
return false
}
if (this.isConstructedFromGivenClass(valueType.classFqName)) {
return true
}
// Supertypes should be checked even for "final" value types (e.g. Int)
// to treat type parameter `T` with `Int` upper bound as value type.
// This behavior is observed on Kotlin JVM and used in interop implementation.
//
// However to optimize this method only first supertype is checked
// (it is supposed to be enough in all sane cases).
val firstSupertype = this.classifier.ownerSuperTypes.firstOrNull() ?: return false
return firstSupertype.isRepresentedAs(valueType)
}
/**
* @return `true` if this type without `null` value must be represented as given value type in generated code.
*
* TODO: this method can be considered as a hack; rework its usages.
*/
tailrec fun IrType.notNullableIsRepresentedAs(valueType: ValueType): Boolean {
if (this.isConstructedFromGivenClass(valueType.classFqName)) {
return true
}
// See comment in [isRepresentedAs].
val firstSupertype = this.classifierOrNull?.ownerSuperTypes?.firstOrNull() ?: return false
return firstSupertype.notNullableIsRepresentedAs(valueType)
}
fun IrType.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 IrType.correspondingValueType: ValueType?
get() = ValueType.values().firstOrNull {
isRepresentedAs(it)
}
@@ -61,7 +61,7 @@ internal class OverriddenFunctionDescriptor(
} else {
descriptor
}
context.specialDeclarationsFactory.getBridgeDescriptor(OverriddenFunctionDescriptor(bridgeOwner, overriddenDescriptor))
context.specialDeclarationsFactory.getBridge(OverriddenFunctionDescriptor(bridgeOwner, overriddenDescriptor))
}
return if (implementation.modality == Modality.ABSTRACT) null else implementation
}
@@ -21,9 +21,9 @@ import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.typeUtil.isUnit
/**
* List of all implemented interfaces (including those which implemented by a super class)
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.backend.konan.descriptors
import org.jetbrains.kotlin.backend.common.descriptors.SharedVariablesManager
import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
@@ -34,8 +35,8 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.types.*
internal class KonanSharedVariablesManager(val context: KonanBackendContext) : SharedVariablesManager {
@@ -55,7 +56,7 @@ internal class KonanSharedVariablesManager(val context: KonanBackendContext) : S
}
private fun refType(elementType: KotlinType): KotlinType {
return refClass.owner.defaultType.replace(listOf(TypeProjectionImpl(elementType)))
return refClass.descriptor.defaultType.replace(listOf(TypeProjectionImpl(elementType)))
}
private fun getElementPropertyDescriptor(sharedVariableDescriptor: VariableDescriptor): PropertyDescriptor {
@@ -74,18 +75,19 @@ internal class KonanSharedVariablesManager(val context: KonanBackendContext) : S
false, false, variableDescriptor.source
)
val valueType = originalDeclaration.descriptor.type
val refConstructorTypeArguments = mapOf(refClassConstructor.descriptor.typeParameters[0] to valueType)
val valueType = originalDeclaration.type
val refConstructorCall = IrCallImpl(
originalDeclaration.startOffset, originalDeclaration.endOffset,
refClassConstructor, refConstructor(valueType), refConstructorTypeArguments
)
refClass.typeWith(valueType),
refClassConstructor, refConstructor(valueType.toKotlinType()), 1
).apply {
putTypeArgument(0, valueType)
}
return IrVariableImpl(
originalDeclaration.startOffset, originalDeclaration.endOffset, originalDeclaration.origin,
sharedVariableDescriptor
sharedVariableDescriptor, refConstructorCall.type
).apply {
initializer = refConstructorCall
}
@@ -97,16 +99,18 @@ internal class KonanSharedVariablesManager(val context: KonanBackendContext) : S
val elementPropertyDescriptor = getElementPropertyDescriptor(sharedVariableDeclaration.descriptor)
val sharedVariableInitialization =
IrCallImpl(initializer.startOffset, initializer.endOffset, elementProperty.setter!!.symbol,
IrCallImpl(initializer.startOffset, initializer.endOffset,
context.irBuiltIns.unitType, elementProperty.setter!!.symbol,
elementPropertyDescriptor.setter!!)
sharedVariableInitialization.dispatchReceiver =
IrGetValueImpl(initializer.startOffset, initializer.endOffset, sharedVariableDeclaration.symbol)
IrGetValueImpl(initializer.startOffset, initializer.endOffset,
sharedVariableDeclaration.type, sharedVariableDeclaration.symbol)
sharedVariableInitialization.putValueArgument(0, initializer)
return IrCompositeImpl(
originalDeclaration.startOffset, originalDeclaration.endOffset, context.builtIns.unitType, null,
originalDeclaration.startOffset, originalDeclaration.endOffset, context.irBuiltIns.unitType, null,
listOf(sharedVariableDeclaration, sharedVariableInitialization)
)
}
@@ -115,18 +119,25 @@ internal class KonanSharedVariablesManager(val context: KonanBackendContext) : S
val elementPropertyDescriptor = getElementPropertyDescriptor(sharedVariableSymbol.descriptor)
return IrCallImpl(originalGet.startOffset, originalGet.endOffset, elementProperty.getter!!.symbol,
return IrCallImpl(originalGet.startOffset, originalGet.endOffset,
originalGet.type, elementProperty.getter!!.symbol,
elementPropertyDescriptor.getter!!).apply {
dispatchReceiver = IrGetValueImpl(originalGet.startOffset, originalGet.endOffset, sharedVariableSymbol)
dispatchReceiver = IrGetValueImpl(
originalGet.startOffset, originalGet.endOffset,
sharedVariableSymbol.owner.type, sharedVariableSymbol
)
}
}
override fun setSharedValue(sharedVariableSymbol: IrVariableSymbol, originalSet: IrSetVariable): IrExpression {
val elementPropertyDescriptor = getElementPropertyDescriptor(sharedVariableSymbol.descriptor)
return IrCallImpl(originalSet.startOffset, originalSet.endOffset, elementProperty.setter!!.symbol,
elementPropertyDescriptor.setter!!).apply {
dispatchReceiver = IrGetValueImpl(originalSet.startOffset, originalSet.endOffset, sharedVariableSymbol)
return IrCallImpl(originalSet.startOffset, originalSet.endOffset, context.irBuiltIns.unitType,
elementProperty.setter!!.symbol, elementPropertyDescriptor.setter!!).apply {
dispatchReceiver = IrGetValueImpl(
originalSet.startOffset, originalSet.endOffset,
sharedVariableSymbol.owner.type, sharedVariableSymbol
)
putValueArgument(0, originalSet.value)
}
}
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS
import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.descriptors.konanInternal
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith
import org.jetbrains.kotlin.backend.konan.llvm.findMainEntryPoint
import org.jetbrains.kotlin.backend.konan.lower.TestProcessor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
@@ -38,12 +39,19 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.translateErased
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
import org.jetbrains.kotlin.types.KotlinType
import kotlin.properties.Delegates
@@ -58,9 +66,6 @@ internal class KonanIr(context: Context, irModule: IrModuleFragment): Ir<Context
override var symbols: KonanSymbols by Delegates.notNull()
fun getClass(type: KotlinType): IrClass? =
(type.constructor.declarationDescriptor as? ClassDescriptor)?.let { get(it) }
fun get(descriptor: FunctionDescriptor): IrFunction {
return moduleIndexForCodegen.functions[descriptor]
?: symbols.symbolTable.referenceFunction(descriptor).owner
@@ -90,10 +95,35 @@ internal class KonanIr(context: Context, irModule: IrModuleFragment): Ir<Context
?: symbols.symbolTable.referenceEnumEntry(descriptor).owner
}
fun getEnum(descriptor: ClassDescriptor): IrClass {
assert(descriptor.kind == ClassKind.ENUM_CLASS)
return originalModuleIndex.classes[descriptor]
?: symbols.symbolTable.referenceClass(descriptor).owner
fun translateErased(type: KotlinType): IrSimpleType = symbols.symbolTable.translateErased(type)
fun translateBroken(type: KotlinType): IrType {
val declarationDescriptor = type.constructor.declarationDescriptor
return when (declarationDescriptor) {
is ClassDescriptor -> {
val classifier = IrClassSymbolImpl(declarationDescriptor)
val typeArguments = type.arguments.map {
if (it.isStarProjection) {
IrStarProjectionImpl
} else {
makeTypeProjection(translateBroken(it.type), it.projectionKind)
}
}
IrSimpleTypeImpl(
classifier,
type.isMarkedNullable,
typeArguments,
emptyList()
)
}
is TypeParameterDescriptor -> IrSimpleTypeImpl(
IrTypeParameterSymbolImpl(declarationDescriptor),
type.isMarkedNullable,
emptyList(),
emptyList()
)
else -> error(declarationDescriptor ?: "null")
}
}
}
@@ -105,6 +135,8 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
val throwable = symbolTable.referenceClass(builtIns.throwable)
val string = symbolTable.referenceClass(builtIns.string)
val enum = symbolTable.referenceClass(builtIns.enum)
val nativePtr = symbolTable.referenceClass(context.builtIns.nativePtr)
val nativePtrType = nativePtr.typeWith(arguments = emptyList())
val arrayList = symbolTable.referenceClass(getArrayListClassDescriptor(context))
@@ -225,19 +257,25 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
val getProgressionLast = context.getInternalFunctions("getProgressionLast")
.map { Pair(it.returnType, symbolTable.referenceSimpleFunction(it)) }.toMap()
val arrayContentToString = arrayTypes.associateBy({ it }, { findArrayExtension(it, "contentToString") })
val arrayContentHashCode = arrayTypes.associateBy({ it }, { findArrayExtension(it, "contentHashCode") })
val arrayContentToString = arrays.associateBy(
{ it },
{ findArrayExtension(it.descriptor, "contentToString") }
)
val arrayContentHashCode = arrays.associateBy(
{ it },
{ findArrayExtension(it.descriptor, "contentHashCode") }
)
fun findArrayExtension(type: KotlinType, name: String): IrSimpleFunctionSymbol {
val descriptor = builtInsPackage("kotlin", "collections")
fun findArrayExtension(descriptor: ClassDescriptor, name: String): IrSimpleFunctionSymbol {
val functionDescriptor = builtInsPackage("kotlin", "collections")
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND)
.singleOrNull {
it.valueParameters.isEmpty()
&& (it.extensionReceiverParameter?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.defaultType == type
&& it.extensionReceiverParameter?.type?.constructor?.declarationDescriptor == descriptor
&& !it.isExpect
}
?: throw Error(type.toString())
return symbolTable.referenceSimpleFunction(descriptor)
?: throw Error(descriptor.toString())
return symbolTable.referenceSimpleFunction(functionDescriptor)
}
override val copyRangeTo = arrays.map { symbol ->
@@ -340,6 +378,11 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
val kFunctions = (0 .. KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS)
.map { symbolTable.referenceClass(context.reflectionTypes.getKFunction(it)) }
fun getKFunctionType(returnType: IrType, parameterTypes: List<IrType>): IrType {
val kFunctionClassSymbol = kFunctions[parameterTypes.size]
return kFunctionClassSymbol.typeWith(parameterTypes + returnType)
}
val suspendFunctions = (0 .. KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS)
.map { symbolTable.referenceClass(builtIns.getSuspendFunction(it)) }
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.konan.file.File
@@ -148,7 +149,7 @@ interface IrSuspendableExpression : IrExpression {
var result: IrExpression
}
class IrSuspensionPointImpl(startOffset: Int, endOffset: Int, type: KotlinType,
class IrSuspensionPointImpl(startOffset: Int, endOffset: Int, type: IrType,
override var suspensionPointIdParameter: IrVariable,
override var result: IrExpression,
override var resumeResult: IrExpression)
@@ -170,7 +171,7 @@ class IrSuspensionPointImpl(startOffset: Int, endOffset: Int, type: KotlinType,
}
}
class IrSuspendableExpressionImpl(startOffset: Int, endOffset: Int, type: KotlinType,
class IrSuspendableExpressionImpl(startOffset: Int, endOffset: Int, type: IrType,
override var suspensionPointId: IrExpression, override var result: IrExpression)
: IrExpressionBase(startOffset, endOffset, type), IrSuspendableExpression {
@@ -198,7 +199,7 @@ internal interface IrPrivateFunctionCall : IrCall {
internal class IrPrivateFunctionCallImpl(startOffset: Int,
endOffset: Int,
type: KotlinType,
type: IrType,
override val symbol: IrFunctionSymbol,
override val descriptor: FunctionDescriptor,
override val virtualCallee: IrCall?,
@@ -235,9 +236,9 @@ internal interface IrPrivateClassReference : IrClassReference {
internal class IrPrivateClassReferenceImpl(startOffset: Int,
endOffset: Int,
type: KotlinType,
type: IrType,
symbol: IrClassifierSymbol,
override val classType: KotlinType,
override val classType: IrType,
override val moduleDescriptor: ModuleDescriptor,
override val totalClasses: Int,
override val classIndex: Int,
@@ -18,23 +18,16 @@ package org.jetbrains.kotlin.backend.konan.irasdescriptors
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.llvm.llvmSymbolOrigin
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.idea.MainFunctionDetector
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.module
// This file contains some IR utilities which actually use descriptors.
// TODO: port this code to IR.
internal val IrDeclaration.annotations get() = this.descriptor.annotations
internal val IrDeclaration.isAnonymousObject get() = DescriptorUtils.isAnonymousObject(this.descriptor)
internal val IrFunction.isExternal get() = this.descriptor.isExternal
internal val IrDeclaration.isLocal get() = DescriptorUtils.isLocal(this.descriptor)
@@ -59,9 +52,5 @@ internal val IrDeclaration.llvmSymbolOrigin get() = this.descriptor.llvmSymbolOr
internal fun IrFunction.isMain() = MainFunctionDetector.isMain(this.descriptor)
internal fun IrTypeOperatorCall.getTypeOperandClass(context: Context): IrClass? =
context.ir.getClass(this.typeOperand)
internal fun IrCatch.getCatchParameterTypeClass(context: Context): IrClass? =
context.ir.getClass(this.catchParameter.type)
internal fun IrType.isObjCObjectType() = this.toKotlinType().isObjCObjectType()
@@ -27,5 +27,7 @@ internal typealias ConstructorDescriptor = IrConstructor
internal typealias ClassConstructorDescriptor = IrConstructor
internal typealias PackageFragmentDescriptor = IrPackageFragment
internal typealias VariableDescriptor = IrVariable
internal typealias ValueDescriptor = IrSymbolDeclaration<IrValueSymbol>
internal typealias ValueDescriptor = IrValueDeclaration
internal typealias ParameterDescriptor = IrValueParameter
internal typealias ValueParameterDescriptor = IrValueParameter
internal typealias TypeParameterDescriptor = IrTypeParameter
@@ -0,0 +1,123 @@
/*
* Copyright 2010-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan.irasdescriptors
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
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.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
val IrClassifierSymbol.typeWithoutArguments: IrType
get() = when (this) {
is IrClassSymbol -> {
require(this.descriptor.declaredTypeParameters.isEmpty())
this.typeWith(arguments = emptyList())
}
is IrTypeParameterSymbol -> this.defaultType
else -> error(this)
}
val IrClassifierSymbol.typeWithStarProjections
get() = when (this) {
is IrClassSymbol -> createType(
hasQuestionMark = false,
arguments = this.descriptor.declaredTypeParameters.map { IrStarProjectionImpl }
)
is IrTypeParameterSymbol -> this.defaultType
else -> error(this)
}
val IrTypeParameterSymbol.defaultType: IrType get() = IrSimpleTypeImpl(
this,
false,
emptyList(),
emptyList()
)
val IrTypeParameter.defaultType: IrType get() = this.symbol.defaultType
fun IrClassifierSymbol.typeWith(vararg arguments: IrType): IrSimpleType = typeWith(arguments.toList())
fun IrClassifierSymbol.typeWith(arguments: List<IrType>): IrSimpleType =
IrSimpleTypeImpl(
this,
false,
arguments.map { makeTypeProjection(it, Variance.INVARIANT) },
emptyList()
)
fun IrClass.typeWith(arguments: List<IrType>) = this.symbol.typeWith(arguments)
fun IrClassSymbol.createType(hasQuestionMark: Boolean, arguments: List<IrTypeArgument>): IrSimpleType =
IrSimpleTypeImpl(
this,
hasQuestionMark,
arguments,
emptyList()
)
fun IrType.getClass(): IrClass? =
(this.classifierOrNull as? IrClassSymbol)?.owner
fun IrType.makeNullableAsSpecified(nullable: Boolean): IrType =
if (nullable) this.makeNullable() else this.makeNotNull()
fun IrType.containsNull(): Boolean = if (this is IrSimpleType) {
if (this.hasQuestionMark) {
true
} else {
val classifier = this.classifier
when (classifier) {
is IrClassSymbol -> false
is IrTypeParameterSymbol -> classifier.owner.superTypes.any { it.containsNull() }
else -> error(classifier)
}
}
} else {
true
}
// TODO: get rid of these:
fun IrType.isSubtypeOf(other: KotlinType): Boolean = this.toKotlinType().isSubtypeOf(other)
fun IrType.isSubtypeOf(other: IrType): Boolean = this.isSubtypeOf(other.toKotlinType())
val IrType.isFunctionOrKFunctionType: Boolean
get() = when (this) {
is IrSimpleType -> {
val kind = classifier.descriptor.getFunctionalClassKind()
kind == FunctionClassDescriptor.Kind.Function || kind == FunctionClassDescriptor.Kind.KFunction
}
else -> false
}
internal tailrec fun IrType.getErasedTypeClass(): IrClassSymbol {
val classifier = this.classifierOrFail
return when (classifier) {
is IrClassSymbol -> classifier
is IrTypeParameterSymbol -> classifier.owner.superTypes.first().getErasedTypeClass()
else -> error(classifier)
}
}
@@ -23,28 +23,15 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.getTypeArgumentOrDefault
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.explicitParameters
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
val IrConstructor.constructedClass get() = this.parent as IrClass
@@ -88,26 +75,6 @@ val IrFunction.allParameters: List<IrValueParameter>
explicitParameters
}
/**
* @return naturally-ordered list of the parameters that can have values specified at call site.
*/
val IrFunction.explicitParameters: List<IrValueParameter>
get() {
val result = ArrayList<IrValueParameter>(valueParameters.size + 2)
this.dispatchReceiverParameter?.let {
result.add(it)
}
this.extensionReceiverParameter?.let {
result.add(it)
}
result.addAll(valueParameters)
return result
}
val IrValueParameter.isVararg get() = this.varargElementType != null
val IrFunction.isSuspend get() = this is IrSimpleFunction && this.isSuspend
@@ -116,6 +83,7 @@ fun IrClass.isUnit() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.unit.toSafe()
fun IrClass.isKotlinArray() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.array.toSafe()
val IrClass.superClasses get() = this.superTypes.map { it.classifierOrFail as IrClassSymbol }
fun IrClass.getSuperClassNotAny() = this.superClasses.map { it.owner }.atMostOne { !it.isInterface && !it.isAny() }
fun IrClass.isAny() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.any.toSafe()
@@ -132,7 +100,8 @@ val IrProperty.konanBackingField: IrField?
this.startOffset,
this.endOffset,
IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
backingFieldDescriptor
backingFieldDescriptor,
this.getter!!.returnType // TODO: this copies the behaviour found in backing field descriptor creation, but both are incorrect for property delegation.
).also {
it.parent = this.parent
}
@@ -143,9 +112,6 @@ val IrProperty.konanBackingField: IrField?
return null
}
val IrClass.defaultType: KotlinType
get() = this.thisReceiver!!.type
val IrField.containingClass get() = this.parent as? IrClass
val IrFunction.isReal get() = this.origin != IrDeclarationOrigin.FAKE_OVERRIDE
@@ -177,109 +143,17 @@ fun IrSimpleFunction.overrides(other: IrSimpleFunction): Boolean {
fun IrClass.isSpecialClassWithNoSupertypes() = this.isAny() || this.isNothing()
val IrClass.constructors get() = this.declarations.filterIsInstance<IrConstructor>()
internal val IrValueParameter.isValueParameter get() = this.index >= 0
fun IrModuleFragment.referenceAllTypeExternalClassifiers(symbolTable: SymbolTable) {
val moduleDescriptor = this.descriptor
private val IrCall.annotationClass
get() = (this.symbol.owner as IrConstructor).constructedClass
fun KotlinType.referenceAllClassifiers() {
TypeUtils.getClassDescriptor(this)?.let {
if (!ErrorUtils.isError(it) && it.module != moduleDescriptor) {
if (it.kind == ClassKind.ENUM_ENTRY) {
symbolTable.referenceEnumEntry(it)
} else {
symbolTable.referenceClass(it)
}
}
}
fun List<IrCall>.hasAnnotation(fqName: FqName): Boolean =
this.any { it.annotationClass.fqNameSafe == fqName }
this.constructor.supertypes.forEach {
it.referenceAllClassifiers()
}
}
fun IrAnnotationContainer.hasAnnotation(fqName: FqName) =
this.annotations.hasAnnotation(fqName)
val visitor = object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitValueParameter(declaration: IrValueParameter) {
super.visitValueParameter(declaration)
declaration.type.referenceAllClassifiers()
}
override fun visitVariable(declaration: IrVariable) {
super.visitVariable(declaration)
declaration.type.referenceAllClassifiers()
}
override fun visitExpression(expression: IrExpression) {
super.visitExpression(expression)
expression.type.referenceAllClassifiers()
}
override fun visitDeclaration(declaration: IrDeclaration) {
super.visitDeclaration(declaration)
declaration.descriptor.annotations.getAllAnnotations().forEach {
handleClassReferences(it.annotation)
}
}
private fun handleClassReferences(annotation: AnnotationDescriptor) {
annotation.allValueArguments.values.forEach {
it.accept(object : AnnotationArgumentVisitor<Unit, Nothing?> {
override fun visitKClassValue(p0: KClassValue?, p1: Nothing?) {
p0?.value?.referenceAllClassifiers()
}
override fun visitArrayValue(p0: ArrayValue?, p1: Nothing?) {
p0?.value?.forEach { it.accept(this, null) }
}
override fun visitAnnotationValue(p0: AnnotationValue?, p1: Nothing?) {
p0?.let { handleClassReferences(p0.value) }
}
override fun visitBooleanValue(p0: BooleanValue?, p1: Nothing?) {}
override fun visitShortValue(p0: ShortValue?, p1: Nothing?) {}
override fun visitByteValue(p0: ByteValue?, p1: Nothing?) {}
override fun visitNullValue(p0: NullValue?, p1: Nothing?) {}
override fun visitDoubleValue(p0: DoubleValue?, p1: Nothing?) {}
override fun visitLongValue(p0: LongValue, p1: Nothing?) {}
override fun visitCharValue(p0: CharValue?, p1: Nothing?) {}
override fun visitIntValue(p0: IntValue?, p1: Nothing?) {}
override fun visitUIntValue(p0: UIntValue?, p1: Nothing?) {}
override fun visitUShortValue(p0: UShortValue?, p1: Nothing?) {}
override fun visitUByteValue(p0: UByteValue?, p1: Nothing?) {}
override fun visitULongValue(p0: ULongValue?, p1: Nothing?) {}
override fun visitErrorValue(p0: ErrorValue?, p1: Nothing?) {}
override fun visitFloatValue(p0: FloatValue?, p1: Nothing?) {}
override fun visitEnumValue(p0: EnumValue?, p1: Nothing?) {}
override fun visitStringValue(p0: StringValue?, p1: Nothing?) {}
}, null)
}
}
override fun visitFunction(declaration: IrFunction) {
super.visitFunction(declaration)
declaration.returnType.referenceAllClassifiers()
}
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
super.visitFunctionAccess(expression)
expression.descriptor.original.typeParameters.forEach {
expression.getTypeArgumentOrDefault(it).referenceAllClassifiers()
}
}
}
this.acceptVoid(visitor)
this.dependencyModules.forEach { module ->
module.externalPackageFragments.forEach {
it.acceptVoid(visitor)
}
}
}
fun List<IrCall>.findAnnotation(fqName: FqName): IrCall? = this.firstOrNull {
it.annotationClass.fqNameSafe == fqName
}
@@ -17,25 +17,19 @@
package org.jetbrains.kotlin.backend.konan.llvm
import llvm.LLVMTypeRef
import llvm.LLVMVoidType
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
@@ -128,14 +122,14 @@ private val publishedApiAnnotation = FqName("kotlin.PublishedApi")
private val inlineExposedAnnotation = FqName("kotlin.internal.InlineExposed")
private fun acyclicTypeMangler(visited: MutableSet<TypeParameterDescriptor>, type: KotlinType): String {
val descriptor = TypeUtils.getTypeParameterDescriptorOrNull(type)
private fun acyclicTypeMangler(visited: MutableSet<TypeParameterDescriptor>, type: IrType): String {
val descriptor = (type.classifierOrNull as? IrTypeParameterSymbol)?.owner
if (descriptor != null) {
val upperBounds = if (visited.contains(descriptor)) "" else {
visited.add(descriptor)
descriptor.upperBounds.map {
descriptor.superTypes.map {
val bound = acyclicTypeMangler(visited, it)
if (bound == "kotlin.Any?") "" else "_$bound"
}.joinToString("")
@@ -143,24 +137,27 @@ private fun acyclicTypeMangler(visited: MutableSet<TypeParameterDescriptor>, typ
return "#GENERIC" + upperBounds
}
var hashString = TypeUtils.getClassDescriptor(type)!!.fqNameSafe.asString()
var hashString = type.getClass()!!.fqNameSafe.asString()
if (type !is IrSimpleType) error(type)
if (!type.arguments.isEmpty()) {
hashString += "<${type.arguments.map {
if (it.isStarProjection()) {
"#STAR"
} else {
val variance = it.projectionKind.label
val projection = if (variance == "") "" else "${variance}_"
projection + acyclicTypeMangler(visited, it.type)
when (it) {
is IrStarProjection -> "#STAR"
is IrTypeProjection -> {
val variance = it.variance.label
val projection = if (variance == "") "" else "${variance}_"
projection + acyclicTypeMangler(visited, it.type)
}
else -> error(it)
}
}.joinToString(",")}>"
}
if (type.isMarkedNullable) hashString += "?"
if (type.hasQuestionMark) hashString += "?"
return hashString
}
private fun typeToHashString(type: KotlinType)
private fun typeToHashString(type: IrType)
= acyclicTypeMangler(mutableSetOf<TypeParameterDescriptor>(), type)
private val FunctionDescriptor.signature: String
@@ -175,7 +172,7 @@ private val FunctionDescriptor.signature: String
when {
this.typeParameters.isNotEmpty() -> "Generic"
returnType.isValueType() -> "ValueType"
!KotlinBuiltIns.isUnitOrNullableUnit(returnType) -> typeToHashString(returnType)
!returnType.isUnitOrNullableUnit() -> typeToHashString(returnType)
else -> ""
}
return "$extensionReceiverPart($argsPart)$signatureSuffix"
@@ -188,7 +185,7 @@ internal val FunctionDescriptor.functionName: String
this.getObjCMethodInfo()?.let {
return buildString {
if (extensionReceiverParameter != null) {
append(TypeUtils.getClassDescriptor(extensionReceiverParameter!!.type)!!.name)
append(extensionReceiverParameter!!.type.getClass()!!.name)
append(".")
}
@@ -235,7 +232,7 @@ internal val IrField.symbolName: String
}
private fun getStringValue(annotation: AnnotationDescriptor): String? {
internal fun getStringValue(annotation: AnnotationDescriptor): String? {
return annotation.allValueArguments.values.ifNotEmpty {
val stringValue = single() as? StringValue
stringValue?.value
@@ -25,6 +25,8 @@ import org.jetbrains.kotlin.backend.konan.descriptors.stdlibModule
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.llvm.objc.ObjCDataGenerator
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.konan.target.KonanTarget
internal class CodeGenerator(override val context: Context) : ContextUtils {
@@ -709,7 +711,7 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
*/
fun getEnumEntry(descriptor: IrEnumEntry, exceptionHandler: ExceptionHandler): LLVMValueRef {
val enumClassDescriptor = descriptor.containingDeclaration as ClassDescriptor
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor.descriptor)
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor)
val ordinal = loweredEnum.entriesMap[descriptor.name]!!
val values = call(
@@ -20,9 +20,8 @@ import llvm.*
import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.isRepresentedAs
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isUnit
private val valueTypes = ValueType.values().associate {
it to when (it) {
@@ -41,7 +40,7 @@ private val valueTypes = ValueType.values().associate {
internal val ValueType.llvmType
get() = valueTypes[this]!!
internal fun RuntimeAware.getLLVMType(type: KotlinType): LLVMTypeRef {
internal fun RuntimeAware.getLLVMType(type: IrType): LLVMTypeRef {
for ((valueType, llvmType) in valueTypes) {
if (type.isRepresentedAs(valueType)) {
return llvmType
@@ -54,13 +53,11 @@ internal fun RuntimeAware.getLLVMType(type: KotlinType): LLVMTypeRef {
internal fun RuntimeAware.getLLVMType(type: DataFlowIR.Type) =
type.correspondingValueType?.let { valueTypes[it]!! } ?: this.kObjHeaderPtr
internal fun RuntimeAware.getLLVMReturnType(type: KotlinType): LLVMTypeRef {
internal fun RuntimeAware.getLLVMReturnType(type: IrType): LLVMTypeRef {
return when {
type.isUnit() -> LLVMVoidType()!!
// TODO: stdlib have methods taking Nothing, such as kotlin.collections.EmptySet.contains().
// KotlinBuiltIns.isNothing(type) -> LLVMVoidType()
else -> getLLVMType(type)
}
}
fun RuntimeAware.isObjectType(type: KotlinType) : Boolean = isObjectType(getLLVMType(type))
}
@@ -184,8 +184,8 @@ private fun debugInfoBaseType(context:Context, targetData:LLVMTargetDataRef, typ
internal val FunctionDescriptor.types:List<KotlinType>
get() {
val parameters = valueParameters.map{it.type}
return listOf(returnType, *parameters.toTypedArray())
val parameters = descriptor.valueParameters.map{it.type}
return listOf(descriptor.returnType!!, *parameters.toTypedArray())
}
internal fun KotlinType.size(context:Context) = context.debugInfo.llvmTypeSizes.getOrDefault(this, context.debugInfo.otherTypeSize)
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.optimizations.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrElement
@@ -36,6 +35,8 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -43,11 +44,6 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isPrimitiveNumberType
import org.jetbrains.kotlin.types.typeUtil.isUnit
val IrClassSymbol.objectIsShared get() = owner.origin == DECLARATION_ORIGIN_ENUM
@@ -862,7 +858,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
* Creates new [ContinuationBlock] that receives the value of given Kotlin type
* and generates [code] starting from its beginning.
*/
private fun continuationBlock(type: KotlinType,
private fun continuationBlock(type: IrType,
locationInfo: LocationInfo?, code: (ContinuationBlock) -> Unit = {}): ContinuationBlock {
val entry = functionGenerationContext.basicBlock("continuation_block", locationInfo)
@@ -893,7 +889,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
throw IllegalStateException("IrVararg neither was lowered nor can be statically evaluated")
}
val arrayClass = context.ir.getClass(value.type)!!
val arrayClass = value.type.getClass()!!
// Note: even if all elements are const, they aren't guaranteed to be statically initialized.
// E.g. an element may be a pointer to lazy-initialized object (aka singleton).
@@ -934,7 +930,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
*/
private val handler by lazy {
using(outerContext) {
continuationBlock(context.builtIns.throwable.defaultType, endLocationInfoFromScope()) {
continuationBlock(context.ir.symbols.throwable.owner.defaultType, endLocationInfoFromScope()) {
genHandler(it.value)
}
}
@@ -1008,7 +1004,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
genCatchBlock()
return // Remaining catch clauses are unreachable.
} else {
val isInstance = genInstanceOf(exception, catch.getCatchParameterTypeClass(context)!!)
val isInstance = genInstanceOf(exception, catch.catchParameter.type.getClass()!!)
val body = functionGenerationContext.basicBlock("catch", catch.startLocation)
val nextCheck = functionGenerationContext.basicBlock("catchCheck", catch.endLocation)
functionGenerationContext.condBr(isInstance, body, nextCheck)
@@ -1058,8 +1054,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateWhen(expression: IrWhen): LLVMValueRef {
context.log{"evaluateWhen : ${ir2string(expression)}"}
var bbExit: LLVMBasicBlockRef? = null // By default "when" does not have "exit".
val isUnit = KotlinBuiltIns.isUnit(expression.type)
val isNothing = KotlinBuiltIns.isNothing(expression.type)
val isUnit = expression.type.isUnit()
val isNothing = expression.type.isNothing()
// We may not cover all cases if IrWhen is used as statement.
val coverAllCases = isUnconditional(expression.branches.last())
@@ -1143,14 +1139,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateGetValue(value: IrGetValue): LLVMValueRef {
context.log{"evaluateGetValue : ${ir2string(value)}"}
val symbol = value.symbol
val ir: IrSymbolDeclaration<IrValueSymbol> = when (symbol) {
is IrVariableSymbol -> symbol.owner
is IrValueParameterSymbol -> symbol.owner
else -> error(symbol)
}
return currentCodeContext.genGetValue(ir)
return currentCodeContext.genGetValue(value.symbol.owner)
}
//-------------------------------------------------------------------------//
@@ -1221,11 +1210,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun KotlinType.isPrimitiveInteger(): Boolean {
return isPrimitiveNumberType() &&
!KotlinBuiltIns.isFloat(this) &&
!KotlinBuiltIns.isDouble(this) &&
!KotlinBuiltIns.isChar(this)
private fun IrType.isPrimitiveInteger(): Boolean {
return this.isPrimitiveType() &&
!this.isBoolean() &&
!this.isFloat() &&
!this.isDouble() &&
!this.isChar()
}
private fun evaluateIntegerCoercion(value: IrTypeOperatorCall): LLVMValueRef {
@@ -1259,10 +1249,10 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateCast(value: IrTypeOperatorCall): LLVMValueRef {
context.log{"evaluateCast : ${ir2string(value)}"}
val dstDescriptor = value.getTypeOperandClass(context)!!
val dstDescriptor = value.typeOperand.getClass()!!
assert(!KotlinBuiltIns.isPrimitiveType(dstDescriptor.defaultType) &&
!KotlinBuiltIns.isPrimitiveType(value.argument.type))
assert(!dstDescriptor.defaultType.isValueType() &&
!value.argument.type.isValueType())
val srcArg = evaluateExpression(value.argument) // Evaluate src expression.
@@ -1304,11 +1294,11 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.condBr(condition, bbNull, bbInstanceOf)
functionGenerationContext.positionAtEnd(bbNull)
val resultNull = if (TypeUtils.isNullableType(type)) kTrue else kFalse
val resultNull = if (type.containsNull()) kTrue else kFalse
functionGenerationContext.br(bbExit)
functionGenerationContext.positionAtEnd(bbInstanceOf)
val typeOperandClass = value.getTypeOperandClass(context)
val typeOperandClass = value.typeOperand.getClass()
val resultInstanceOf = if (typeOperandClass != null) {
genInstanceOf(srcArg, typeOperandClass)
} else {
@@ -1883,7 +1873,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
private fun FunctionDescriptor.returnsUnit() = returnType == context.builtIns.unitType && !isSuspend
private fun FunctionDescriptor.returnsUnit() = returnType.isUnit() && !isSuspend
/**
* Evaluates all arguments of [expression] that are explicitly represented in the IR.
@@ -1906,7 +1896,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateFunctionReference(expression: IrFunctionReference): LLVMValueRef {
// TODO: consider creating separate IR element for pointer to function.
assert (TypeUtils.getClassDescriptor(expression.type) == context.interopBuiltIns.cPointer)
assert (expression.type.getClass()?.descriptor == context.interopBuiltIns.cPointer)
assert (expression.getArguments().isEmpty())
@@ -2105,6 +2095,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
private fun evaluateIntrinsicCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
val descriptor = callee.descriptor.original
val function = callee.symbol.owner
val name = descriptor.fqNameUnsafe.asString()
when (name) {
@@ -2137,13 +2128,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
interop.nativePointedGetRawPointer, interop.cPointerGetRawValue -> args.single()
in interop.readPrimitive -> {
val pointerType = pointerType(codegen.getLLVMType(descriptor.returnType!!))
val pointerType = pointerType(codegen.getLLVMType(function.returnType))
val rawPointer = args.last()
val pointer = functionGenerationContext.bitcast(pointerType, rawPointer)
functionGenerationContext.load(pointer)
}
in interop.writePrimitive -> {
val pointerType = pointerType(codegen.getLLVMType(descriptor.valueParameters.last().type))
val pointerType = pointerType(codegen.getLLVMType(function.valueParameters.last().type))
val rawPointer = args[1]
val pointer = functionGenerationContext.bitcast(pointerType, rawPointer)
functionGenerationContext.store(args[2], pointer)
@@ -2154,7 +2145,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
interop.getPointerSize -> Int32(LLVMPointerSize(codegen.llvmTargetData)).llvm
context.builtIns.nativePtrToLong -> {
val intPtrValue = functionGenerationContext.ptrToInt(args.single(), codegen.intPtrType)
val resultType = functionGenerationContext.getLLVMType(descriptor.returnType!!)
val resultType = functionGenerationContext.getLLVMType(function.returnType)
if (resultType == intPtrValue.type) {
intPtrValue
@@ -2169,7 +2160,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
interop.getObjCClass -> {
val typeArgument = callee.getTypeArgument(descriptor.typeParameters.single())
val irClass = context.ir.getClass(typeArgument!!)!!
val irClass = typeArgument!!.getClass()!!
genGetObjCClass(irClass)
}
@@ -2184,8 +2175,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
interop.writeBits -> genWriteBits(args)
context.ir.symbols.getClassTypeInfo.descriptor -> {
val typeArgument = callee.getTypeArgumentOrDefault(descriptor.typeParameters.single())
val typeArgumentClass = context.ir.getClass(typeArgument)
val typeArgument = callee.getTypeArgument(0)!!
val typeArgumentClass = typeArgument.getClass()
if (typeArgumentClass == null) {
// E.g. for `T::class` in a body of an inline function itself.
functionGenerationContext.unreachable()
@@ -2202,7 +2193,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
context.ir.symbols.createUninitializedInstance.descriptor -> {
val typeParameterT = context.ir.symbols.createUninitializedInstance.descriptor.typeParameters[0]
val enumClass = callee.getTypeArgument(typeParameterT)!!
val enumIrClass = context.ir.getClass(enumClass)!!
val enumIrClass = enumClass.getClass()!!
functionGenerationContext.allocInstance(enumIrClass, resultLifetime(callee))
}
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.getStringValueOrNull
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.simpleFunctions
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.FqName
@@ -140,7 +141,7 @@ private fun Context.getDeclaredFields(classDescriptor: ClassDescriptor): List<Ir
private fun ContextUtils.createClassBodyType(name: String, fields: List<IrField>): LLVMTypeRef {
val fieldTypes = fields.map {
@Suppress("DEPRECATION")
getLLVMType(if (it.isDelegate) context.builtIns.nullableAnyType else it.type)
getLLVMType(if (it.isDelegate) context.irBuiltIns.anyNType else it.type)
}
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!!
@@ -101,9 +101,9 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
private fun exportTypeInfoIfRequired(classDesc: ClassDescriptor, typeInfoGlobal: LLVMValueRef?) {
val annot = classDesc.descriptor.annotations.findAnnotation(FqName("konan.ExportTypeInfo"))
if (annot != null) {
val nameValue = annot.allValueArguments.values.single() as StringValue
val name = getStringValue(annot)!!
// TODO: use LLVMAddAlias?
val global = addGlobal(nameValue.value, pointerType(runtime.typeInfoType), isExported = true)
val global = addGlobal(name, pointerType(runtime.typeInfoType), isExported = true)
LLVMSetInitializer(global, typeInfoGlobal)
}
}
@@ -18,9 +18,6 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.*
import llvm.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit
interface RuntimeAware {
val runtime: Runtime
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.backend.konan.llvm
import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.types.KotlinType
/**
* Provides utilities to create static data.
@@ -20,7 +20,6 @@ import llvm.LLVMLinkage
import llvm.LLVMSetLinkage
import llvm.LLVMTypeRef
import llvm.LLVMValueRef
import org.jetbrains.kotlin.backend.konan.irasdescriptors.defaultType
import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe
import org.jetbrains.kotlin.backend.konan.irasdescriptors.llvmSymbolOrigin
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -28,8 +27,6 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.TypeProjection
import org.jetbrains.kotlin.types.replace
private fun StaticData.objHeader(typeInfo: ConstPointer): Struct {
@@ -176,9 +176,3 @@ internal fun debugInfoParameterLocation(builder: DIBuilderRef?,
return VariableDebugLocation(localVariable = variableDeclaration!!, location = location, file = file, line = line)
}
private val ValueDescriptor.type get() = when (this) {
is IrVariable -> this.type
is IrValueParameter -> this.type
else -> error(this)
}
@@ -19,18 +19,17 @@ package org.jetbrains.kotlin.backend.konan.llvm.objcexport
import llvm.*
import org.jetbrains.kotlin.backend.konan.descriptors.CurrentKonanModule
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.util.OperatorNameConventions
internal fun ObjCExportCodeGenerator.generateKotlinFunctionImpl(invokeMethod: FunctionDescriptor): ConstPointer {
internal fun ObjCExportCodeGenerator.generateKotlinFunctionImpl(invokeMethod: IrSimpleFunction): ConstPointer {
// TODO: consider also overriding methods of `Any`.
val numberOfParameters = invokeMethod.valueParameters.size
val function = generateFunction(
codegen,
codegen.getLlvmFunctionType(context.ir.get(invokeMethod)),
codegen.getLlvmFunctionType(invokeMethod),
"invokeFunction$numberOfParameters"
) {
val args = (0 until numberOfParameters).map { index -> kotlinReferenceToObjC(param(index + 1)) }
@@ -380,7 +380,7 @@ private fun ObjCExportCodeGenerator.generateKotlinFunctionAdapterToBlock(numberO
val invokeMethod = irInterface.declarations.filterIsInstance<IrSimpleFunction>()
.single { it.name == OperatorNameConventions.INVOKE }
val invokeImpl = generateKotlinFunctionImpl(invokeMethod.descriptor)
val invokeImpl = generateKotlinFunctionImpl(invokeMethod)
return rttiGenerator.generateSyntheticInterfaceImpl(
irInterface,
@@ -18,22 +18,25 @@ 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.explicitParameters
import org.jetbrains.kotlin.backend.common.descriptors.isSuspend
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.target
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.containsNull
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isOverridable
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isSuspend
import org.jetbrains.kotlin.backend.konan.irasdescriptors.makeNullableAsSpecified
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.makeNullable
/**
* Boxes and unboxes values of value types when necessary.
@@ -48,9 +51,11 @@ internal class Autoboxing(val context: Context) : FileLoweringPass {
}
private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTransformer(context.builtIns) {
val symbols = context.ir.symbols
private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTransformer(
context.builtIns,
context.ir.symbols,
context.irBuiltIns
) {
// TODO: should we handle the cases when expression type
// is not equal to e.g. called function return type?
@@ -59,23 +64,23 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
/**
* @return type to use for runtime type checks instead of given one (e.g. `IntBox` instead of `Int`)
*/
private fun getRuntimeReferenceType(type: KotlinType): KotlinType {
private fun getRuntimeReferenceType(type: IrType): IrType {
ValueType.values().forEach {
if (type.notNullableIsRepresentedAs(it)) {
return getBoxType(it).makeNullableAsSpecified(TypeUtils.isNullableType(type))
return getBoxType(it).makeNullableAsSpecified(type.containsNull())
}
}
return type
}
override fun IrExpression.useInTypeOperator(operator: IrTypeOperator, typeOperand: KotlinType): IrExpression {
override fun IrExpression.useInTypeOperator(operator: IrTypeOperator, typeOperand: IrType): IrExpression {
return if (operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT ||
operator == IrTypeOperator.IMPLICIT_INTEGER_COERCION) {
this
} else {
// Codegen expects the argument of type-checking operator to be an object reference:
this.useAs(builtIns.nullableAnyType)
this.useAs(context.irBuiltIns.anyNType)
}
}
@@ -86,6 +91,7 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
}
val newTypeOperand = getRuntimeReferenceType(expression.typeOperand)
val newTypeOperandClassifier = newTypeOperand.classifierOrFail
return when (expression.operator) {
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
@@ -101,7 +107,7 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
}
IrTypeOperatorCallImpl(expression.startOffset, expression.endOffset,
newExpressionType, expression.operator, newTypeOperand,
newExpressionType, expression.operator, newTypeOperand, newTypeOperandClassifier,
expression.argument).useAs(expression.type)
}
@@ -110,40 +116,49 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
expression
} else {
IrTypeOperatorCallImpl(expression.startOffset, expression.endOffset,
expression.type, expression.operator, newTypeOperand, expression.argument)
expression.type, expression.operator, newTypeOperand, newTypeOperandClassifier,
expression.argument)
}
}
}
private var currentFunctionDescriptor: FunctionDescriptor? = null
private var currentFunctionDescriptor: IrFunction? = null
override fun visitFunction(declaration: IrFunction): IrStatement {
currentFunctionDescriptor = declaration.descriptor
currentFunctionDescriptor = declaration
val result = super.visitFunction(declaration)
currentFunctionDescriptor = null
return result
}
override fun IrExpression.useAsReturnValue(returnTarget: CallableDescriptor): IrExpression {
if (returnTarget.isSuspend && returnTarget == currentFunctionDescriptor)
return this.useAs(context.builtIns.nullableAnyType)
val returnType = returnTarget.returnType
?: return this
return this.useAs(returnType)
override fun IrExpression.useAsReturnValue(returnTarget: IrReturnTargetSymbol): IrExpression = when (returnTarget) {
is IrSimpleFunctionSymbol -> if (returnTarget.owner.isSuspend && returnTarget == currentFunctionDescriptor?.symbol) {
this.useAs(irBuiltIns.anyNType)
} else {
this.useAs(returnTarget.owner.returnType)
}
is IrConstructorSymbol -> this.useAs(irBuiltIns.unitType)
is IrReturnableBlockSymbol -> this.useAs(returnTarget.owner.type)
else -> error(returnTarget)
}
override fun IrExpression.useAs(type: KotlinType): IrExpression {
override fun IrExpression.useAs(type: IrType): IrExpression {
val interop = context.interopBuiltIns
if (this.isNullConst() && interop.nullableInteropValueTypes.any { type.isRepresentedAs(it) }) {
return IrCallImpl(startOffset, endOffset, symbols.getNativeNullPtr).uncheckedCast(type)
return IrCallImpl(
startOffset,
endOffset,
symbols.getNativeNullPtr.owner.returnType,
symbols.getNativeNullPtr
).uncheckedCast(type)
}
val actualType = when (this) {
is IrCall -> {
if (this.descriptor.isSuspend) context.builtIns.nullableAnyType
else this.callTarget.returnType ?: this.type
if (this.symbol.owner.isSuspend) irBuiltIns.anyNType
else this.callTarget.returnType
}
is IrGetField -> this.descriptor.original.type
is IrGetField -> this.symbol.owner.type
is IrTypeOperatorCall -> when (this.operator) {
IrTypeOperator.IMPLICIT_INTEGER_COERCION ->
@@ -159,65 +174,63 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
return this.adaptIfNecessary(actualType, type)
}
private val IrMemberAccessExpression.target: CallableDescriptor get() = when (this) {
private val IrFunctionAccessExpression.target: IrFunction get() = when (this) {
is IrCall -> this.callTarget
is IrDelegatingConstructorCall -> this.descriptor.original
is IrDelegatingConstructorCall -> this.symbol.owner
else -> TODO(this.render())
}
private val IrCall.callTarget: FunctionDescriptor
get() = if (superQualifier == null && descriptor.isOverridable) {
private val IrCall.callTarget: IrFunction
get() = if (superQualifier == null && symbol.owner.isOverridable) {
// A virtual call.
descriptor.original
symbol.owner
} else {
descriptor.target
symbol.owner.target
}
override fun IrExpression.useAsDispatchReceiver(expression: IrMemberAccessExpression): IrExpression {
override fun IrExpression.useAsDispatchReceiver(expression: IrFunctionAccessExpression): IrExpression {
return this.useAsArgument(expression.target.dispatchReceiverParameter!!)
}
override fun IrExpression.useAsExtensionReceiver(expression: IrMemberAccessExpression): IrExpression {
override fun IrExpression.useAsExtensionReceiver(expression: IrFunctionAccessExpression): IrExpression {
return this.useAsArgument(expression.target.extensionReceiverParameter!!)
}
override fun IrExpression.useAsValueArgument(expression: IrMemberAccessExpression,
parameter: ValueParameterDescriptor): IrExpression {
override fun IrExpression.useAsValueArgument(expression: IrFunctionAccessExpression,
parameter: IrValueParameter): IrExpression {
return this.useAsArgument(expression.target.valueParameters[parameter.index])
}
override fun IrExpression.useForField(field: PropertyDescriptor): IrExpression {
return this.useForVariable(field.original)
}
private fun IrExpression.adaptIfNecessary(actualType: KotlinType, expectedType: KotlinType): IrExpression {
private fun IrExpression.adaptIfNecessary(actualType: IrType, expectedType: IrType): IrExpression {
val conversion = symbols.getTypeConversion(actualType, expectedType)
return if (conversion == null) {
this
} else {
val parameter = conversion.descriptor.explicitParameters.single()
val parameter = conversion.owner.explicitParameters.single()
val argument = this.uncheckedCast(parameter.type)
IrCallImpl(startOffset, endOffset, conversion).apply {
addArguments(listOf(parameter to argument))
IrCallImpl(startOffset, endOffset, conversion.owner.returnType, conversion).apply {
addArguments(mapOf(parameter to argument))
}.uncheckedCast(this.type) // Try not to bring new type incompatibilities.
}
}
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
expression.transformChildrenVoid()
assert(expression.getArgumentsWithIr().isEmpty())
return expression
}
/**
* Casts this expression to `type` without changing its representation in generated code.
*/
@Suppress("UNUSED_PARAMETER")
private fun IrExpression.uncheckedCast(type: KotlinType): IrExpression {
private fun IrExpression.uncheckedCast(type: IrType): IrExpression {
// TODO: apply some cast if types are incompatible; not required currently.
return this
}
private val ValueType.shortName
get() = this.classFqName.shortName()
private fun getBoxType(valueType: ValueType) =
context.getInternalClass("${valueType.shortName}Box").defaultType
private fun getBoxType(valueType: ValueType) = symbols.boxClasses[valueType]!!.owner.defaultType
}
@@ -23,26 +23,27 @@ 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.descriptors.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isNullableAny
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.simpleFunctions
import org.jetbrains.kotlin.ir.util.transformFlat
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 WorkersBridgesBuilding(val context: Context) : DeclarationContainerLoweringPass, IrElementTransformerVoid() {
@@ -100,7 +101,16 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
IrDeclarationOrigin.DEFINED,
runtimeJobDescriptor
).also {
it.createParameterDeclarations()
it.returnType = context.irBuiltIns.anyNType
it.valueParameters += IrValueParameterImpl(
it.startOffset,
it.endOffset,
IrDeclarationOrigin.DEFINED,
it.descriptor.valueParameters.single(),
context.irBuiltIns.anyNType,
null
)
}
}
val overriddenJobDescriptor = OverriddenFunctionDescriptor(jobFunction, runtimeJobFunction)
@@ -118,7 +128,7 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
type = job.type,
symbol = bridge.symbol,
descriptor = bridge.descriptor,
typeArguments = null)
typeArgumentsCount = 0)
)
return expression
}
@@ -158,7 +168,7 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
val irBuilder = context.createIrBuilder(declaration.symbol, declaration.startOffset, declaration.endOffset)
declaration.body = irBuilder.irBlockBody(declaration) {
buildTypeSafeBarrier(declaration, descriptor, typeSafeBarrierDescription)
buildTypeSafeBarrier(declaration, declaration, typeSafeBarrierDescription)
body.statements.forEach { +it }
}
return declaration
@@ -187,7 +197,7 @@ internal val IrFunction.bridgeTarget: IrFunction?
get() = (origin as? DECLARATION_ORIGIN_BRIDGE_METHOD)?.bridgeTarget
private fun IrBuilderWithScope.returnIfBadType(value: IrExpression,
type: KotlinType,
type: IrType,
returnValueOnFail: IrExpression)
= irIfThen(irNotIs(value, type), irReturn(returnValueOnFail))
@@ -199,18 +209,18 @@ private fun IrBuilderWithScope.irConst(value: Any?) = when (value) {
}
private fun IrBlockBodyBuilder.buildTypeSafeBarrier(function: IrFunction,
originalDescriptor: FunctionDescriptor,
originalFunction: IrFunction,
typeSafeBarrierDescription: BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription) {
val valueParameters = function.valueParameters
val originalValueParameters = originalDescriptor.valueParameters
val originalValueParameters = originalFunction.valueParameters
for (i in valueParameters.indices) {
if (!typeSafeBarrierDescription.checkParameter(i))
continue
val type = originalValueParameters[i].type
if (type != context.builtIns.nullableAnyType) {
+returnIfBadType(irGet(valueParameters[i].symbol), type,
if (!type.isNullableAny()) {
+returnIfBadType(irGet(valueParameters[i]), type,
if (typeSafeBarrierDescription == BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT)
irGet(valueParameters[2].symbol)
irGet(valueParameters[2])
else irConst(typeSafeBarrierDescription.defaultValue)
)
}
@@ -221,7 +231,7 @@ private fun Context.buildBridge(startOffset: Int, endOffset: Int,
descriptor: OverriddenFunctionDescriptor, targetSymbol: IrFunctionSymbol,
superQualifierSymbol: IrClassSymbol? = null): IrFunction {
val bridge = specialDeclarationsFactory.getBridgeDescriptor(descriptor)
val bridge = specialDeclarationsFactory.getBridge(descriptor)
if (bridge.modality == Modality.ABSTRACT) {
return bridge
@@ -230,23 +240,28 @@ private fun Context.buildBridge(startOffset: Int, endOffset: Int,
val irBuilder = createIrBuilder(bridge.symbol, startOffset, endOffset)
bridge.body = irBuilder.irBlockBody(bridge) {
val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor.overriddenDescriptor.descriptor)
typeSafeBarrierDescription?.let { buildTypeSafeBarrier(bridge, descriptor.descriptor.descriptor, it) }
typeSafeBarrierDescription?.let { buildTypeSafeBarrier(bridge, descriptor.descriptor, it) }
val delegatingCall = IrCallImpl(startOffset, endOffset, targetSymbol, targetSymbol.descriptor,
val delegatingCall = IrCallImpl(
startOffset,
endOffset,
(targetSymbol.owner as IrFunction).returnType,
targetSymbol,
targetSymbol.descriptor,
superQualifierSymbol = superQualifierSymbol /* Call non-virtually */
).apply {
bridge.dispatchReceiverParameter?.let {
dispatchReceiver = irGet(it.symbol)
dispatchReceiver = irGet(it)
}
bridge.extensionReceiverParameter?.let {
extensionReceiver = irGet(it.symbol)
extensionReceiver = irGet(it)
}
bridge.valueParameters.forEachIndexed { index, parameter ->
this.putValueArgument(index, irGet(parameter.symbol))
this.putValueArgument(index, irGet(parameter))
}
}
if (KotlinBuiltIns.isUnitOrNullableUnit(bridge.returnType))
if (bridge.returnType.isUnit())
+delegatingCall
else
+irReturn(delegatingCall)
@@ -22,6 +22,8 @@ import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer
import org.jetbrains.kotlin.backend.common.lower.at
import org.jetbrains.kotlin.backend.common.lower.irNot
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.irasdescriptors.containsNull
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isSubtypeOf
import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.builders.*
@@ -33,13 +35,13 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isNothing
import org.jetbrains.kotlin.ir.util.isNullConst
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.isNullable
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import org.jetbrains.kotlin.types.typeUtil.makeNullable
/**
* This lowering pass lowers some calls to [IrBuiltinOperatorDescriptor]s.
@@ -82,9 +84,11 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass,
irBuiltins.eqeqeq -> lowerEqeqeq(expression)
irBuiltins.throwNpe -> IrCallImpl(expression.startOffset, expression.endOffset,
context.ir.symbols.ThrowNullPointerException.owner.returnType,
context.ir.symbols.ThrowNullPointerException)
irBuiltins.noWhenBranchMatchedException -> IrCallImpl(expression.startOffset, expression.endOffset,
context.ir.symbols.ThrowNoWhenBranchMatchedException.owner.returnType,
context.ir.symbols.ThrowNoWhenBranchMatchedException)
else -> expression
@@ -148,8 +152,8 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass,
putValueArgument(0, rhs)
}
val lhsIsNotNullable = !lhs.type.isNullable()
val rhsIsNotNullable = !rhs.type.isNullable()
val lhsIsNotNullable = !lhs.type.containsNull()
val rhsIsNotNullable = !rhs.type.containsNull()
return if (expression.descriptor in ieee754EqualsDescriptors()) {
if (lhsIsNotNullable && rhsIsNotNullable)
@@ -159,15 +163,15 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass,
val rhsTemp = irTemporary(rhs)
if (lhsIsNotNullable xor rhsIsNotNullable) { // Exactly one nullable.
+irLogicalAnd(
irIsNotNull(irGet((if (lhsIsNotNullable) rhsTemp else lhsTemp).symbol)),
callEquals(irGet(lhsTemp.symbol), irGet(rhsTemp.symbol))
irIsNotNull(irGet(if (lhsIsNotNullable) rhsTemp else lhsTemp)),
callEquals(irGet(lhsTemp), irGet(rhsTemp))
)
} else { // Both are nullable.
+irIfThenElse(builtIns.booleanType, irIsNull(irGet(lhsTemp.symbol)),
irIsNull(irGet(rhsTemp.symbol)),
+irIfThenElse(context.irBuiltIns.booleanType, irIsNull(irGet(lhsTemp)),
irIsNull(irGet(rhsTemp)),
irLogicalAnd(
irIsNotNull(irGet(rhsTemp.symbol)),
callEquals(irGet(lhsTemp.symbol), irGet(rhsTemp.symbol))
irIsNotNull(irGet(rhsTemp)),
callEquals(irGet(lhsTemp), irGet(rhsTemp))
)
)
}
@@ -179,12 +183,12 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass,
irBlock {
val lhsTemp = irTemporary(lhs)
if (rhsIsNotNullable)
+irLogicalAnd(irIsNotNull(irGet(lhsTemp.symbol)), callEquals(irGet(lhsTemp.symbol), rhs))
+irLogicalAnd(irIsNotNull(irGet(lhsTemp)), callEquals(irGet(lhsTemp), rhs))
else {
val rhsTemp = irTemporary(rhs)
+irIfThenElse(builtIns.booleanType, irIsNull(irGet(lhsTemp.symbol)),
irIsNull(irGet(rhsTemp.symbol)),
callEquals(irGet(lhsTemp.symbol), irGet(rhsTemp.symbol))
+irIfThenElse(irBuiltins.booleanType, irIsNull(irGet(lhsTemp)),
irIsNull(irGet(rhsTemp)),
callEquals(irGet(lhsTemp), irGet(rhsTemp))
)
}
}
@@ -193,7 +197,7 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass,
}
}
private fun selectIntrinsic(from: List<IrSimpleFunctionSymbol>, lhsType: KotlinType, rhsType: KotlinType, allowNullable: Boolean) =
private fun selectIntrinsic(from: List<IrSimpleFunctionSymbol>, lhsType: IrType, rhsType: IrType, allowNullable: Boolean) =
from.atMostOne {
val leftParamType = it.owner.valueParameters[0].type
val rightParamType = it.owner.valueParameters[1].type
@@ -18,16 +18,14 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.descriptors.getFunction
import org.jetbrains.kotlin.backend.common.descriptors.isFunctionOrKFunctionType
import org.jetbrains.kotlin.backend.common.descriptors.replace
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isFunctionOrKFunctionType
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith
import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
@@ -47,19 +45,20 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
internal class CallableReferenceLowering(val context: Context): FileLoweringPass {
@@ -161,15 +160,16 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
val parent: IrDeclarationParent,
val functionReference: IrFunctionReference) {
private val functionDescriptor = functionReference.descriptor
private val functionParameters = functionDescriptor.explicitParameters
private val boundFunctionParameters = functionReference.getArguments().map { it.first }
private val functionDescriptor = functionReference.descriptor.original
private val irFunction = functionReference.symbol.owner
private val functionParameters = irFunction.explicitParameters
private val boundFunctionParameters = functionReference.getArgumentsWithIr().map { it.first }
private val unboundFunctionParameters = functionParameters - boundFunctionParameters
private lateinit var functionReferenceClassDescriptor: ClassDescriptorImpl
private lateinit var functionReferenceClass: IrClassImpl
private lateinit var functionReferenceThis: IrValueParameterSymbol
private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrFieldSymbol>
private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrField>
private val kFunctionImplSymbol = context.ir.symbols.kFunctionImpl
@@ -177,29 +177,26 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
val startOffset = functionReference.startOffset
val endOffset = functionReference.endOffset
val returnType = functionDescriptor.returnType!!
val superTypes = mutableListOf(
kFunctionImplSymbol.owner.defaultType.replace(listOf(returnType))
)
val superClasses = mutableListOf(kFunctionImplSymbol.owner)
val returnType = irFunction.returnType
val superTypes = mutableListOf(kFunctionImplSymbol.typeWith(returnType))
val numberOfParameters = unboundFunctionParameters.size
val functionClassDescriptor = context.reflectionTypes.getKFunction(numberOfParameters)
val functionIrClass = context.ir.symbols.kFunctions[numberOfParameters].owner
val functionParameterTypes = unboundFunctionParameters.map { it.type }
val functionClassTypeParameters = functionParameterTypes + returnType
superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeParameters)
superClasses += context.ir.symbols.kFunctions[numberOfParameters].owner
superTypes += functionIrClass.symbol.typeWith(functionClassTypeParameters)
var suspendFunctionClassDescriptor: ClassDescriptor? = null
var suspendFunctionClassTypeParameters: List<KotlinType>? = null
var suspendFunctionIrClass: IrClass? = null
var suspendFunctionClassTypeParameters: List<IrType>? = null
val lastParameterType = unboundFunctionParameters.lastOrNull()?.type
if (lastParameterType != null && TypeUtils.getClassDescriptor(lastParameterType) == continuationClassDescriptor) {
if (lastParameterType != null && lastParameterType.classifierOrNull?.descriptor == continuationClassDescriptor) {
lastParameterType as IrSimpleType
// If the last parameter is Continuation<> inherit from SuspendFunction.
suspendFunctionClassDescriptor = kotlinPackageScope.getContributedClassifier(
Name.identifier("SuspendFunction${numberOfParameters - 1}"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) + lastParameterType.arguments.single().type
superTypes += suspendFunctionClassDescriptor.defaultType.replace(suspendFunctionClassTypeParameters)
superClasses += context.ir.symbols.suspendFunctions[numberOfParameters - 1].owner
suspendFunctionIrClass = context.ir.symbols.suspendFunctions[numberOfParameters - 1].owner
suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) +
(lastParameterType.arguments.single().typeOrNull ?: context.irBuiltIns.anyNType)
superTypes += suspendFunctionIrClass.symbol.typeWith(suspendFunctionClassTypeParameters)
}
functionReferenceClassDescriptor = object : ClassDescriptorImpl(
@@ -207,7 +204,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
/* name = */ "${functionDescriptor.name}\$${functionReferenceCount++}".synthesizedName,
/* modality = */ Modality.FINAL,
/* kind = */ ClassKind.CLASS,
/* superTypes = */ superTypes,
/* superTypes = */ superTypes.map { it.toKotlinType() },
/* source = */ SourceElement.NO_SOURCE,
/* isExternal = */ false,
/* storageManager = */ LockBasedStorageManager.NO_LOCKS
@@ -225,13 +222,15 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
val constructorBuilder = createConstructorBuilder()
val invokeFunctionDescriptor = functionClassDescriptor.getFunction("invoke", functionClassTypeParameters)
val invokeMethodBuilder = createInvokeMethodBuilder(invokeFunctionDescriptor)
val invokeFunctionSymbol =
functionIrClass.simpleFunctions().single { it.name.asString() == "invoke" }.symbol
val invokeMethodBuilder = createInvokeMethodBuilder(invokeFunctionSymbol, functionReferenceClass)
var suspendInvokeMethodBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>? = null
if (suspendFunctionClassDescriptor != null) {
val suspendInvokeFunctionDescriptor = suspendFunctionClassDescriptor.getFunction("invoke", suspendFunctionClassTypeParameters!!)
suspendInvokeMethodBuilder = createInvokeMethodBuilder(suspendInvokeFunctionDescriptor)
if (suspendFunctionIrClass != null) {
val suspendInvokeFunctionSymbol =
suspendFunctionIrClass.simpleFunctions().single { it.name.asString() == "invoke" }.symbol
suspendInvokeMethodBuilder = createInvokeMethodBuilder(suspendInvokeFunctionSymbol, functionReferenceClass)
}
val memberScope = stub<MemberScope>("callable reference class")
@@ -253,7 +252,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
functionReferenceClass.addChild(it.ir)
}
functionReferenceClass.setSuperSymbolsAndAddFakeOverrides(superClasses)
functionReferenceClass.setSuperSymbolsAndAddFakeOverrides(superTypes)
return BuiltFunctionReference(functionReferenceClass, constructorBuilder.ir)
}
@@ -275,15 +274,19 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
override fun doInitialize() {
val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
val constructorParameters = boundFunctionParameters.mapIndexed { index, parameter ->
parameter.copyAsValueParameter(descriptor, index)
parameter.descriptor.copyAsValueParameter(descriptor, index)
}
descriptor.initialize(constructorParameters, Visibilities.PUBLIC)
descriptor.returnType = functionReferenceClassDescriptor.defaultType
}
override fun buildIr(): IrConstructor {
val symbols = this@CallableReferenceLowering.context.ir.symbols
val irBuiltIns = context.irBuiltIns
argumentToPropertiesMap = boundFunctionParameters.associate {
it to buildPropertyWithBackingField(it.name, it.type, false)
it.descriptor to buildField(it.name, it.type, false)
}
val startOffset = functionReference.startOffset
@@ -294,30 +297,36 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
symbol = symbol).apply {
returnType = functionReferenceClass.defaultType
val irBuilder = context.createIrBuilder(this.symbol, startOffset, endOffset)
createParameterDeclarations()
boundFunctionParameters.mapIndexedTo(this.valueParameters) { index, parameter ->
parameter.copy(descriptor.valueParameters[index])
}
body = irBuilder.irBlockBody {
+IrDelegatingConstructorCallImpl(startOffset, endOffset,
kFunctionImplConstructorSymbol, kFunctionImplConstructorSymbol.descriptor).apply {
val name = IrConstImpl(startOffset, endOffset, context.builtIns.stringType,
context.irBuiltIns.unitType,
kFunctionImplConstructorSymbol, kFunctionImplConstructorSymbol.descriptor, 0).apply {
val stringType = irBuiltIns.stringType
val name = IrConstImpl(startOffset, endOffset, stringType,
IrConstKind.String, functionDescriptor.name.asString())
putValueArgument(0, name)
val fqName = IrConstImpl(startOffset, endOffset, context.builtIns.stringType, IrConstKind.String,
val fqName = IrConstImpl(startOffset, endOffset, stringType, IrConstKind.String,
(functionReference.symbol.owner).fullName)
putValueArgument(1, fqName)
val bound = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType,
val bound = IrConstImpl.boolean(startOffset, endOffset, context.irBuiltIns.booleanType,
boundFunctionParameters.isNotEmpty())
putValueArgument(2, bound)
val needReceiver = boundFunctionParameters.singleOrNull() is ReceiverParameterDescriptor
val receiver = if (needReceiver) irGet(valueParameters.single().symbol) else irNull()
val needReceiver = boundFunctionParameters.singleOrNull()?.descriptor is ReceiverParameterDescriptor
val receiver = if (needReceiver) irGet(valueParameters.single()) else irNull()
putValueArgument(3, receiver)
}
+IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol)
+IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, irBuiltIns.unitType)
// Save all arguments to fields.
boundFunctionParameters.forEachIndexed { index, parameter ->
+irSetField(irGet(functionReferenceThis), argumentToPropertiesMap[parameter]!!, irGet(valueParameters[index].symbol))
+irSetField(irGet(functionReferenceThis.owner), argumentToPropertiesMap[parameter.descriptor]!!, irGet(valueParameters[index]))
}
}
}
@@ -327,9 +336,11 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
private val IrFunction.fullName: String
get() = parent.fqNameSafe.child(Name.identifier(functionName)).asString()
private fun createInvokeMethodBuilder(superFunctionDescriptor: FunctionDescriptor)
private fun createInvokeMethodBuilder(superFunctionSymbol: IrSimpleFunctionSymbol, parent: IrClass)
= object : SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
val superFunctionDescriptor: FunctionDescriptor = superFunctionSymbol.descriptor
override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ functionReferenceClassDescriptor,
@@ -368,10 +379,18 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
symbol = ourSymbol).apply {
returnType = superFunctionSymbol.owner.returnType // FIXME: substitute
val function = this
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
createParameterDeclarations()
this.parent = parent
this.createDispatchReceiverParameter()
superFunctionSymbol.owner.valueParameters.mapTo(this.valueParameters) {
it.copy(descriptor.valueParameters[it.index]) // FIXME: substitute
}
body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn(
@@ -383,21 +402,21 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
if (!unboundArgsSet.contains(it))
// Bound parameter - read from field.
irGetField(
irGet(function.dispatchReceiverParameter!!.symbol),
argumentToPropertiesMap[it]!!
irGet(function.dispatchReceiverParameter!!),
argumentToPropertiesMap[it.descriptor]!!
)
else {
if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size)
// For suspend functions the last argument is continuation and it is implicit.
irCall(getContinuationSymbol,
listOf(ourSymbol.descriptor.returnType!!))
irCall(getContinuationSymbol.owner,
listOf(returnType))
else
irGet(valueParameters[unboundIndex++].symbol)
irGet(valueParameters[unboundIndex++])
}
when (it) {
functionDescriptor.dispatchReceiverParameter -> dispatchReceiver = argument
functionDescriptor.extensionReceiverParameter -> extensionReceiver = argument
else -> putValueArgument((it as ValueParameterDescriptor).index, argument)
irFunction.dispatchReceiverParameter -> dispatchReceiver = argument
irFunction.extensionReceiverParameter -> extensionReceiver = argument
else -> putValueArgument(it.index, argument)
}
}
assert(unboundIndex == valueParameters.size, { "Not all arguments of <invoke> are used" })
@@ -408,21 +427,17 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
}
}
private fun buildPropertyWithBackingField(name: Name, type: KotlinType, isMutable: Boolean): IrFieldSymbol {
val propertyBuilder = context.createPropertyWithBackingFieldBuilder(
startOffset = functionReference.startOffset,
endOffset = functionReference.endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
owner = functionReferenceClassDescriptor,
name = name,
type = type,
isMutable = isMutable).apply {
initialize()
}
functionReferenceClass.addChild(propertyBuilder.ir)
return propertyBuilder.ir.backingField!!.symbol
private fun buildField(name: Name, type: IrType, isMutable: Boolean): IrField = createField(
functionReference.startOffset,
functionReference.endOffset,
type,
name,
isMutable,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
functionReferenceClassDescriptor
).also {
functionReferenceClass.addChild(it)
}
}
}
@@ -4,10 +4,11 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer
import org.jetbrains.kotlin.backend.common.lower.at
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.types.isString
import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
@@ -29,14 +30,14 @@ internal class CompileTimeEvaluateLowering(val context: Context): FileLoweringPa
// TODO: refer functions more reliably.
if (elementsArr.elements.any { it is IrSpreadElement }
|| !elementsArr.elements.all { it is IrConst<*> && KotlinBuiltIns.isString(it.type) })
|| !elementsArr.elements.all { it is IrConst<*> && it.type.isString() })
return expression
builder.at(expression)
val typeArguments = descriptor.typeParameters.map { expression.getTypeArgument(it)!! }
return builder.irCall(context.ir.symbols.listOfInternal, typeArguments).apply {
val typeArgument = expression.getTypeArgument(0)!!
return builder.irCall(context.ir.symbols.listOfInternal.owner, listOf(typeArgument)).apply {
putValueArgument(0, elementsArr)
}
}
@@ -20,15 +20,15 @@ import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
internal class DataClassOperatorsLowering(val context: Context): FunctionLoweringPass {
@@ -45,40 +45,37 @@ internal class DataClassOperatorsLowering(val context: Context): FunctionLowerin
return expression
val argument = expression.getValueArgument(0)!!
val argumentType = argument.type.makeNotNullable()
val genericType =
if (argumentType.arguments.isEmpty())
argumentType
else
(argumentType.constructor.declarationDescriptor as ClassDescriptor).defaultType
val isToString = descriptor == irBuiltins.dataClassArrayMemberToString
val newSymbol = if (isToString)
context.ir.symbols.arrayContentToString[genericType]!!
val argumentClassifier = argument.type.classifierOrFail
val isToString = expression.symbol == irBuiltins.dataClassArrayMemberToStringSymbol
val newCalleeSymbol = if (isToString)
context.ir.symbols.arrayContentToString[argumentClassifier]!!
else
context.ir.symbols.arrayContentHashCode[genericType]!!
context.ir.symbols.arrayContentHashCode[argumentClassifier]!!
val newCallee = newCalleeSymbol.owner
val startOffset = expression.startOffset
val endOffset = expression.endOffset
val irBuilder = context.createIrBuilder(irFunction.symbol, startOffset, endOffset)
return irBuilder.run {
val typeArguments =
if (argumentType.arguments.isEmpty())
emptyList<KotlinType>()
else argumentType.arguments.map { it.type }
if (!argument.type.isMarkedNullable) {
irCall(newSymbol, typeArguments).apply {
// TODO: use more precise type arguments.
val typeArguments = (0 until newCallee.typeParameters.size).map { irBuiltins.anyNType }
if (!argument.type.isSimpleTypeWithQuestionMark) {
irCall(newCallee, typeArguments).apply {
extensionReceiver = argument
}
} else {
val tmp = scope.createTemporaryVariable(argument)
val call = irCall(newSymbol, typeArguments).apply {
extensionReceiver = irGet(tmp.symbol)
val call = irCall(newCallee, typeArguments).apply {
extensionReceiver = irGet(tmp)
}
irBlock(argument) {
+tmp
+irIfThenElse(call.type,
irEqeqeq(irGet(tmp.symbol), irNull()),
irEqeqeq(irGet(tmp), irNull()),
if (isToString)
irString("null")
else
@@ -24,14 +24,17 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.createClassSymbolOrNull
import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.createValueSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -46,7 +49,6 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.makeNullable
internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
val parentDescriptor: DeclarationDescriptor,
@@ -484,7 +486,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
return IrCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = newDescriptor.returnType!!,
type = context.ir.translateErased(newDescriptor.returnType!!),
descriptor = newDescriptor,
typeArgumentsCount = expression.typeArgumentsCount,
origin = expression.origin,
@@ -497,19 +499,100 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
//---------------------------------------------------------------------//
override fun visitFunction(declaration: IrFunction): IrFunction =
IrFunctionImpl(
startOffset = declaration.startOffset,
endOffset = declaration.endOffset,
origin = mapDeclarationOrigin(declaration.origin),
descriptor = mapFunctionDeclaration(declaration.descriptor),
body = declaration.body?.transform(this, null)
override fun visitSimpleFunction(declaration: IrSimpleFunction): IrFunction {
val descriptor = mapFunctionDeclaration(declaration.descriptor)
return IrFunctionImpl(
startOffset = declaration.startOffset,
endOffset = declaration.endOffset,
origin = mapDeclarationOrigin(declaration.origin),
descriptor = descriptor
).also {
it.returnType = context.ir.translateErased(descriptor.returnType!!)
it.body = declaration.body?.transform(this, null)
it.setOverrides(context.ir.symbols.symbolTable)
}.transformParameters(declaration)
}.transformParameters1(declaration)
}
override fun visitConstructor(declaration: IrConstructor): IrConstructor {
val descriptor = mapConstructorDeclaration(declaration.descriptor)
return IrConstructorImpl(
startOffset = declaration.startOffset,
endOffset = declaration.endOffset,
origin = mapDeclarationOrigin(declaration.origin),
descriptor = descriptor
).also {
it.returnType = context.ir.translateErased(descriptor.returnType)
it.body = declaration.body?.transform(this, null)
}.transformParameters1(declaration)
}
private fun FunctionDescriptor.getTypeParametersToTransform() =
when {
this is PropertyAccessorDescriptor -> correspondingProperty.typeParameters
else -> typeParameters
}
protected fun <T : IrFunction> T.transformParameters1(original: T): T =
apply {
transformTypeParameters(original, descriptor.getTypeParametersToTransform())
transformValueParameters1(original)
}
protected fun <T : IrFunction> T.transformValueParameters1(original: T) =
apply {
dispatchReceiverParameter =
original.dispatchReceiverParameter?.replaceDescriptor1(
descriptor.dispatchReceiverParameter ?: throw AssertionError("No dispatch receiver in $descriptor")
)
extensionReceiverParameter =
original.extensionReceiverParameter?.replaceDescriptor1(
descriptor.extensionReceiverParameter ?: throw AssertionError("No extension receiver in $descriptor")
)
original.valueParameters.mapIndexedTo(valueParameters) { i, originalValueParameter ->
originalValueParameter.replaceDescriptor1(descriptor.valueParameters[i])
}
}
protected fun IrValueParameter.replaceDescriptor1(newDescriptor: ParameterDescriptor) =
IrValueParameterImpl(
startOffset, endOffset,
mapDeclarationOrigin(origin),
newDescriptor,
context.ir.translateErased(newDescriptor.type),
(newDescriptor as? ValueParameterDescriptor)?.varargElementType?.let { context.ir.translateErased(it) },
defaultValue?.transform(this@InlineCopyIr, null)
).apply {
transformAnnotations(this)
}
//---------------------------------------------------------------------//
override fun visitGetValue(expression: IrGetValue): IrGetValue {
val descriptor = mapValueReference(expression.descriptor)
return IrGetValueImpl(
expression.startOffset, expression.endOffset,
context.ir.translateErased(descriptor.type),
descriptor,
mapStatementOrigin(expression.origin)
)
}
override fun visitVariable(declaration: IrVariable): IrVariable {
val descriptor = mapVariableDeclaration(declaration.descriptor)
return IrVariableImpl(
declaration.startOffset, declaration.endOffset,
mapDeclarationOrigin(declaration.origin),
descriptor,
context.ir.translateErased(descriptor.type),
declaration.initializer?.transform(this, null)
).apply {
transformAnnotations(declaration)
}
}
private fun <T : IrFunction> T.transformDefaults(original: T): T {
for (originalValueParameter in original.descriptor.valueParameters) {
val valueParameter = descriptor.valueParameters[originalValueParameter.index]
@@ -522,7 +605,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
//---------------------------------------------------------------------//
fun getTypeOperatorReturnType(operator: IrTypeOperator, type: KotlinType) : KotlinType {
fun getTypeOperatorReturnType(operator: IrTypeOperator, type: IrType) : IrType {
return when (operator) {
IrTypeOperator.CAST,
IrTypeOperator.IMPLICIT_CAST,
@@ -531,22 +614,24 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> type
IrTypeOperator.SAFE_CAST -> type.makeNullable()
IrTypeOperator.INSTANCEOF,
IrTypeOperator.NOT_INSTANCEOF -> context.builtIns.booleanType
IrTypeOperator.NOT_INSTANCEOF -> context.irBuiltIns.booleanType
}
}
//---------------------------------------------------------------------//
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall {
val typeOperand = substituteType(expression.typeOperand)!!
val returnType = getTypeOperatorReturnType(expression.operator, typeOperand)
val erasedTypeOperand = substituteAndEraseType(expression.typeOperand)!!
val typeOperand = substituteAndBreakType(expression.typeOperand)
val returnType = getTypeOperatorReturnType(expression.operator, erasedTypeOperand)
return IrTypeOperatorCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = returnType,
operator = expression.operator,
typeOperand = typeOperand,
argument = expression.argument.transform(this, null)
argument = expression.argument.transform(this, null),
typeOperandClassifier = (typeOperand as IrSimpleType).classifier
)
}
@@ -556,7 +641,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
IrReturnImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = substituteType(expression.type)!!,
type = substituteAndEraseType(expression.type)!!,
returnTargetDescriptor = mapReturnTarget(expression.returnTarget),
value = expression.value.transform(this, null)
)
@@ -577,7 +662,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
} else {
IrBlockImpl(
expression.startOffset, expression.endOffset,
substituteType(expression.type)!!,
substituteAndEraseType(expression.type)!!,
mapStatementOrigin(expression.origin),
expression.statements.map { it.transform(this, null) }
)
@@ -587,7 +672,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
//-------------------------------------------------------------------------//
override fun visitClassReference(expression: IrClassReference): IrClassReference {
val newExpressionType = substituteType(expression.type)!! // Substituted expression type.
val newExpressionType = substituteAndEraseType(expression.type)!! // Substituted expression type.
val newDescriptorType = substituteType(expression.descriptor.defaultType)!! // Substituted type of referenced class.
val classDescriptor = newDescriptorType.constructor.declarationDescriptor!! // Get ClassifierDescriptor of the referenced class.
return IrClassReferenceImpl(
@@ -602,7 +687,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
//-------------------------------------------------------------------------//
override fun visitGetClass(expression: IrGetClass): IrGetClass {
val type = substituteType(expression.type)!!
val type = substituteAndEraseType(expression.type)!!
return IrGetClassImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
@@ -616,6 +701,27 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
return irLoop
}
override fun visitClass(declaration: IrClass): IrClass {
val descriptor = this.mapClassDeclaration(declaration.descriptor)
return context.ir.symbols.symbolTable.declareClass(
declaration.startOffset, declaration.endOffset, mapDeclarationOrigin(declaration.origin),
descriptor
).apply {
declaration.declarations.mapTo(this.declarations) {
it.transform(this@InlineCopyIr, null) as IrDeclaration
}
this.transformAnnotations(declaration)
this.thisReceiver = declaration.thisReceiver?.replaceDescriptor1(this.descriptor.thisAsReceiverParameter)
this.transformTypeParameters(declaration, this.descriptor.declaredTypeParameters)
descriptor.defaultType.constructor.supertypes.mapTo(this.superTypes) {
context.ir.translateErased(it)
}
}
}
}
//-------------------------------------------------------------------------//
@@ -627,12 +733,24 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
return descriptorSubstituteMap[oldClassDescriptor]?.let { (it as ClassDescriptor).defaultType } ?: substitutedType
}
private fun substituteAndEraseType(oldType: IrType?): IrType? {
oldType ?: return null
val substitutedKotlinType = substituteType(oldType.toKotlinType())
?: return oldType
return context.ir.translateErased(substitutedKotlinType)
}
private fun substituteAndBreakType(oldType: IrType): IrType {
return context.ir.translateBroken(substituteType(oldType.toKotlinType())!!)
}
//-------------------------------------------------------------------------//
private fun IrMemberAccessExpression.substituteTypeArguments(original: IrMemberAccessExpression) {
for (index in 0 until original.typeArgumentsCount) {
val originalTypeArgument = original.getTypeArgument(index)
val newTypeArgument = substituteType(originalTypeArgument)!!
val newTypeArgument = substituteAndBreakType(originalTypeArgument!!)
this.putTypeArgument(index, newTypeArgument)
}
}
@@ -649,7 +767,10 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
class SubstitutedDescriptor(val inlinedFunction: FunctionDescriptor, val descriptor: DeclarationDescriptor)
class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>)
internal class DescriptorSubstitutorForExternalScope(
val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>,
val context: Context
)
: IrElementTransformerVoidWithContext() {
private val variableSubstituteMap = mutableMapOf<VariableDescriptor, VariableDescriptor>()
@@ -710,6 +831,7 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<
endOffset = declaration.endOffset,
origin = declaration.origin,
descriptor = newDescriptor,
type = context.ir.translateErased(newDescriptor.type),
initializer = declaration.initializer
)
}
@@ -725,6 +847,7 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<
return IrGetValueImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = context.ir.translateErased(newDescriptor.type),
origin = expression.origin,
symbol = createValueSymbol(newDescriptor)
)
@@ -743,7 +866,7 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<
return IrCallImpl(
startOffset = oldExpression.startOffset,
endOffset = oldExpression.endOffset,
type = newDescriptor.returnType!!,
type = context.ir.translateErased(newDescriptor.returnType!!),
symbol = createFunctionSymbol(newDescriptor),
descriptor = newDescriptor,
typeArgumentsCount = oldExpression.typeArgumentsCount,
@@ -1,471 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.builtIns
open class DefaultArgumentStubGenerator constructor(val context: CommonBackendContext): DeclarationContainerLoweringPass {
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
if (memberDeclaration is IrFunction)
lower(memberDeclaration).also { functions ->
functions.forEach {
it.parent = irDeclarationContainer
}
}
else
null
}
}
private val symbols = context.ir.symbols
private fun lower(irFunction: IrFunction): List<IrFunction> {
val functionDescriptor = irFunction.descriptor
if (!functionDescriptor.needsDefaultArgumentsLowering)
return listOf(irFunction)
val bodies = functionDescriptor.valueParameters
.mapNotNull{irFunction.getDefault(it)}
log { "detected ${functionDescriptor.name.asString()} has got #${bodies.size} default expressions" }
functionDescriptor.overriddenDescriptors.forEach { context.log{"DEFAULT-REPLACER: $it"} }
if (bodies.isNotEmpty()) {
val newIrFunction = functionDescriptor.generateDefaultsFunction(context)
newIrFunction.parent = irFunction.parent
val descriptor = newIrFunction.descriptor
log { "$functionDescriptor -> $descriptor" }
val builder = context.createIrBuilder(newIrFunction.symbol)
newIrFunction.body = builder.irBlockBody(newIrFunction) {
val params = mutableListOf<IrVariableSymbol>()
val variables = mutableMapOf<ValueDescriptor, IrValueSymbol>()
irFunction.dispatchReceiverParameter?.let {
variables[it.descriptor] = newIrFunction.dispatchReceiverParameter!!.symbol
}
if (descriptor.extensionReceiverParameter != null) {
variables[functionDescriptor.extensionReceiverParameter!!] =
newIrFunction.extensionReceiverParameter!!.symbol
}
for (valueParameter in functionDescriptor.valueParameters) {
val parameterSymbol = newIrFunction.valueParameters[valueParameter.index].symbol
val temporaryVariableSymbol =
IrVariableSymbolImpl(scope.createTemporaryVariableDescriptor(parameterSymbol.descriptor))
params.add(temporaryVariableSymbol)
variables.put(valueParameter, temporaryVariableSymbol)
if (valueParameter.hasDefaultValue()) {
val kIntAnd = symbols.intAnd
val condition = irNotEquals(irCall(kIntAnd).apply {
dispatchReceiver = irGet(maskParameterSymbol(newIrFunction, valueParameter.index / 32))
putValueArgument(0, irInt(1 shl (valueParameter.index % 32)))
}, irInt(0))
val expressionBody = getDefaultParameterExpressionBody(irFunction, valueParameter)
/* Use previously calculated values in next expression. */
expressionBody.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
log { "GetValue: ${expression.descriptor}" }
val valueSymbol = variables[expression.descriptor] ?: return expression
return irGet(valueSymbol)
}
})
val variableInitialization = irIfThenElse(
type = temporaryVariableSymbol.descriptor.type,
condition = condition,
thenPart = expressionBody.expression,
elsePart = irGet(parameterSymbol))
+ scope.createTemporaryVariable(
symbol = temporaryVariableSymbol,
initializer = variableInitialization)
/* Mapping calculated values with its origin variables. */
} else {
+ scope.createTemporaryVariable(
symbol = temporaryVariableSymbol,
initializer = irGet(parameterSymbol))
}
}
if (irFunction is IrConstructor) {
+ IrDelegatingConstructorCallImpl(
startOffset = irFunction.startOffset,
endOffset = irFunction.endOffset,
symbol = irFunction.symbol, descriptor = irFunction.symbol.descriptor
).apply {
params.forEachIndexed { i, variable ->
putValueArgument(i, irGet(variable))
}
if (functionDescriptor.dispatchReceiverParameter != null) {
dispatchReceiver = irGet(newIrFunction.dispatchReceiverParameter!!.symbol)
}
}
} else {
+irReturn(irCall(irFunction.symbol).apply {
if (functionDescriptor.dispatchReceiverParameter != null) {
dispatchReceiver = irGet(newIrFunction.dispatchReceiverParameter!!.symbol)
}
if (functionDescriptor.extensionReceiverParameter != null) {
extensionReceiver = irGet(variables[functionDescriptor.extensionReceiverParameter!!]!!)
}
params.forEachIndexed { i, variable ->
putValueArgument(i, irGet(variable))
}
})
}
}
// Remove default argument initializers.
irFunction.valueParameters.forEach {
it.defaultValue = null
}
return listOf(irFunction, newIrFunction)
}
return listOf(irFunction)
}
private fun log(msg: () -> String) = context.log { "DEFAULT-REPLACER: ${msg()}" }
}
private fun Scope.createTemporaryVariableDescriptor(parameterDescriptor: ParameterDescriptor?): VariableDescriptor =
IrTemporaryVariableDescriptorImpl(
containingDeclaration = this.scopeOwner,
name = parameterDescriptor!!.name.asString().synthesizedName,
outType = parameterDescriptor.type,
isMutable = false)
private fun Scope.createTemporaryVariable(symbol: IrVariableSymbol, initializer: IrExpression) =
IrVariableImpl(
startOffset = initializer.startOffset,
endOffset = initializer.endOffset,
origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
symbol = symbol).apply {
this.initializer = initializer
}
private fun getDefaultParameterExpressionBody(irFunction: IrFunction, valueParameter: ValueParameterDescriptor): IrExpressionBody {
return irFunction.getDefault(valueParameter) ?: TODO("FIXME!!!")
}
private fun maskParameterDescriptor(function: IrFunction, number: Int) =
maskParameterSymbol(function, number).descriptor as ValueParameterDescriptor
private fun maskParameterSymbol(function: IrFunction, number: Int) =
function.valueParameters.single { it.descriptor.name == parameterMaskName(number) }.symbol
private fun markerParameterDescriptor(descriptor: FunctionDescriptor) = descriptor.valueParameters.single { it.name == kConstructorMarkerName }
fun nullConst(expression: IrElement, type: KotlinType) = when {
KotlinBuiltIns.isFloat(type) -> IrConstImpl.float (expression.startOffset, expression.endOffset, type, 0.0F)
KotlinBuiltIns.isDouble(type) -> IrConstImpl.double (expression.startOffset, expression.endOffset, type, 0.0)
KotlinBuiltIns.isBoolean(type) -> IrConstImpl.boolean (expression.startOffset, expression.endOffset, type, false)
KotlinBuiltIns.isByte(type) -> IrConstImpl.byte (expression.startOffset, expression.endOffset, type, 0)
KotlinBuiltIns.isChar(type) -> IrConstImpl.char (expression.startOffset, expression.endOffset, type, 0.toChar())
KotlinBuiltIns.isShort(type) -> IrConstImpl.short (expression.startOffset, expression.endOffset, type, 0)
KotlinBuiltIns.isInt(type) -> IrConstImpl.int (expression.startOffset, expression.endOffset, type, 0)
KotlinBuiltIns.isLong(type) -> IrConstImpl.long (expression.startOffset, expression.endOffset, type, 0)
else -> IrConstImpl.constNull (expression.startOffset, expression.endOffset, type.builtIns.nullableNothingType)
}
class DefaultParameterInjector constructor(val context: CommonBackendContext): BodyLoweringPass {
override fun lower(irBody: IrBody) {
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
super.visitDelegatingConstructorCall(expression)
val descriptor = expression.descriptor
if (!descriptor.needsDefaultArgumentsLowering)
return expression
val argumentsCount = argumentCount(expression)
if (argumentsCount == descriptor.valueParameters.size)
return expression
val (symbolForCall, params) = parametersForCall(expression)
return IrDelegatingConstructorCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
symbol = symbolForCall as IrConstructorSymbol,
descriptor = symbolForCall.descriptor)
.apply {
params.forEach {
log { "call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}" }
putValueArgument(it.first.index, it.second)
}
dispatchReceiver = expression.dispatchReceiver
}
}
override fun visitCall(expression: IrCall): IrExpression {
super.visitCall(expression)
val functionDescriptor = expression.descriptor
if (!functionDescriptor.needsDefaultArgumentsLowering)
return expression
val argumentsCount = argumentCount(expression)
if (argumentsCount == functionDescriptor.valueParameters.size)
return expression
val (symbol, params) = parametersForCall(expression)
val descriptor = symbol.descriptor
descriptor.typeParameters.forEach { log { "$descriptor [${it.index}]: $it" } }
descriptor.original.typeParameters.forEach { log { "${descriptor.original}[${it.index}] : $it" } }
return IrCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
symbol = symbol,
descriptor = descriptor,
typeArguments = expression.descriptor.typeParameters.map{it to (expression.getTypeArgument(it) ?: it.defaultType) }.toMap())
.apply {
params.forEach {
log { "call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}" }
putValueArgument(it.first.index, it.second)
}
expression.extensionReceiver?.apply{
extensionReceiver = expression.extensionReceiver
}
expression.dispatchReceiver?.apply {
dispatchReceiver = expression.dispatchReceiver
}
log { "call::extension@: ${ir2string(expression.extensionReceiver)}" }
log { "call::dispatch@: ${ir2string(expression.dispatchReceiver)}" }
}
}
private fun IrFunction.findSuperMethodWithDefaultArguments(): IrFunction? {
if (!this.descriptor.needsDefaultArgumentsLowering) return null
if (this !is IrSimpleFunction) return this
this.overriddenSymbols.forEach {
it.owner.findSuperMethodWithDefaultArguments()?.let { return it }
}
return this
}
private fun parametersForCall(expression: IrFunctionAccessExpression): Pair<IrFunctionSymbol, List<Pair<ValueParameterDescriptor, IrExpression?>>> {
val descriptor = expression.descriptor
val keyFunction = expression.symbol.owner.findSuperMethodWithDefaultArguments()!!
val keyDescriptor = keyFunction.descriptor
val realFunction = keyDescriptor.generateDefaultsFunction(context)
realFunction.parent = keyFunction.parent
val realDescriptor = realFunction.descriptor
log { "$descriptor -> $realDescriptor" }
val maskValues = Array((descriptor.valueParameters.size + 31) / 32, { 0 })
val params = mutableListOf<Pair<ValueParameterDescriptor, IrExpression?>>()
params.addAll(descriptor.valueParameters.mapIndexed { i, _ ->
val valueArgument = expression.getValueArgument(i)
if (valueArgument == null) {
val maskIndex = i / 32
maskValues[maskIndex] = maskValues[maskIndex] or (1 shl (i % 32))
}
val valueParameterDescriptor = realDescriptor.valueParameters[i]
val defaultValueArgument = if (valueParameterDescriptor.isVararg) null else nullConst(expression, valueParameterDescriptor.type)
valueParameterDescriptor to (valueArgument ?: defaultValueArgument)
})
maskValues.forEachIndexed { i, maskValue ->
params += maskParameterDescriptor(realFunction, i) to IrConstImpl.int(
startOffset = irBody.startOffset,
endOffset = irBody.endOffset,
type = descriptor.builtIns.intType,
value = maskValue)
}
if (expression.descriptor is ClassConstructorDescriptor) {
val defaultArgumentMarker = context.ir.symbols.defaultConstructorMarker
params += markerParameterDescriptor(realDescriptor) to IrGetObjectValueImpl(
startOffset = irBody.startOffset,
endOffset = irBody.endOffset,
type = defaultArgumentMarker.owner.defaultType,
symbol = defaultArgumentMarker)
}
else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
params += realDescriptor.valueParameters.last() to
IrConstImpl.constNull(irBody.startOffset, irBody.endOffset, context.builtIns.any.defaultType)
}
params.forEach {
log { "descriptor::${realDescriptor.name.asString()}#${it.first.index}: ${it.first.name.asString()}" }
}
return Pair(realFunction.symbol, params)
}
private fun argumentCount(expression: IrMemberAccessExpression) =
expression.descriptor.valueParameters.count { expression.getValueArgument(it) != null }
})
}
private fun log(msg: () -> String) = context.log { "DEFAULT-INJECTOR: ${msg()}" }
}
private val CallableMemberDescriptor.needsDefaultArgumentsLowering
get() = valueParameters.any { it.hasDefaultValue() } && !(this is FunctionDescriptor && isInline)
private fun FunctionDescriptor.generateDefaultsFunction(context: CommonBackendContext): IrFunction {
return context.ir.defaultParameterDeclarationsCache.getOrPut(this) {
val descriptor = when (this) {
is ClassConstructorDescriptor ->
ClassConstructorDescriptorImpl.create(
/* containingDeclaration = */ containingDeclaration,
/* annotations = */ annotations,
/* isPrimary = */ false,
/* source = */ source)
else -> {
val name = Name.identifier("$name\$default")
SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ containingDeclaration,
/* annotations = */ annotations,
/* name = */ name,
/* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED,
/* source = */ source)
}
}
val syntheticParameters = MutableList((valueParameters.size + 31) / 32) { i ->
valueParameter(descriptor, valueParameters.size + i, parameterMaskName(i), descriptor.builtIns.intType)
}
if (this is ClassConstructorDescriptor) {
syntheticParameters += valueParameter(descriptor, syntheticParameters.last().index + 1,
kConstructorMarkerName,
context.ir.symbols.defaultConstructorMarker.owner.defaultType)
}
else if (context.ir.shouldGenerateHandlerParameterForDefaultBodyFun()) {
syntheticParameters += valueParameter(descriptor, syntheticParameters.last().index + 1,
"handler".synthesizedName,
context.ir.symbols.any.owner.defaultType)
}
descriptor.initialize(
/* receiverParameterType = */ extensionReceiverParameter?.type,
/* dispatchReceiverParameter = */ dispatchReceiverParameter,
/* typeParameters = */ typeParameters.map {
TypeParameterDescriptorImpl.createForFurtherModification(
/* containingDeclaration = */ descriptor,
/* annotations = */ it.annotations,
/* reified = */ it.isReified,
/* variance = */ it.variance,
/* name = */ it.name,
/* index = */ it.index,
/* source = */ it.source,
/* reportCycleError = */ null,
/* supertypeLoopsChecker = */ SupertypeLoopChecker.EMPTY
).apply {
it.upperBounds.forEach { addUpperBound(it) }
setInitialized()
}
},
/* unsubstitutedValueParameters = */ valueParameters.map {
ValueParameterDescriptorImpl(
containingDeclaration = descriptor,
original = null, /* ValueParameterDescriptorImpl::copy do not save original. */
index = it.index,
annotations = it.annotations,
name = it.name,
outType = it.type,
declaresDefaultValue = false,
isCrossinline = it.isCrossinline,
isNoinline = it.isNoinline,
varargElementType = it.varargElementType,
source = it.source)
} + syntheticParameters,
/* unsubstitutedReturnType = */ returnType,
/* modality = */ Modality.FINAL,
/* visibility = */ this.visibility)
descriptor.isSuspend = this.isSuspend
context.log{"adds to cache[$this] = $descriptor"}
val startOffset = this.startOffsetOrUndefined
val endOffset = this.endOffsetOrUndefined
val result: IrFunction = when (descriptor) {
is ClassConstructorDescriptor -> IrConstructorImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
descriptor
)
else -> IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER,
descriptor
)
}
result.createParameterDeclarations()
result
}
}
object DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER :
IrDeclarationOriginImpl("DEFAULT_PARAMETER_EXTENT")
private fun valueParameter(descriptor: FunctionDescriptor, index: Int, name: Name, type: KotlinType): ValueParameterDescriptor {
return ValueParameterDescriptorImpl(
containingDeclaration = descriptor,
original = null,
index = index,
annotations = Annotations.EMPTY,
name = name,
outType = type,
declaresDefaultValue = false,
isCrossinline = false,
isNoinline = false,
varargElementType = null,
source = SourceElement.NO_SOURCE
)
}
internal val kConstructorMarkerName = "marker".synthesizedName
private fun parameterMaskName(number: Int) = "mask$number".synthesizedName
@@ -16,15 +16,13 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.backend.jvm.descriptors.initialize
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.ir.createArrayOfExpression
import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
@@ -35,15 +33,14 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrLocalDelegatedProperty
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrLocalDelegatedPropertyReference
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.util.addChild
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
@@ -55,10 +52,10 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
private val reflectionTypes = context.reflectionTypes
private var tempIndex = 0
private fun getKPropertyImplConstructor(receiverTypes: List<KotlinType>,
returnType: KotlinType,
private fun getKPropertyImplConstructor(receiverTypes: List<IrType>,
returnType: IrType,
isLocal: Boolean,
isMutable: Boolean) : Pair<IrConstructorSymbol, Map<TypeParameterDescriptor, KotlinType>> {
isMutable: Boolean) : Pair<IrConstructorSymbol, List<IrType>> {
val symbols = context.ir.symbols
@@ -87,10 +84,7 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
}
}
val typeParameters = classSymbol.descriptor.declaredTypeParameters
val arguments = (receiverTypes + listOf(returnType))
.mapIndexed { index, type -> typeParameters[index] to type }
.toMap()
return classSymbol.constructors.single() to arguments
}
@@ -102,17 +96,21 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
override fun lower(irFile: IrFile) {
val kProperties = mutableMapOf<VariableDescriptorWithAccessors, Pair<IrExpression, Int>>()
val arrayClass = context.ir.symbols.array
val arrayClass = context.ir.symbols.array.owner
val arrayItemGetter = arrayClass.functions.single { it.descriptor.name == Name.identifier("get") }
val kPropertyImplType = reflectionTypes.kProperty1Impl.replace(context.builtIns.anyType, context.builtIns.anyType)
val anyType = context.irBuiltIns.anyType
val kPropertyImplType = context.ir.symbols.kProperty1Impl.typeWith(anyType, anyType)
val kPropertiesFieldType: IrType = context.ir.symbols.array.typeWith(kPropertyImplType)
val kPropertiesField = IrFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
createKPropertiesFieldDescriptor(irFile.packageFragmentDescriptor,
context.builtIns.array.replace(kPropertyImplType)
)
kPropertiesFieldType.toKotlinType()
),
kPropertiesFieldType
)
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
@@ -148,11 +146,9 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
createKProperty(expression, this) to kProperties.size
}
return irCall(arrayItemGetter, typeArguments = listOf(kPropertyImplType)).apply {
dispatchReceiver =
IrGetFieldImpl(expression.startOffset, expression.endOffset, kPropertiesField.symbol)
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, field.second))
return irCall(arrayItemGetter).apply {
dispatchReceiver = irGetField(null, kPropertiesField)
putValueArgument(0, irInt(field.second))
}
}
}
@@ -173,14 +169,16 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
else { // Cache KProperties with no arguments.
// TODO: what about `receiversCount == 1` case?
val field = kProperties.getOrPut(propertyDescriptor) {
createLocalKProperty(propertyDescriptor, this) to kProperties.size
createLocalKProperty(
propertyDescriptor,
expression.getter.owner.returnType,
this
) to kProperties.size
}
return irCall(arrayItemGetter, typeArguments = listOf(kPropertyImplType)).apply {
dispatchReceiver =
IrGetFieldImpl(expression.startOffset, expression.endOffset, kPropertiesField.symbol)
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, field.second))
return irCall(arrayItemGetter).apply {
dispatchReceiver = irGetField(null, kPropertiesField)
putValueArgument(0, irInt(field.second))
}
}
}
@@ -203,23 +201,23 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
val startOffset = expression.startOffset
val endOffset = expression.endOffset
return irBuilder.irBlock(expression) {
val receiverTypes = mutableListOf<KotlinType>()
val receiverTypes = mutableListOf<IrType>()
val dispatchReceiver = expression.dispatchReceiver.let {
if (it == null)
null
else
irTemporary(value = it, nameHint = "\$dispatchReceiver${tempIndex++}").symbol
irTemporary(value = it, nameHint = "\$dispatchReceiver${tempIndex++}")
}
val extensionReceiver = expression.extensionReceiver.let {
if (it == null)
null
else
irTemporary(value = it, nameHint = "\$extensionReceiver${tempIndex++}").symbol
irTemporary(value = it, nameHint = "\$extensionReceiver${tempIndex++}")
}
val propertyDescriptor = expression.descriptor
val returnType = expression.getter?.owner?.returnType ?: expression.field!!.owner.type
val returnType = propertyDescriptor.type
val getterCallableReference = propertyDescriptor.getter?.let { getter ->
val getterCallableReference = expression.getter?.owner?.let { getter ->
getter.extensionReceiverParameter.let {
if (it != null && expression.extensionReceiver == null)
receiverTypes.add(it.type)
@@ -228,39 +226,37 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
if (it != null && expression.dispatchReceiver == null)
receiverTypes.add(it.type)
}
val getterKFunctionType = reflectionTypes.getKFunctionType(
annotations = Annotations.EMPTY,
receiverType = receiverTypes.firstOrNull(),
parameterTypes = if (receiverTypes.size < 2) listOf() else listOf(receiverTypes[1]),
returnType = returnType)
val getterKFunctionType = this@PropertyDelegationLowering.context.ir.symbols.getKFunctionType(
returnType,
receiverTypes
)
IrFunctionReferenceImpl(
startOffset = startOffset,
endOffset = endOffset,
type = getterKFunctionType,
symbol = expression.getter!!,
descriptor = getter,
typeArguments = null
descriptor = getter.descriptor,
typeArgumentsCount = 0
).apply {
this.dispatchReceiver = dispatchReceiver?.let { irGet(it) }
this.extensionReceiver = extensionReceiver?.let { irGet(it) }
}
}
val setterCallableReference = propertyDescriptor.setter?.let {
if (!isKMutablePropertyType(expression.type)) null
val setterCallableReference = expression.setter?.owner?.let {
if (!isKMutablePropertyType(expression.type.toKotlinType())) null
else {
val setterKFunctionType = reflectionTypes.getKFunctionType(
annotations = Annotations.EMPTY,
receiverType = receiverTypes.firstOrNull(),
parameterTypes = if (receiverTypes.size < 2) listOf(returnType) else listOf(receiverTypes[1], returnType),
returnType = context.builtIns.unitType)
val setterKFunctionType = this@PropertyDelegationLowering.context.ir.symbols.getKFunctionType(
context.irBuiltIns.unitType,
receiverTypes + returnType
)
IrFunctionReferenceImpl(
startOffset = startOffset,
endOffset = endOffset,
type = setterKFunctionType,
symbol = expression.setter!!,
descriptor = it,
typeArguments = null
descriptor = it.descriptor,
typeArgumentsCount = 0
).apply {
this.dispatchReceiver = dispatchReceiver?.let { irGet(it) }
this.extensionReceiver = extensionReceiver?.let { irGet(it) }
@@ -273,7 +269,7 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
returnType = returnType,
isLocal = false,
isMutable = setterCallableReference != null)
val initializer = irCall(symbol, constructorTypeArguments).apply {
val initializer = irCall(symbol.owner, constructorTypeArguments).apply {
putValueArgument(0, irString(propertyDescriptor.name.asString()))
if (getterCallableReference != null)
putValueArgument(1, getterCallableReference)
@@ -285,16 +281,15 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
}
private fun createLocalKProperty(propertyDescriptor: VariableDescriptorWithAccessors,
propertyType: IrType,
irBuilder: IrBuilderWithScope): IrExpression {
irBuilder.run {
val returnType = propertyDescriptor.type
val (symbol, constructorTypeArguments) = getKPropertyImplConstructor(
receiverTypes = emptyList(),
returnType = returnType,
returnType = propertyType,
isLocal = true,
isMutable = false)
val initializer = irCall(symbol, constructorTypeArguments).apply {
val initializer = irCall(symbol.owner, constructorTypeArguments).apply {
putValueArgument(0, irString(propertyDescriptor.name.asString()))
}
return initializer
@@ -316,10 +311,15 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
private object DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION :
IrDeclarationOriginImpl("KPROPERTIES_FOR_DELEGATION")
private fun createKPropertiesFieldDescriptor(containingDeclaration: DeclarationDescriptor, fieldType: SimpleType): PropertyDescriptorImpl {
private fun createKPropertiesFieldDescriptor(containingDeclaration: DeclarationDescriptor, fieldType: KotlinType): PropertyDescriptorImpl {
return PropertyDescriptorImpl.create(containingDeclaration, Annotations.EMPTY, Modality.FINAL, Visibilities.PRIVATE,
false, "KPROPERTIES".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE,
false, false, false, false, false, false).initialize(fieldType)
false, false, false, false, false, false).apply {
val receiverType: KotlinType? = null
this.setType(fieldType, emptyList(), null, receiverType)
this.initialize(null, null)
}
}
}
@@ -20,16 +20,19 @@ import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.jvm.descriptors.createValueParameter
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor
import org.jetbrains.kotlin.backend.common.ir.createArrayOfExpression
import org.jetbrains.kotlin.backend.common.ir.createSimpleDelegatingConstructorDescriptor
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement
@@ -38,61 +41,60 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.*
internal class EnumSyntheticFunctionsBuilder(val context: Context) {
fun buildValuesExpression(startOffset: Int, endOffset: Int,
enumClassDescriptor: ClassDescriptor): IrExpression {
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor)
enumClass: IrClass): IrExpression {
val typeParameterT = genericValuesDescriptor.typeParameters[0]
val enumClassType = enumClassDescriptor.defaultType
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumClassType)))
val substitutedValueOf = genericValuesDescriptor.substitute(typeSubstitutor)!!
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClass)
return IrCallImpl(startOffset, endOffset,
genericValuesSymbol, substitutedValueOf, mapOf(typeParameterT to enumClassType))
return irCall(startOffset, endOffset, genericValuesSymbol.owner, listOf(enumClass.defaultType))
.apply {
val receiver = IrGetObjectValueImpl(startOffset, endOffset,
loweredEnum.implObject.defaultType, loweredEnum.implObject.symbol)
putValueArgument(0, IrGetFieldImpl(startOffset, endOffset, loweredEnum.valuesField.symbol, receiver))
loweredEnum.implObject.defaultType,
loweredEnum.implObject.symbol)
putValueArgument(0, IrGetFieldImpl(
startOffset,
endOffset,
loweredEnum.valuesField.symbol,
loweredEnum.valuesField.type,
receiver
))
}
}
fun buildValueOfExpression(startOffset: Int, endOffset: Int,
enumClassDescriptor: ClassDescriptor,
enumClass: IrClass,
value: IrExpression): IrExpression {
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor)
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClass)
val typeParameterT = genericValueOfDescriptor.typeParameters[0]
val enumClassType = enumClassDescriptor.defaultType
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumClassType)))
val substitutedValueOf = genericValueOfDescriptor.substitute(typeSubstitutor)!!
return IrCallImpl(startOffset, endOffset,
genericValueOfSymbol, substitutedValueOf, mapOf(typeParameterT to enumClassType))
return irCall(startOffset, endOffset, genericValueOfSymbol.owner, listOf(enumClass.defaultType))
.apply {
putValueArgument(0, value)
val receiver = IrGetObjectValueImpl(startOffset, endOffset,
loweredEnum.implObject.defaultType, loweredEnum.implObject.symbol)
putValueArgument(1, IrGetFieldImpl(startOffset, endOffset, loweredEnum.valuesField.symbol, receiver))
putValueArgument(1, IrGetFieldImpl(
startOffset,
endOffset,
loweredEnum.valuesField.symbol,
loweredEnum.valuesField.type,
receiver
))
}
}
private val genericValueOfSymbol = context.ir.symbols.valueOfForEnum
private val genericValueOfDescriptor = genericValueOfSymbol.descriptor
private val genericValuesSymbol = context.ir.symbols.valuesForEnum
private val genericValuesDescriptor = genericValuesSymbol.descriptor
}
internal class EnumUsageLowering(val context: Context)
@@ -105,16 +107,13 @@ internal class EnumUsageLowering(val context: Context)
}
override fun visitGetEnumValue(expression: IrGetEnumValue): IrExpression {
val enumClassDescriptor = expression.descriptor.containingDeclaration as ClassDescriptor
return loadEnumEntry(expression.startOffset, expression.endOffset, enumClassDescriptor, expression.descriptor.name)
}
// TODO: remove as soon IR is fixed (there should no be any enum get with GET_OBJECT operation).
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
if (expression.descriptor.kind != ClassKind.ENUM_ENTRY)
return super.visitGetObjectValue(expression)
val enumClassDescriptor = expression.descriptor.containingDeclaration as ClassDescriptor
return loadEnumEntry(expression.startOffset, expression.endOffset, enumClassDescriptor, expression.descriptor.name)
val entry = expression.symbol.owner
return loadEnumEntry(
expression.startOffset,
expression.endOffset,
entry.parentAsClass,
entry.name
)
}
override fun visitCall(expression: IrCall): IrExpression {
@@ -125,18 +124,20 @@ internal class EnumUsageLowering(val context: Context)
if (descriptor.original != enumValuesDescriptor && descriptor.original != enumValueOfDescriptor)
return expression
val genericT = descriptor.original.typeParameters[0]
val substitutedT = expression.getTypeArgument(genericT)!!
val classDescriptor = substitutedT.constructor.declarationDescriptor as? ClassDescriptor
val irClassSymbol = expression.getTypeArgument(0)!!.classifierOrNull as? IrClassSymbol
?: return expression // Type parameter.
assert (classDescriptor.kind == ClassKind.ENUM_CLASS)
if (irClassSymbol == context.ir.symbols.enum) return expression // Type parameter erased to 'Enum'.
val irClass = irClassSymbol.owner
assert (irClass.kind == ClassKind.ENUM_CLASS)
return if (descriptor.original == enumValuesDescriptor) {
enumSyntheticFunctionsBuilder.buildValuesExpression(expression.startOffset, expression.endOffset, classDescriptor)
enumSyntheticFunctionsBuilder.buildValuesExpression(expression.startOffset, expression.endOffset, irClass)
} else {
val value = expression.getValueArgument(0)!!
enumSyntheticFunctionsBuilder.buildValueOfExpression(expression.startOffset, expression.endOffset, classDescriptor, value)
enumSyntheticFunctionsBuilder.buildValueOfExpression(expression.startOffset, expression.endOffset, irClass, value)
}
}
@@ -146,12 +147,12 @@ internal class EnumUsageLowering(val context: Context)
private val enumValuesSymbol = context.ir.symbols.enumValues
private val enumValuesDescriptor = enumValuesSymbol.descriptor
private fun loadEnumEntry(startOffset: Int, endOffset: Int, enumClassDescriptor: ClassDescriptor, name: Name): IrExpression {
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor)
private fun loadEnumEntry(startOffset: Int, endOffset: Int, enumClass: IrClass, name: Name): IrExpression {
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClass)
val ordinal = loweredEnum.entriesMap[name]!!
return IrCallImpl(startOffset, endOffset, loweredEnum.itemGetterSymbol, loweredEnum.itemGetterDescriptor).apply {
dispatchReceiver = IrCallImpl(startOffset, endOffset, loweredEnum.valuesGetter.symbol)
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, enumClassDescriptor.module.builtIns.intType, ordinal))
return irCall(startOffset, endOffset, loweredEnum.itemGetterSymbol.owner, emptyList()).apply {
dispatchReceiver = IrCallImpl(startOffset, endOffset, loweredEnum.valuesGetter.returnType, loweredEnum.valuesGetter.symbol)
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, ordinal))
}
}
}
@@ -178,7 +179,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
private inner class EnumClassTransformer(val irClass: IrClass) {
private val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(irClass.descriptor)
private val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(irClass)
private val loweredEnumConstructors = mutableMapOf<ClassConstructorDescriptor, IrConstructor>()
private val descriptorToIrConstructorWithDefaultArguments = mutableMapOf<ClassConstructorDescriptor, IrConstructor>()
private val defaultEnumEntryConstructors = mutableMapOf<ClassConstructorDescriptor, IrConstructor>()
@@ -212,7 +213,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
blockBody.statements.transformFlat {
if (it is IrEnumConstructorCall)
listOf(it, IrInstanceInitializerCallImpl(declaration.startOffset, declaration.startOffset,
irClass.symbol))
irClass.symbol, context.irBuiltIns.unitType))
else null
}
}
@@ -245,17 +246,22 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val defaultClassDescriptor = ClassDescriptorImpl(descriptor, "DEFAULT".synthesizedName, Modality.FINAL,
ClassKind.CLASS, listOf(descriptor.defaultType), SourceElement.NO_SOURCE, false, LockBasedStorageManager.NO_LOCKS)
val defaultClass = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, defaultClassDescriptor)
defaultClass.createParameterDeclarations()
val constructors = mutableSetOf<ClassConstructorDescriptor>()
descriptor.constructors.forEach {
val loweredEnumConstructorSymbol = loweredEnumConstructors[it]!!.symbol
val loweredEnumConstructor = loweredEnumConstructorSymbol.descriptor
val constructorDescriptor = defaultClassDescriptor.createSimpleDelegatingConstructorDescriptor(loweredEnumConstructor)
val loweredEnumIrConstructor = loweredEnumConstructors[it]!!
val loweredEnumConstructor = loweredEnumIrConstructor.descriptor
val constructor = defaultClass.addSimpleDelegatingConstructor(
loweredEnumConstructorSymbol, constructorDescriptor,
DECLARATION_ORIGIN_ENUM)
loweredEnumIrConstructor,
context.irBuiltIns,
DECLARATION_ORIGIN_ENUM
)
val constructorDescriptor = constructor.descriptor
constructors.add(constructorDescriptor)
defaultEnumEntryConstructors.put(loweredEnumConstructor, constructor)
@@ -273,8 +279,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val memberScope = stub<MemberScope>("enum default class")
defaultClassDescriptor.initialize(memberScope, constructors, null)
defaultClass.createParameterDeclarations()
defaultClass.setSuperSymbolsAndAddFakeOverrides(listOf(irClass))
defaultClass.setSuperSymbolsAndAddFakeOverrides(listOf(irClass.defaultType))
return defaultClass
}
@@ -310,12 +315,6 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
++i
}
val constructorOfAny = context.ir.symbols.any.constructors.single()
implObject.addSimpleDelegatingConstructor(
constructorOfAny, implObject.descriptor.constructors.single(),
DECLARATION_ORIGIN_ENUM)
implObject.addChild(createSyntheticValuesPropertyDeclaration(enumEntries))
implObject.addChild(createValuesPropertyInitializer(enumEntries))
@@ -329,17 +328,19 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
val irValuesInitializer = context.createArrayOfExpression(irClass.descriptor.defaultType,
val irValuesInitializer = context.createArrayOfExpression(irClass.defaultType,
enumEntries
.sortedBy { it.descriptor.name }
.map {
val enumEntryClass = ((it.initializerExpression!! as IrCall).descriptor as ConstructorDescriptor).constructedClass
val typeParameterT = genericCreateUninitializedInstanceDescriptor.typeParameters[0]
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumEntryClass.defaultType)))
val substitutedCreateUninitializedInstance = genericCreateUninitializedInstanceDescriptor.substitute(typeSubstitutor)!!
IrCallImpl(startOffset, endOffset,
genericCreateUninitializedInstanceSymbol, substitutedCreateUninitializedInstance, mapOf(typeParameterT to enumEntryClass.defaultType)
val entryConstructorCall = it.initializerExpression!! as IrCall
val entryConstructor = entryConstructorCall.symbol.owner as IrConstructor
val entryClass = entryConstructor.constructedClass
irCall(startOffset, endOffset,
genericCreateUninitializedInstanceSymbol.owner,
listOf(entryClass.defaultType)
)
}, startOffset, endOffset)
val irField = loweredEnum.valuesField.apply {
initializer = IrExpressionBodyImpl(startOffset, endOffset, irValuesInitializer)
@@ -349,8 +350,20 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val receiver = IrGetObjectValueImpl(startOffset, endOffset,
loweredEnum.implObject.defaultType, loweredEnum.implObject.symbol)
val value = IrGetFieldImpl(startOffset, endOffset, loweredEnum.valuesField.symbol, receiver)
val returnStatement = IrReturnImpl(startOffset, endOffset, loweredEnum.valuesGetter.symbol, value)
val value = IrGetFieldImpl(
startOffset,
endOffset,
loweredEnum.valuesField.symbol,
loweredEnum.valuesField.type,
receiver
)
val returnStatement = IrReturnImpl(
startOffset,
endOffset,
context.irBuiltIns.nothingType,
loweredEnum.valuesGetter.symbol,
value
)
getter.body = IrBlockBodyImpl(startOffset, endOffset, listOf(returnStatement))
return IrPropertyImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM,
@@ -363,7 +376,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
private val arrayGetSymbol = context.ir.symbols.array.functions.single { it.descriptor.name == Name.identifier("get") }
private val arrayType = context.builtIns.getArrayType(Variance.INVARIANT, irClass.defaultType)
private val arrayType = context.ir.symbols.array.typeWith(irClass.defaultType)
private fun createValuesPropertyInitializer(enumEntries: List<IrEnumEntry>): IrAnonymousInitializerImpl {
val startOffset = irClass.startOffset
@@ -371,13 +384,13 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
return IrAnonymousInitializerImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, loweredEnum.implObject.descriptor).apply {
body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody(irClass) {
val instances = irTemporary(irGetField(irGet(loweredEnum.implObject.thisReceiver!!.symbol), loweredEnum.valuesField.symbol))
val instances = irTemporary(irGetField(irGet(loweredEnum.implObject.thisReceiver!!), loweredEnum.valuesField))
enumEntries
.sortedBy { it.descriptor.name }
.withIndex()
.forEach {
val instance = irCall(arrayGetSymbol).apply {
dispatchReceiver = irGet(instances.symbol)
dispatchReceiver = irGet(instances)
putValueArgument(0, irInt(it.index))
}
val initializer = it.value.initializerExpression!! as IrCall
@@ -387,7 +400,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
}
+irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(arrayType)).apply {
extensionReceiver = irGet(loweredEnum.implObject.thisReceiver!!.symbol)
extensionReceiver = irGet(loweredEnum.implObject.thisReceiver!!)
}
}
}
@@ -396,23 +409,35 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
private fun createSyntheticValuesMethodBody(declaration: IrFunction): IrBody {
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
val valuesExpression = enumSyntheticFunctionsBuilder.buildValuesExpression(startOffset, endOffset, irClass.descriptor)
val valuesExpression = enumSyntheticFunctionsBuilder.buildValuesExpression(startOffset, endOffset, irClass)
return IrBlockBodyImpl(startOffset, endOffset,
listOf(IrReturnImpl(startOffset, endOffset, declaration.symbol, valuesExpression))
)
return IrBlockBodyImpl(startOffset, endOffset).apply {
statements += IrReturnImpl(
startOffset,
endOffset,
context.irBuiltIns.nothingType,
declaration.symbol,
valuesExpression
)
}
}
private fun createSyntheticValueOfMethodBody(declaration: IrFunction): IrBody {
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
val value = IrGetValueImpl(startOffset, endOffset, declaration.valueParameters[0].symbol)
val valueOfExpression = enumSyntheticFunctionsBuilder.buildValueOfExpression(startOffset, endOffset, irClass.descriptor, value)
val parameter = declaration.valueParameters[0]
val value = IrGetValueImpl(startOffset, endOffset, parameter.type, parameter.symbol)
val valueOfExpression = enumSyntheticFunctionsBuilder.buildValueOfExpression(startOffset, endOffset, irClass, value)
return IrBlockBodyImpl(
startOffset, endOffset,
listOf(IrReturnImpl(startOffset, endOffset, declaration.symbol, valueOfExpression))
)
return IrBlockBodyImpl(startOffset, endOffset).apply {
statements += IrReturnImpl(
startOffset,
endOffset,
context.irBuiltIns.nothingType,
declaration.symbol,
valueOfExpression
)
}
}
private fun lowerEnumConstructors(irClass: IrClass) {
@@ -423,18 +448,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
private fun transformEnumConstructor(enumConstructor: IrConstructor): IrConstructor {
val constructorDescriptor = enumConstructor.descriptor
val loweredConstructorDescriptor = lowerEnumConstructor(constructorDescriptor)
val loweredEnumConstructor = IrConstructorImpl(
enumConstructor.startOffset, enumConstructor.endOffset, enumConstructor.origin,
loweredConstructorDescriptor,
enumConstructor.body!! // will be transformed later
)
loweredEnumConstructor.parent = enumConstructor.parent
loweredEnumConstructors[constructorDescriptor] = loweredEnumConstructor
loweredEnumConstructor.createParameterDeclarations()
val loweredEnumConstructor = lowerEnumConstructor(enumConstructor)
enumConstructor.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach {
val body = enumConstructor.getDefault(it)!!
@@ -443,54 +457,75 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val descriptor = expression.descriptor
when (descriptor) {
is ValueParameterDescriptor -> {
val parameter = loweredEnumConstructor.valueParameters[descriptor.loweredIndex()]
return IrGetValueImpl(expression.startOffset,
expression.endOffset,
loweredEnumConstructor.valueParameters[descriptor.loweredIndex()].symbol)
parameter.type,
parameter.symbol)
}
}
return expression
}
})
loweredEnumConstructor.putDefault(loweredConstructorDescriptor.valueParameters[it.loweredIndex()], body)
descriptorToIrConstructorWithDefaultArguments[loweredConstructorDescriptor] = loweredEnumConstructor
loweredEnumConstructor.valueParameters[it.loweredIndex()].defaultValue = body
descriptorToIrConstructorWithDefaultArguments[loweredEnumConstructor.descriptor] = loweredEnumConstructor
}
return loweredEnumConstructor
}
private fun lowerEnumConstructor(constructorDescriptor: ClassConstructorDescriptor): ClassConstructorDescriptor {
private fun lowerEnumConstructor(enumConstructor: IrConstructor): IrConstructorImpl {
val loweredConstructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
constructorDescriptor.containingDeclaration,
constructorDescriptor.annotations,
constructorDescriptor.isPrimary,
constructorDescriptor.source
enumConstructor.descriptor.containingDeclaration,
enumConstructor.descriptor.annotations,
enumConstructor.descriptor.isPrimary,
enumConstructor.descriptor.source
)
val valueParameters =
listOf(
loweredConstructorDescriptor.createValueParameter(0, "name", context.builtIns.stringType),
loweredConstructorDescriptor.createValueParameter(1, "ordinal", context.builtIns.intType)
loweredConstructorDescriptor.createValueParameter(
0,
"name",
context.irBuiltIns.stringType,
enumConstructor.startOffset,
enumConstructor.endOffset
),
loweredConstructorDescriptor.createValueParameter(
1,
"ordinal",
context.irBuiltIns.intType,
enumConstructor.startOffset,
enumConstructor.endOffset
)
) +
constructorDescriptor.valueParameters.map {
lowerConstructorValueParameter(loweredConstructorDescriptor, it)
enumConstructor.valueParameters.map {
val descriptor = it.descriptor as ValueParameterDescriptor
val loweredValueParameterDescriptor = descriptor.copy(
loweredConstructorDescriptor,
it.name,
descriptor.loweredIndex()
)
loweredEnumConstructorParameters[descriptor] = loweredValueParameterDescriptor
it.copy(loweredValueParameterDescriptor)
}
loweredConstructorDescriptor.initialize(valueParameters, Visibilities.PROTECTED)
loweredConstructorDescriptor.returnType = constructorDescriptor.returnType
return loweredConstructorDescriptor
}
private fun lowerConstructorValueParameter(
loweredConstructorDescriptor: ClassConstructorDescriptor,
valueParameterDescriptor: ValueParameterDescriptor
): ValueParameterDescriptor {
val loweredValueParameterDescriptor = valueParameterDescriptor.copy(
loweredConstructorDescriptor,
valueParameterDescriptor.name,
valueParameterDescriptor.loweredIndex()
loweredConstructorDescriptor.initialize(
valueParameters.map { it.descriptor as ValueParameterDescriptor },
Visibilities.PROTECTED
)
loweredEnumConstructorParameters[valueParameterDescriptor] = loweredValueParameterDescriptor
return loweredValueParameterDescriptor
loweredConstructorDescriptor.returnType = enumConstructor.descriptor.returnType
val loweredEnumConstructor = IrConstructorImpl(
enumConstructor.startOffset, enumConstructor.endOffset, enumConstructor.origin,
loweredConstructorDescriptor
).apply {
returnType = enumConstructor.returnType
body = enumConstructor.body!! // will be transformed later
}
loweredEnumConstructor.valueParameters += valueParameters
loweredEnumConstructor.parent = enumConstructor.parent
loweredEnumConstructors[enumConstructor.descriptor] = loweredEnumConstructor
return loweredEnumConstructor
}
private fun lowerEnumClassBody() {
@@ -505,7 +540,8 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val origin = enumConstructorCall.origin
val result = IrDelegatingConstructorCallImpl(startOffset, endOffset,
enumConstructorCall.symbol, enumConstructorCall.descriptor)
context.irBuiltIns.unitType,
enumConstructorCall.symbol, enumConstructorCall.descriptor, enumConstructorCall.typeArgumentsCount)
assert(result.descriptor.valueParameters.size == 2) {
"Enum(String, Int) constructor call expected:\n${result.dump()}"
@@ -519,8 +555,12 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
throw AssertionError("No 'ordinal' parameter in enum constructor: $enumClassConstructor")
}
result.putValueArgument(0, IrGetValueImpl(startOffset, endOffset, nameParameter.symbol, origin))
result.putValueArgument(1, IrGetValueImpl(startOffset, endOffset, ordinalParameter.symbol, origin))
result.putValueArgument(0,
IrGetValueImpl(startOffset, endOffset, nameParameter.type, nameParameter.symbol, origin)
)
result.putValueArgument(1,
IrGetValueImpl(startOffset, endOffset, ordinalParameter.type, ordinalParameter.symbol, origin)
)
return result
}
@@ -534,13 +574,15 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $descriptor")
}
val result = IrDelegatingConstructorCallImpl(startOffset, endOffset,
loweredDelegatedConstructor.symbol, loweredDelegatedConstructor.descriptor)
val result = IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.unitType,
loweredDelegatedConstructor.symbol, loweredDelegatedConstructor.descriptor, 0)
val firstParameter = enumClassConstructor.valueParameters[0]
result.putValueArgument(0,
IrGetValueImpl(startOffset, endOffset, enumClassConstructor.valueParameters[0].symbol))
IrGetValueImpl(startOffset, endOffset, firstParameter.type, firstParameter.symbol))
val secondParameter = enumClassConstructor.valueParameters[1]
result.putValueArgument(1,
IrGetValueImpl(startOffset, endOffset, enumClassConstructor.valueParameters[1].symbol))
IrGetValueImpl(startOffset, endOffset, secondParameter.type, secondParameter.symbol))
descriptor.valueParameters.forEach { valueParameter ->
result.putValueArgument(valueParameter.loweredIndex(), delegatingConstructorCall.getValueArgument(valueParameter))
@@ -565,8 +607,10 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val result = createConstructorCall(startOffset, endOffset, loweredConstructor.symbol)
result.putValueArgument(0, IrConstImpl.string(startOffset, endOffset, context.builtIns.stringType, name))
result.putValueArgument(1, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, ordinal))
result.putValueArgument(0,
IrConstImpl.string(startOffset, endOffset, context.irBuiltIns.stringType, name))
result.putValueArgument(1,
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, ordinal))
descriptor.valueParameters.forEach { valueParameter ->
val i = valueParameter.index
@@ -584,14 +628,25 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
private inner class InEnumEntryClassConstructor(enumEntry: ClassDescriptor) : InEnumEntry(enumEntry) {
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol)
= IrDelegatingConstructorCallImpl(startOffset, endOffset, loweredConstructor, loweredConstructor.descriptor)
override fun createConstructorCall(
startOffset: Int,
endOffset: Int,
loweredConstructor: IrConstructorSymbol
) = IrDelegatingConstructorCallImpl(
startOffset,
endOffset,
context.irBuiltIns.unitType,
loweredConstructor,
loweredConstructor.descriptor,
0
)
}
private inner class InEnumEntryInitializer(enumEntry: ClassDescriptor) : InEnumEntry(enumEntry) {
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrCall {
return IrCallImpl(startOffset, endOffset,
defaultEnumEntryConstructors[loweredConstructor.descriptor]?.symbol ?: loweredConstructor)
val irConstructorSymbol = defaultEnumEntryConstructors[loweredConstructor.descriptor]?.symbol
?: loweredConstructor
return IrCallImpl(startOffset, endOffset, irConstructorSymbol.owner.returnType, irConstructorSymbol)
}
}
@@ -668,7 +723,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val loweredEnumConstructor = loweredEnumConstructors[expression.descriptor.containingDeclaration]!!
val loweredIrParameter = loweredEnumConstructor.valueParameters[loweredParameter.index]
assert(loweredIrParameter.descriptor == loweredParameter)
return IrGetValueImpl(expression.startOffset, expression.endOffset,
return IrGetValueImpl(expression.startOffset, expression.endOffset, loweredIrParameter.type,
loweredIrParameter.symbol, expression.origin)
} else {
return expression
@@ -685,9 +740,11 @@ private class ParameterMapper(val originalConstructor: IrConstructor) : IrElemen
val descriptor = expression.descriptor
when (descriptor) {
is ValueParameterDescriptor -> {
val parameter = originalConstructor.valueParameters[descriptor.index]
return IrGetValueImpl(expression.startOffset,
expression.endOffset,
originalConstructor.valueParameters[descriptor.index].symbol)
parameter.type,
parameter.symbol)
}
}
return expression
@@ -5,6 +5,8 @@ import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.irasdescriptors.containsNull
import org.jetbrains.kotlin.backend.konan.irasdescriptors.getClass
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
@@ -16,6 +18,7 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.getPropertyGetter
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -50,11 +53,11 @@ internal class EnumWhenLowering(private val context: Context) : IrElementTransfo
}
val subject = irBlock.statements[0] as IrVariable
// Subject should not be nullable because we will access the `ordinal` property.
if (subject.type.isNullable()) {
if (subject.type.containsNull()) {
return false
}
// Check that subject is enum entry.
val enumClass = subject.type.constructor.declarationDescriptor as? ClassDescriptor
val enumClass = subject.type.getClass()
?: return false
return enumClass.kind == ClassKind.ENUM_CLASS
}
@@ -83,14 +86,22 @@ internal class EnumWhenLowering(private val context: Context) : IrElementTransfo
private fun createEnumOrdinalVariable(enumVariable: IrVariable): IrVariable {
val ordinalPropertyGetter = context.ir.symbols.enum.getPropertyGetter("ordinal")!!
val getOrdinal = IrCallImpl(enumVariable.startOffset, enumVariable.endOffset, ordinalPropertyGetter).apply {
dispatchReceiver = IrGetValueImpl(enumVariable.startOffset, enumVariable.endOffset, enumVariable.symbol)
val getOrdinal = IrCallImpl(
enumVariable.startOffset, enumVariable.endOffset,
ordinalPropertyGetter.owner.returnType,
ordinalPropertyGetter
).apply {
dispatchReceiver = IrGetValueImpl(
enumVariable.startOffset, enumVariable.endOffset,
enumVariable.type, enumVariable.symbol
)
}
// Create temporary variable for subject's ordinal.
val ordinalDescriptor = IrTemporaryVariableDescriptorImpl(enumVariable.descriptor.containingDeclaration,
Name.identifier(enumVariable.name.asString() + "_ordinal"), context.builtIns.intType)
return IrVariableImpl(enumVariable.startOffset, enumVariable.endOffset,
IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, ordinalDescriptor, getOrdinal)
IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, ordinalDescriptor,
context.irBuiltIns.intType, getOrdinal)
}
override fun visitCall(expression: IrCall): IrExpression {
@@ -100,7 +111,7 @@ internal class EnumWhenLowering(private val context: Context) : IrElementTransfo
}
private val areEqualByValue = context.ir.symbols.areEqualByValue.first {
it.owner.valueParameters[0].type == context.builtIns.intType
it.owner.valueParameters[0].type.classifierOrNull == context.ir.symbols.int
}
// We are looking for branch that is a comparison of the subject and another enum entry.
@@ -114,19 +125,20 @@ internal class EnumWhenLowering(private val context: Context) : IrElementTransfo
}
val lhs = callArgs[0].second
val rhs = callArgs[1].second
// Both entries should belong to the same class.
if (lhs.type != rhs.type) {
return call
}
// If there is nothing on stack then nothing we can do.
val (topmostSubject, topmostOrdinalProvider) = subjectWithOrdinalStack.peek()
?: return call
if (lhs is IrValueAccessExpression && lhs.symbol.owner == topmostSubject && rhs is IrGetEnumValue) {
if (lhs is IrValueAccessExpression && lhs.symbol.owner == topmostSubject && rhs is IrGetEnumValue &&
// Both entries should belong to the same class:
topmostSubject.type.classifierOrNull?.owner == rhs.symbol.owner.parent) {
val entryOrdinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(rhs.descriptor)
val subjectOrdinal = topmostOrdinalProvider.value
return IrCallImpl(call.startOffset, call.endOffset, areEqualByValue).apply {
putValueArgument(0, IrGetValueImpl(lhs.startOffset, lhs.endOffset, subjectOrdinal.symbol))
putValueArgument(1, IrConstImpl.int(rhs.startOffset, rhs.endOffset, context.builtIns.intType, entryOrdinal))
return IrCallImpl(call.startOffset, call.endOffset, areEqualByValue.owner.returnType, areEqualByValue).apply {
putValueArgument(0,
IrGetValueImpl(lhs.startOffset, lhs.endOffset, subjectOrdinal.type, subjectOrdinal.symbol))
putValueArgument(1,
IrConstImpl.int(rhs.startOffset, rhs.endOffset, context.irBuiltIns.intType, entryOrdinal))
}
}
return call
@@ -3,10 +3,7 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.MemberDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
@@ -79,20 +76,21 @@ internal class ExpectDeclarationsRemoving(val context: Context) : FileLoweringPa
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid()
val newSymbol = remapExpectValueSymbol(expression.symbol)
val newValue = remapExpectValue(expression.symbol)
?: return expression
return IrGetValueImpl(
expression.startOffset,
expression.endOffset,
newSymbol,
newValue.type,
newValue.symbol,
expression.origin
)
}
}, data = null)
}
private fun remapExpectValueSymbol(symbol: IrValueSymbol): IrValueParameterSymbol? {
private fun remapExpectValue(symbol: IrValueSymbol): IrValueParameter? {
if (symbol !is IrValueParameterSymbol) {
return null
}
@@ -120,6 +118,6 @@ internal class ExpectDeclarationsRemoving(val context: Context) : FileLoweringPa
}
else -> error(parent)
}.symbol
}
}
}
@@ -36,39 +36,44 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrReturnTargetSymbol
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit
internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, IrElementTransformerVoidWithContext() {
private val symbols get() = context.ir.symbols
private interface HighLevelJump {
fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression): IrExpression
}
private data class Return(val target: IrReturnTargetSymbol): HighLevelJump {
override fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression)
= IrReturnImpl(startOffset, endOffset, context.builtIns.nothingType, target, value)
= IrReturnImpl(startOffset, endOffset, context.irBuiltIns.nothingType, target, value)
}
private data class Break(val loop: IrLoop): HighLevelJump {
override fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression)
= IrBlockImpl(startOffset, endOffset, context.builtIns.nothingType, null,
= IrBlockImpl(startOffset, endOffset, context.irBuiltIns.nothingType, null,
statements = listOf(
value,
IrBreakImpl(startOffset, endOffset, context.builtIns.nothingType, loop)
IrBreakImpl(startOffset, endOffset, context.irBuiltIns.nothingType, loop)
))
}
private data class Continue(val loop: IrLoop): HighLevelJump {
override fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression)
= IrBlockImpl(startOffset, endOffset, context.builtIns.nothingType, null,
= IrBlockImpl(startOffset, endOffset, context.irBuiltIns.nothingType, null,
statements = listOf(
value,
IrContinueImpl(startOffset, endOffset, context.builtIns.nothingType, loop)
IrContinueImpl(startOffset, endOffset, context.irBuiltIns.nothingType, loop)
))
}
@@ -183,10 +188,11 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
val currentTryScope = tryScopes[index]
currentTryScope.jumps.getOrPut(jump) {
val symbol = getIrReturnableBlockSymbol(jump.toString(), value.type)
val type = value.type
val symbol = getIrReturnableBlockSymbol(jump.toString(), type)
with(currentTryScope) {
irBuilder.run {
val inlinedFinally = irInlineFinally(symbol, expression, finallyExpression)
val inlinedFinally = irInlineFinally(symbol, type, expression, finallyExpression)
expression = performHighLevelJump(
tryScopes = tryScopes,
index = index + 1,
@@ -201,7 +207,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
return IrReturnImpl(
startOffset = startOffset,
endOffset = endOffset,
type = context.builtIns.nothingType,
type = context.irBuiltIns.nothingType,
returnTargetSymbol = it,
value = value)
}
@@ -219,7 +225,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
val transformedTry = IrTryImpl(
startOffset = startOffset,
endOffset = endOffset,
type = context.builtIns.nothingType
type = context.irBuiltIns.nothingType
)
val transformedFinallyExpression = finallyExpression.transform(transformer, null)
val parameter = IrTemporaryVariableDescriptorImpl(
@@ -228,24 +234,26 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
outType = context.builtIns.throwable.defaultType
)
val catchParameter = IrVariableImpl(
startOffset, endOffset, IrDeclarationOrigin.CATCH_PARAMETER, parameter)
startOffset, endOffset, IrDeclarationOrigin.CATCH_PARAMETER, parameter,
symbols.throwable.owner.defaultType)
val syntheticTry = IrTryImpl(
startOffset = startOffset,
endOffset = endOffset,
type = context.builtIns.nothingType,
type = context.irBuiltIns.nothingType,
tryResult = transformedTry,
catches = listOf(
irCatch(catchParameter).apply {
result = irBlock {
+finallyExpression.copy()
+irThrow(irGet(catchParameter.symbol))
+irThrow(irGet(catchParameter))
}
}),
finallyExpression = null
)
using(TryScope(syntheticTry, transformedFinallyExpression, this)) {
val fallThroughSymbol = getIrReturnableBlockSymbol("fallThrough", aTry.type)
val fallThroughType = aTry.type
val fallThroughSymbol = getIrReturnableBlockSymbol("fallThrough", fallThroughType)
val transformedResult = aTry.tryResult.transform(transformer, null)
transformedTry.tryResult = irReturn(fallThroughSymbol, transformedResult)
for (aCatch in aTry.catches) {
@@ -253,28 +261,28 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
transformedCatch.result = irReturn(fallThroughSymbol, transformedCatch.result)
transformedTry.catches.add(transformedCatch)
}
return irInlineFinally(fallThroughSymbol, it.expression, it.finallyExpression)
return irInlineFinally(fallThroughSymbol, fallThroughType, it.expression, it.finallyExpression)
}
}
}
private fun IrBuilderWithScope.irInlineFinally(symbol: IrReturnableBlockSymbol,
private fun IrBuilderWithScope.irInlineFinally(symbol: IrReturnableBlockSymbol, type: IrType,
value: IrExpression,
finallyExpression: IrExpression): IrExpression {
val returnType = symbol.descriptor.returnType!!
return when {
returnType.isUnit() || returnType.isNothing() -> irBlock(value, null, returnType) {
+irReturnableBlock(symbol) {
returnType.isUnit() || returnType.isNothing() -> irBlock(value, null, type) {
+irReturnableBlock(symbol, type) {
+value
}
+finallyExpression.copy()
}
else -> irBlock(value, null, returnType) {
val tmp = irTemporary(irReturnableBlock(symbol) {
else -> irBlock(value, null, type) {
val tmp = irTemporary(irReturnableBlock(symbol, type) {
+irReturn(symbol, value)
})
+finallyExpression.copy()
+irGet(tmp.symbol)
+irGet(tmp)
}
}
}
@@ -285,16 +293,16 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
initialize(null, null, emptyList(), emptyList(), returnType, Modality.ABSTRACT, Visibilities.PRIVATE)
}
private fun getIrReturnableBlockSymbol(name: String, returnType: KotlinType): IrReturnableBlockSymbol =
IrReturnableBlockSymbolImpl(getFakeFunctionDescriptor(name, returnType))
private fun getIrReturnableBlockSymbol(name: String, returnType: IrType): IrReturnableBlockSymbol =
IrReturnableBlockSymbolImpl(getFakeFunctionDescriptor(name, returnType.toKotlinType()))
private inline fun <reified T : IrElement> T.copy() = this.deepCopyWithVariables()
fun IrBuilderWithScope.irReturn(target: IrReturnTargetSymbol, value: IrExpression) =
IrReturnImpl(startOffset, endOffset, context.builtIns.nothingType, target, value)
IrReturnImpl(startOffset, endOffset, context.irBuiltIns.nothingType, target, value)
inline fun IrBuilderWithScope.irReturnableBlock(symbol: IrReturnableBlockSymbol, body: IrBlockBuilder.() -> Unit) =
IrReturnableBlockImpl(startOffset, endOffset, symbol.descriptor.returnType!!, symbol, null,
IrBlockBuilder(context, scope, startOffset, endOffset, null, symbol.descriptor.returnType!!)
inline fun IrBuilderWithScope.irReturnableBlock(symbol: IrReturnableBlockSymbol, type: IrType, body: IrBlockBuilder.() -> Unit) =
IrReturnableBlockImpl(startOffset, endOffset, type, symbol, null,
IrBlockBuilder(context, scope, startOffset, endOffset, null, type)
.block(body).statements)
}
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
@@ -36,6 +37,9 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
@@ -134,36 +138,40 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
//region Util methods ==============================================================================================
private fun IrExpression.castIfNecessary(progressionType: ProgressionType): IrExpression {
val type = this.type.toKotlinType()
assert(type in progressionElementClassesTypes || type in progressionElementClassesNullableTypes)
return if (type == progressionType.elementType) {
this
} else {
IrCallImpl(startOffset, endOffset, symbols.getFunction(progressionType.numberCastFunctionName, type))
val function = symbols.getFunction(progressionType.numberCastFunctionName, type)
IrCallImpl(startOffset, endOffset, function.owner.returnType, function)
.apply { dispatchReceiver = this@castIfNecessary }
}
}
private fun DeclarationIrBuilder.ensureNotNullable(expression: IrExpression): IrExpression {
return if (expression.type.isMarkedNullable) {
irImplicitCast(expression, expression.type.makeNotNullable())
return if (expression.type.isSimpleTypeWithQuestionMark) {
irImplicitCast(expression, expression.type.makeNotNull())
} else {
expression
}
}
private fun IrExpression.unaryMinus(): IrExpression =
IrCallImpl(startOffset, endOffset, symbols.getUnaryOperator(OperatorNameConventions.UNARY_MINUS, type)).apply {
dispatchReceiver = this@unaryMinus
}
private fun IrExpression.unaryMinus(): IrExpression {
val unaryOperator = symbols.getUnaryOperator(OperatorNameConventions.UNARY_MINUS, type.toKotlinType())
return IrCallImpl(startOffset, endOffset, unaryOperator.owner.returnType, unaryOperator).apply {
dispatchReceiver = this@unaryMinus
}
}
private fun ProgressionInfo.defaultStep(startOffset: Int, endOffset: Int): IrExpression =
progressionType.elementType.let { type ->
val step = if (increasing) 1 else -1
when {
KotlinBuiltIns.isInt(type) || KotlinBuiltIns.isChar(type) ->
IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, step)
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, step)
KotlinBuiltIns.isLong(type) ->
IrConstImpl.long(startOffset, endOffset, context.builtIns.longType, step.toLong())
IrConstImpl.long(startOffset, endOffset, context.irBuiltIns.longType, step.toLong())
else -> throw IllegalArgumentException()
}
}
@@ -178,9 +186,9 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
// Used only by the assert.
private fun stepHasRightType(step: IrExpression, progressionType: ProgressionType) =
((progressionType.isCharProgression() || progressionType.isIntProgression()) &&
KotlinBuiltIns.isInt(step.type.makeNotNullable())) ||
KotlinBuiltIns.isInt(step.type.toKotlinType().makeNotNullable())) ||
(progressionType.isLongProgression() &&
KotlinBuiltIns.isLong(step.type.makeNotNullable()))
KotlinBuiltIns.isLong(step.type.toKotlinType().makeNotNullable()))
private fun irCheckProgressionStep(progressionType: ProgressionType,
step: IrExpression): Pair<IrExpression, Boolean> {
@@ -193,25 +201,25 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
// so there is no need to cast it.
assert(stepHasRightType(step, progressionType))
val symbol = symbols.checkProgressionStep[step.type.makeNotNullable()]
val symbol = symbols.checkProgressionStep[step.type.toKotlinType().makeNotNullable()]
?: throw IllegalArgumentException("Unknown progression element type: ${step.type}")
return IrCallImpl(step.startOffset, step.endOffset, symbol).apply {
return IrCallImpl(step.startOffset, step.endOffset, symbol.owner.returnType, symbol).apply {
putValueArgument(0, step)
} to true
}
private fun irGetProgressionLast(progressionType: ProgressionType,
first: IrVariableSymbol,
first: IrVariable,
lastExpression: IrExpression,
step: IrVariableSymbol): IrExpression {
step: IrVariable): IrExpression {
val symbol = symbols.getProgressionLast[progressionType.elementType]
?: throw IllegalArgumentException("Unknown progression element type: ${lastExpression.type}")
val startOffset = lastExpression.startOffset
val endOffset = lastExpression.endOffset
return IrCallImpl(startOffset, lastExpression.endOffset, symbol).apply {
putValueArgument(0, IrGetValueImpl(startOffset, endOffset, first))
return IrCallImpl(startOffset, lastExpression.endOffset, symbol.owner.returnType, symbol).apply {
putValueArgument(0, IrGetValueImpl(startOffset, endOffset, first.type, first.symbol))
putValueArgument(1, lastExpression.castIfNecessary(progressionType))
putValueArgument(2, IrGetValueImpl(startOffset, endOffset, step))
putValueArgument(2, IrGetValueImpl(startOffset, endOffset, step.type, step.symbol))
}
}
//endregion
@@ -236,11 +244,11 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
/** Contains information about variables used in the loop. */
private data class ForLoopInfo(
val progressionInfo: ProgressionInfo,
val inductionVariable: IrVariableSymbol,
val bound: IrVariableSymbol,
val last: IrVariableSymbol,
val step: IrVariableSymbol,
var loopVariable: IrVariableSymbol? = null)
val inductionVariable: IrVariable,
val bound: IrVariable,
val last: IrVariable,
val step: IrVariable,
var loopVariable: IrVariable? = null)
private inner class ProgressionInfoBuilder : IrElementVisitor<ProgressionInfo?, Nothing?> {
@@ -287,7 +295,7 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
override fun visitElement(element: IrElement, data: Nothing?): ProgressionInfo? = null
override fun visitCall(expression: IrCall, data: Nothing?): ProgressionInfo? {
val type = expression.type
val type = expression.type.toKotlinType()
val progressionType = when {
type.isSubtypeOf(symbols.charProgression.descriptor.defaultType) -> CHAR_PROGRESSION
type.isSubtypeOf(symbols.intProgression.descriptor.defaultType) -> INT_PROGRESSION
@@ -362,15 +370,15 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
var lastExpression: IrExpression? = null
if (!closed) {
val decrementSymbol = symbols.getUnaryOperator(OperatorNameConventions.DEC, boundValue.descriptor.type)
lastExpression = irCall(decrementSymbol).apply {
dispatchReceiver = irGet(boundValue.symbol)
lastExpression = irCall(decrementSymbol.owner).apply {
dispatchReceiver = irGet(boundValue)
}
}
if (needLastCalculation) {
lastExpression = irGetProgressionLast(progressionType,
inductionVariable.symbol,
lastExpression ?: irGet(boundValue.symbol),
stepValue.symbol)
inductionVariable,
lastExpression ?: irGet(boundValue),
stepValue)
}
val lastValue = if (lastExpression != null) {
scope.createTemporaryVariable(lastExpression,
@@ -383,12 +391,12 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
}
iteratorToLoopInfo[symbol] = ForLoopInfo(progressionInfo,
inductionVariable.symbol,
boundValue.symbol,
lastValue.symbol,
stepValue.symbol)
inductionVariable,
boundValue,
lastValue,
stepValue)
return IrCompositeImpl(startOffset, endOffset, context.builtIns.unitType, null, statements)
return IrCompositeImpl(startOffset, endOffset, context.irBuiltIns.unitType, null, statements)
}
}
}
@@ -406,15 +414,15 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
forLoopInfo.inductionVariable.descriptor.type,
forLoopInfo.step.descriptor.type
)
forLoopInfo.loopVariable = variable.symbol
forLoopInfo.loopVariable = variable
with(builder) {
variable.initializer = irGet(forLoopInfo.inductionVariable)
val increment = irSetVar(forLoopInfo.inductionVariable,
irCallOp(plusOperator, irGet(forLoopInfo.inductionVariable), irGet(forLoopInfo.step)))
irCallOp(plusOperator.owner, irGet(forLoopInfo.inductionVariable), irGet(forLoopInfo.step)))
return IrCompositeImpl(variable.startOffset,
variable.endOffset,
context.irBuiltIns.unit,
context.irBuiltIns.unitType,
IrStatementOrigin.FOR_LOOP_NEXT,
listOf(variable, increment))
}
@@ -427,16 +435,16 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
return irCall(context.irBuiltIns.greaterFunByOperandType[context.irBuiltIns.int]?.symbol!!).apply {
val minConst = when {
progressionType.isIntProgression() -> IrConstImpl
.int(startOffset, endOffset, context.builtIns.intType, Int.MIN_VALUE)
.int(startOffset, endOffset, context.irBuiltIns.intType, Int.MIN_VALUE)
progressionType.isCharProgression() -> IrConstImpl
.char(startOffset, endOffset, context.builtIns.charType, 0.toChar())
.char(startOffset, endOffset, context.irBuiltIns.charType, 0.toChar())
progressionType.isLongProgression() -> IrConstImpl
.long(startOffset, endOffset, context.builtIns.longType, Long.MIN_VALUE)
.long(startOffset, endOffset, context.irBuiltIns.longType, Long.MIN_VALUE)
else -> throw IllegalArgumentException("Unknown progression type")
}
val compareToCall = irCall(symbols.getBinaryOperator(OperatorNameConventions.COMPARE_TO,
forLoopInfo.bound.descriptor.type,
minConst.type)).apply {
minConst.type.toKotlinType())).apply {
dispatchReceiver = irGet(forLoopInfo.bound)
putValueArgument(0, minConst)
}
@@ -458,7 +466,7 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
forLoopInfo.last.descriptor.type)
val check: IrExpression = irCall(comparingBuiltIn!!).apply {
putValueArgument(0, irCallOp(compareTo, irGet(forLoopInfo.inductionVariable), irGet(forLoopInfo.last)))
putValueArgument(0, irCallOp(compareTo.owner, irGet(forLoopInfo.inductionVariable), irGet(forLoopInfo.last)))
putValueArgument(1, irInt(0))
}
@@ -41,8 +41,9 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.createValueSymbol
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
@@ -66,7 +67,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
fun inline(irModule: IrModuleFragment): IrElement {
val transformedModule = irModule.accept(this, null)
DescriptorSubstitutorForExternalScope(globalSubstituteMap).run(transformedModule) // Transform calls to object that might be returned from inline function call.
DescriptorSubstitutorForExternalScope(globalSubstituteMap, context).run(transformedModule) // Transform calls to object that might be returned from inline function call.
return transformedModule
}
@@ -157,8 +158,8 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
irBuilder.run {
val constructorDescriptor = delegatingConstructorCall.descriptor.original
val constructorCall = irCall(delegatingConstructorCall.symbol,
constructorDescriptor.typeParameters.associate { it to delegatingConstructorCall.getTypeArgument(it)!! }).apply {
val constructorCall = irCall(delegatingConstructorCall.symbol, callee.type,
constructorDescriptor.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply {
constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) }
}
val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter
@@ -167,12 +168,12 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this"
)
statements[0] = newThis
substituteMap[oldThis] = irGet(newThis.symbol)
statements.add(irReturn(irGet(newThis.symbol)))
substituteMap[oldThis] = irGet(newThis)
statements.add(irReturn(irGet(newThis)))
}
}
val returnType = copyFunctionDeclaration.descriptor.returnType!! // Substituted return type.
val returnType = copyFunctionDeclaration.returnType // Substituted return type.
val sourceFileName = context.ir.originalModuleIndex.declarationToFile[caller.descriptor.original]?:""
val inlineFunctionBody = IrReturnableBlockImpl( // Create new IR element to replace "call".
startOffset = startOffset,
@@ -235,6 +236,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val immediateCall = IrCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = expression.type,
symbol = functionArgument.symbol,
descriptor = functionArgument.descriptor).apply {
functionParameters.forEach {
@@ -290,7 +292,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val substitutionContext = mutableMapOf<TypeConstructor, TypeProjection>()
for (index in 0 until irCall.typeArgumentsCount) {
val typeArgument = irCall.getTypeArgument(index) ?: continue
substitutionContext[typeParameters[index].typeConstructor] = TypeProjectionImpl(typeArgument)
substitutionContext[typeParameters[index].typeConstructor] = TypeProjectionImpl(typeArgument.toKotlinType())
}
return TypeSubstitutor.create(substitutionContext)
}
@@ -359,8 +361,9 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
}
val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>()
functionDescriptor.valueParameters.forEach { parameterDescriptor -> // Iterate value parameter descriptors.
val argument = valueArguments[parameterDescriptor.index] // Get appropriate argument from call site.
irFunction.valueParameters.forEach { parameter -> // Iterate value parameters.
val parameterDescriptor = parameter.descriptor as ValueParameterDescriptor
val argument = valueArguments[parameterDescriptor.index] // Get appropriate argument from call site.
when {
argument != null -> { // Argument is good enough.
parameterToArgument += ParameterToArgument( // Associate current parameter with the argument.
@@ -381,8 +384,8 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val emptyArray = IrVarargImpl(
startOffset = irCall.startOffset,
endOffset = irCall.endOffset,
type = parameterDescriptor.type,
varargElementType = parameterDescriptor.varargElementType!!
type = parameter.type,
varargElementType = parameter.varargElementType!!
)
parameterToArgument += ParameterToArgument(
parameterDescriptor = parameterDescriptor,
@@ -432,7 +435,8 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val getVal = IrGetValueImpl( // Create new expression, representing access the new variable.
startOffset = currentScope.irElement.startOffset,
endOffset = currentScope.irElement.endOffset,
symbol = createValueSymbol(newVariable.descriptor)
type = newVariable.type,
symbol = newVariable.symbol
)
substituteMap[parameterDescriptor] = getVal // Parameter will be replaced with the new variable.
}
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.util.addChild
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.createDispatchReceiverParameter
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -64,7 +64,7 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement {
initializers.add(IrBlockImpl(declaration.startOffset, declaration.endOffset,
context.builtIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER, declaration.body.statements))
context.irBuiltIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER, declaration.body.statements))
return declaration
}
@@ -72,11 +72,16 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
val initializer = declaration.initializer ?: return declaration
val startOffset = initializer.startOffset
val endOffset = initializer.endOffset
initializers.add(IrBlockImpl(startOffset, endOffset, context.builtIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER,
initializers.add(IrBlockImpl(startOffset, endOffset, context.irBuiltIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER,
listOf(
IrSetFieldImpl(startOffset, endOffset, declaration.symbol,
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol),
initializer.expression, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER))))
IrGetValueImpl(
startOffset, endOffset,
irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol
),
initializer.expression,
context.irBuiltIns.unitType,
STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER))))
declaration.initializer = null
return declaration
}
@@ -109,9 +114,13 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
val initializer = IrFunctionImpl(startOffset, endOffset, DECLARATION_ORIGIN_ANONYMOUS_INITIALIZER,
initializerMethodDescriptor, IrBlockBodyImpl(startOffset, endOffset, initializers))
initializerMethodDescriptor)
initializer.createParameterDeclarations()
initializer.returnType = context.irBuiltIns.unitType
initializer.body = IrBlockBodyImpl(startOffset, endOffset, initializers)
initializer.parent = irClass
initializer.createDispatchReceiverParameter()
initializers.forEach {
it.transformChildrenVoid(object : IrElementTransformerVoid() {
@@ -120,6 +129,7 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
return IrGetValueImpl(
expression.startOffset,
expression.endOffset,
initializer.dispatchReceiverParameter!!.type,
initializer.dispatchReceiverParameter!!.symbol
)
} else {
@@ -129,7 +139,7 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
})
}
irClass.addChild(initializer)
irClass.declarations.add(initializer)
return initializer.symbol
}
@@ -156,8 +166,13 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
} else {
val startOffset = it.startOffset
val endOffset = it.endOffset
listOf(IrCallImpl(startOffset, endOffset, initializerMethodSymbol).apply {
dispatchReceiver = IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol)
listOf(IrCallImpl(startOffset, endOffset,
context.irBuiltIns.unitType, initializerMethodSymbol
).apply {
dispatchReceiver = IrGetValueImpl(
startOffset, endOffset,
irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol
)
})
}
}
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.util.addChild
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
@@ -57,7 +56,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
}
private fun createOuterThisField() {
val field = context.specialDeclarationsFactory.getOuterThisField(classDescriptor)
val field = context.specialDeclarationsFactory.getOuterThisField(irClass)
outerThisFieldSymbol = field.symbol
irClass.addChild(field)
}
@@ -78,12 +77,15 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
?: throw AssertionError("Unexpected constructor body: ${irConstructor.body}")
val startOffset = irConstructor.startOffset
val endOffset = irConstructor.endOffset
val thisReceiver = irClass.thisReceiver!!
val outerReceiver = irConstructor.dispatchReceiverParameter!!
blockBody.statements.add(
0,
IrSetFieldImpl(
startOffset, endOffset, outerThisFieldSymbol,
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol),
IrGetValueImpl(startOffset, endOffset, irConstructor.dispatchReceiverParameter!!.symbol)
IrGetValueImpl(startOffset, endOffset, thisReceiver.type, thisReceiver.symbol),
IrGetValueImpl(startOffset, endOffset, outerReceiver.type, outerReceiver.symbol),
context.irBuiltIns.unitType
)
)
}
@@ -108,28 +110,28 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
val origin = expression.origin
var irThis: IrExpression
var innerClass: ClassDescriptor
var innerClass: IrClass
if (constructorSymbol == null || constructorSymbol.descriptor.constructedClass != classDescriptor) {
innerClass = classDescriptor
innerClass = irClass
val currentIrFunction = currentFunction!!.scope.scopeOwnerSymbol.owner as IrFunction
val currentFunctionReceiver = currentIrFunction.dispatchReceiverParameter
val thisSymbol = if (currentFunctionReceiver?.descriptor == irClass.thisReceiver!!.descriptor) {
val thisParameter = if (currentFunctionReceiver?.descriptor == irClass.thisReceiver!!.descriptor) {
currentFunctionReceiver
} else {
irClass.thisReceiver!!
}.symbol
}
irThis = IrGetValueImpl(startOffset, endOffset, thisSymbol, origin)
irThis = IrGetValueImpl(startOffset, endOffset, thisParameter.type, thisParameter.symbol, origin)
} else {
// For constructor we have outer class as dispatchReceiverParameter.
innerClass = DescriptorUtils.getContainingClass(classDescriptor) ?:
innerClass = irClass.parent as? IrClass ?:
throw AssertionError("No containing class for inner class $classDescriptor")
irThis = IrGetValueImpl(startOffset, endOffset,
constructorSymbol.owner.dispatchReceiverParameter!!.symbol, origin)
val thisParameter = constructorSymbol.owner.dispatchReceiverParameter!!
irThis = IrGetValueImpl(startOffset, endOffset, thisParameter.type, thisParameter.symbol, origin)
}
while (innerClass != implicitThisClass) {
while (innerClass.descriptor != implicitThisClass) {
if (!innerClass.isInner) {
// Captured 'this' unrelated to inner classes nesting hierarchy, leave it as is -
// should be transformed by closures conversion.
@@ -137,11 +139,16 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
}
val outerThisField = context.specialDeclarationsFactory.getOuterThisField(innerClass)
irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField.symbol, irThis, origin)
irThis = IrGetFieldImpl(
startOffset, endOffset,
outerThisField.symbol, outerThisField.type,
irThis,
origin
)
val outer = innerClass.containingDeclaration
innerClass = outer as? ClassDescriptor ?:
throw AssertionError("Unexpected containing declaration for inner class $innerClass: $outer")
val outer = innerClass.parent
innerClass = outer as? IrClass ?:
throw AssertionError("Unexpected containing declaration for inner class ${innerClass.descriptor}: $outer")
}
return irThis
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.allParameters
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.backend.common.pop
@@ -26,12 +25,13 @@ import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.allOverriddenDescriptors
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructors
import org.jetbrains.kotlin.backend.konan.irasdescriptors.getObjCMethodInfo
import org.jetbrains.kotlin.backend.konan.irasdescriptors.getSuperClassNotAny
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isReal
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
@@ -41,10 +41,12 @@ import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
@@ -53,10 +55,6 @@ import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import org.jetbrains.kotlin.types.typeUtil.isUnit
internal class InteropLoweringPart1(val context: Context) : IrBuildingTransformer(context), FileLoweringPass {
@@ -83,7 +81,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
private fun IrBuilderWithScope.getObjCClass(classSymbol: IrClassSymbol): IrExpression {
val classDescriptor = classSymbol.descriptor
assert(!classDescriptor.isObjCMetaClass())
return irCall(symbols.interopGetObjCClass, listOf(classDescriptor.defaultType))
return irCall(symbols.interopGetObjCClass, symbols.nativePtrType, listOf(classSymbol.typeWithStarProjections))
}
private val outerClasses = mutableListOf<IrClass>()
@@ -131,7 +129,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
val superClass = irClass.getSuperClassNotAny()!!
val superConstructors = superClass.constructors.filter {
constructor.overridesConstructor(it)
}
}.toList()
val superConstructor = superConstructors.singleOrNull() ?: run {
val annotation = context.interopBuiltIns.objCOverrideInit.name
@@ -179,38 +177,42 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
initMethod.name,
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE
).apply {
val valueParameters = initMethod.valueParameters.map {
ValueParameterDescriptorImpl(
this,
null,
it.index,
Annotations.EMPTY,
it.name,
it.type,
false,
false,
false,
it.varargElementType,
SourceElement.NO_SOURCE
)
}
initialize(
)
val valueParameters = initMethod.valueParameters.map {
val descriptor = ValueParameterDescriptorImpl(
resultDescriptor,
null,
irClass.descriptor.thisAsReceiverParameter,
emptyList<TypeParameterDescriptor>(),
valueParameters,
irClass.defaultType,
Modality.OPEN,
Visibilities.PUBLIC
it.index,
Annotations.EMPTY,
it.name,
it.descriptor.type,
false,
false,
false,
it.varargElementType?.toKotlinType(),
SourceElement.NO_SOURCE
)
it.copy(descriptor)
}
resultDescriptor.initialize(
null,
irClass.descriptor.thisAsReceiverParameter,
emptyList<TypeParameterDescriptor>(),
valueParameters.map { it.descriptor as ValueParameterDescriptor },
irClass.descriptor.defaultType,
Modality.OPEN,
Visibilities.PUBLIC
)
return IrFunctionImpl(
constructor.startOffset, constructor.endOffset, OVERRIDING_INITIALIZER_BY_CONSTRUCTOR,
resultDescriptor
).also { result ->
result.createParameterDeclarations()
result.returnType = irClass.defaultType
result.parent = irClass
result.createDispatchReceiverParameter()
result.valueParameters += valueParameters
result.overriddenSymbols.add(initMethod.symbol)
result.descriptor.overriddenDescriptors = listOf(initMethod.descriptor)
@@ -218,10 +220,10 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
result.body = context.createIrBuilder(result.symbol).irBlockBody(result) {
+irReturn(
irCall(symbols.interopObjCObjectInitBy, listOf(irClass.defaultType)).apply {
extensionReceiver = irGet(result.dispatchReceiverParameter!!.symbol)
putValueArgument(0, irCall(constructor.symbol).also {
extensionReceiver = irGet(result.dispatchReceiverParameter!!)
putValueArgument(0, irCall(constructor).also {
result.valueParameters.forEach { parameter ->
it.putValueArgument(parameter.index, irGet(parameter.symbol))
it.putValueArgument(parameter.index, irGet(parameter))
}
})
}
@@ -236,9 +238,9 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
IrDeclarationOriginImpl("OVERRIDING_INITIALIZER_BY_CONSTRUCTOR")
private fun IrConstructor.overridesConstructor(other: IrConstructor): Boolean {
return this.valueParameters.size == other.valueParameters.size &&
this.valueParameters.all {
val otherParameter = other.valueParameters[it.index]
return this.descriptor.valueParameters.size == other.descriptor.valueParameters.size &&
this.descriptor.valueParameters.all {
val otherParameter = other.descriptor.valueParameters[it.index]
it.name == otherParameter.name && it.type == otherParameter.type
}
}
@@ -260,10 +262,10 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
}
}
val returnType = function.descriptor.returnType!!
val returnType = function.returnType
if (!returnType.isUnit()) {
context.reportCompilationError("Unexpected $action method return type: $returnType\n" +
context.reportCompilationError("Unexpected $action method return type: ${returnType.toKotlinType()}\n" +
"Only 'Unit' is supported here",
currentFile, function
)
@@ -303,7 +305,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
private fun getMethodSignatureEncoding(function: IrFunction): String {
assert(function.extensionReceiverParameter == null)
assert(function.valueParameters.all { it.type.isObjCObjectType() })
assert(function.descriptor.returnType!!.isUnit())
assert(function.returnType.isUnit())
// Note: these values are valid for x86_64 and arm64.
return when (function.valueParameters.size) {
@@ -319,10 +321,10 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
private fun generateFunctionImp(selector: String, function: IrFunction): IrSimpleFunction {
val signatureEncoding = getMethodSignatureEncoding(function)
val returnType = function.descriptor.returnType!!
val returnType = function.returnType
assert(returnType.isUnit())
val nativePtrType = context.builtIns.nativePtr.defaultType
val nativePtrType = context.ir.symbols.nativePtrType
val parameterTypes = mutableListOf(nativePtrType) // id self
@@ -353,7 +355,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
index,
Annotations.EMPTY,
Name.identifier("p$index"),
it,
it.toKotlinType(),
false,
false,
false,
@@ -366,7 +368,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
null, null,
emptyList(),
valueParameters,
returnType,
function.descriptor.returnType,
Modality.FINAL,
Visibilities.PRIVATE
)
@@ -375,20 +377,33 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
function.startOffset, function.endOffset,
IrDeclarationOrigin.DEFINED,
newDescriptor
).apply { createParameterDeclarations() }
).apply {
this.returnType = function.returnType
parameterTypes.mapIndexedTo(this.valueParameters) { index, it ->
IrValueParameterImpl(
startOffset,
endOffset,
IrDeclarationOrigin.DEFINED,
descriptor.valueParameters[index],
it,
null
)
}
}
val builder = context.createIrBuilder(newFunction.symbol)
newFunction.body = builder.irBlockBody(newFunction) {
+irCall(function.symbol).apply {
+irCall(function).apply {
dispatchReceiver = interpretObjCPointer(
irGet(newFunction.valueParameters[0].symbol),
irGet(newFunction.valueParameters[0]),
function.dispatchReceiverParameter!!.type
)
function.valueParameters.forEachIndexed { index, parameter ->
putValueArgument(index,
interpretObjCPointer(
irGet(newFunction.valueParameters[index + 2].symbol),
irGet(newFunction.valueParameters[index + 2]),
parameter.type
)
)
@@ -399,8 +414,8 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
return newFunction
}
private fun IrBuilderWithScope.interpretObjCPointer(expression: IrExpression, type: KotlinType): IrExpression {
val callee: IrFunctionSymbol = if (TypeUtils.isNullableType(type)) {
private fun IrBuilderWithScope.interpretObjCPointer(expression: IrExpression, type: IrType): IrExpression {
val callee: IrFunctionSymbol = if (type.containsNull()) {
symbols.interopInterpretObjCPointerOrNull
} else {
symbols.interopInterpretObjCPointer
@@ -534,7 +549,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
val initCall = builder.genLoweredObjCMethodCall(
initMethodInfo,
superQualifier = symbolTable.referenceClass(expression.descriptor.constructedClass),
receiver = builder.getRawPtr(builder.irGet(constructedClass.thisReceiver!!.symbol)),
receiver = builder.getRawPtr(builder.irGet(constructedClass.thisReceiver!!)),
arguments = initMethod.valueParameters.map { expression.getValueArgument(it)!! }
)
@@ -544,10 +559,17 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
return builder.irBlock(expression) {
// Required for the IR to be valid, will be ignored in codegen:
+IrDelegatingConstructorCallImpl(startOffset, endOffset, superConstructor, superConstructor.descriptor)
+IrDelegatingConstructorCallImpl(
startOffset,
endOffset,
context.irBuiltIns.unitType,
superConstructor,
superConstructor.descriptor,
0
)
+irCall(symbols.interopObjCObjectSuperInitCheck).apply {
extensionReceiver = irGet(constructedClass.thisReceiver!!.symbol)
extensionReceiver = irGet(constructedClass.thisReceiver!!)
putValueArgument(0, initCall)
}
}
@@ -560,10 +582,10 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
receiver: IrExpression, arguments: List<IrExpression>): IrExpression {
val superClass = superQualifier?.let { getObjCClass(it) } ?:
irCall(symbols.getNativeNullPtr)
irCall(symbols.getNativeNullPtr, symbols.nativePtrType)
val bridge = symbolTable.referenceSimpleFunction(info.bridge)
return irCall(bridge).apply {
return irCall(bridge, symbolTable.translateErased(info.bridge.returnType!!)).apply {
putValueArgument(0, superClass)
putValueArgument(1, receiver)
@@ -646,18 +668,16 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
return when (descriptor) {
context.interopBuiltIns.typeOf -> {
val typeArgument = expression.getSingleTypeArgument()
val classDescriptor = TypeUtils.getClassDescriptor(typeArgument)
val classSymbol = typeArgument.classifierOrNull as? IrClassSymbol
if (classDescriptor == null) {
if (classSymbol == null) {
expression
} else {
val companionObjectDescriptor = classDescriptor.companionObjectDescriptor ?:
val classDescriptor = classSymbol.descriptor
val companionObject = classDescriptor.companionObjectDescriptor ?:
error("native variable class $classDescriptor must have the companion object")
IrGetObjectValueImpl(
expression.startOffset, expression.endOffset, companionObjectDescriptor.defaultType,
symbolTable.referenceClass(companionObjectDescriptor)
)
builder.at(expression).irGetObject(symbolTable.referenceClass(companionObject))
}
}
else -> expression
@@ -674,14 +694,14 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
val initCall = genLoweredObjCMethodCall(
initMethodInfo,
superQualifier = null,
receiver = irGet(allocated.symbol),
receiver = irGet(allocated),
arguments = arguments
)
+IrTryImpl(startOffset, endOffset, initCall.type).apply {
tryResult = initCall
finallyExpression = irCall(symbols.interopObjCRelease).apply {
putValueArgument(0, irGet(allocated.symbol)) // Balance pointer retained by alloc.
putValueArgument(0, irGet(allocated)) // Balance pointer retained by alloc.
}
}
}
@@ -770,8 +790,8 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
}
val targetSymbol = irCallableReference.symbol
val target = targetSymbol.descriptor
val signatureTypes = target.allParameters.map { it.type } + target.returnType!!
val target = targetSymbol.owner
val signatureTypes = target.allParameters.map { it.type } + target.returnType
signatureTypes.forEachIndexed { index, type ->
type.ensureSupportedInCallbacks(
@@ -781,9 +801,10 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
}
descriptor.typeParameters.forEachIndexed { index, typeParameterDescriptor ->
val typeArgument = expression.getTypeArgument(typeParameterDescriptor)!!
val signatureType = signatureTypes[index]
if (typeArgument != signatureType) {
val typeArgument = expression.getTypeArgument(typeParameterDescriptor)!!.toKotlinType()
val signatureType = signatureTypes[index].toKotlinType()
if (typeArgument.constructor != signatureType.constructor ||
typeArgument.isMarkedNullable != signatureType.isMarkedNullable) {
context.reportCompilationError(
"C function signature element mismatch: expected '$signatureType', got '$typeArgument'",
irFile, expression
@@ -794,8 +815,8 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
IrFunctionReferenceImpl(
builder.startOffset, builder.endOffset,
expression.type,
targetSymbol, target,
typeArguments = null)
targetSymbol, target.descriptor,
typeArgumentsCount = 0)
}
interop.scheduleFunction -> {
@@ -812,9 +833,9 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
val target = targetSymbol.descriptor
val jobPointer = IrFunctionReferenceImpl(
builder.startOffset, builder.endOffset,
interop.cPointer.defaultType,
symbols.scheduleImpl.owner.valueParameters[3].type,
targetSymbol, target,
typeArguments = null)
typeArgumentsCount = 0)
builder.irCall(symbols.scheduleImpl).apply {
putValueArgument(0, expression.dispatchReceiver)
@@ -827,33 +848,36 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
interop.signExtend, interop.narrow -> {
val integerTypePredicates = arrayOf(
KotlinBuiltIns::isByte, KotlinBuiltIns::isShort, KotlinBuiltIns::isInt, KotlinBuiltIns::isLong
IrType::isByte, IrType::isShort, IrType::isInt, IrType::isLong
)
val receiver = expression.extensionReceiver!!
val typeOperand = expression.getSingleTypeArgument()
val kotlinTypeOperand = typeOperand.toKotlinType()
val receiverTypeIndex = integerTypePredicates.indexOfFirst { it(receiver.type) }
val typeOperandIndex = integerTypePredicates.indexOfFirst { it(typeOperand) }
val receiverKotlinType = receiver.type.toKotlinType()
if (receiverTypeIndex == -1) {
context.reportCompilationError("Receiver's type ${receiver.type} is not an integer type",
context.reportCompilationError("Receiver's type $receiverKotlinType is not an integer type",
irFile, receiver)
}
if (typeOperandIndex == -1) {
context.reportCompilationError("Type argument $typeOperand is not an integer type",
context.reportCompilationError("Type argument $kotlinTypeOperand is not an integer type",
irFile, expression)
}
when (descriptor) {
interop.signExtend -> if (receiverTypeIndex > typeOperandIndex) {
context.reportCompilationError("unable to sign extend ${receiver.type} to $typeOperand",
context.reportCompilationError("unable to sign extend $receiverKotlinType to $kotlinTypeOperand",
irFile, expression)
}
interop.narrow -> if (receiverTypeIndex < typeOperandIndex) {
context.reportCompilationError("unable to narrow ${receiver.type} to $typeOperand",
context.reportCompilationError("unable to narrow $receiverKotlinType to $kotlinTypeOperand",
irFile, expression)
}
@@ -863,8 +887,12 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
val receiverClass = symbols.integerClasses.single {
receiver.type.isSubtypeOf(it.owner.defaultType)
}
val targetClass = symbols.integerClasses.single {
typeOperand.isSubtypeOf(it.owner.defaultType)
}
val conversionSymbol = receiverClass.functions.single {
it.descriptor.name == Name.identifier("to$typeOperand")
it.descriptor.name == Name.identifier("to${targetClass.owner.name}")
}
builder.irCall(conversionSymbol).apply {
@@ -880,16 +908,16 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
returnType.checkCTypeNullability(::reportError)
val invokeImpl = symbols.interopInvokeImpls[TypeUtils.getClassDescriptor(returnType)] ?:
val invokeImpl = symbols.interopInvokeImpls[returnType.getClass()?.descriptor] ?:
context.reportCompilationError(
"Invocation of C function pointer with return type '$returnType' is not supported yet",
"Invocation of C function pointer with return type '${returnType.toKotlinType()}' is not supported yet",
irFile, expression
)
builder.irCall(invokeImpl).apply {
putValueArgument(0, expression.extensionReceiver)
val varargParameter = invokeImpl.descriptor.valueParameters[1]
val varargParameter = invokeImpl.owner.valueParameters[1]
val varargArgument = IrVarargImpl(
startOffset, endOffset, varargParameter.type, varargParameter.varargElementType!!
).apply {
@@ -897,7 +925,7 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
this.addElement(expression.getValueArgument(it)!!)
}
}
putValueArgument(varargParameter, varargArgument)
putValueArgument(varargParameter.index, varargArgument)
}
}
@@ -928,31 +956,31 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
}
}
private fun KotlinType.ensureSupportedInCallbacks(isReturnType: Boolean, reportError: (String) -> Nothing) {
private fun IrType.ensureSupportedInCallbacks(isReturnType: Boolean, reportError: (String) -> Nothing) {
this.checkCTypeNullability(reportError)
if (isReturnType && KotlinBuiltIns.isUnit(this)) {
if (isReturnType && this.isUnit()) {
return
}
if (KotlinBuiltIns.isPrimitiveType(this)) {
if (this.isPrimitiveType()) {
return
}
if (TypeUtils.getClassDescriptor(this) == interop.cPointer) {
if (this.getClass()?.descriptor == interop.cPointer) {
return
}
reportError("Type $this is not supported in callback signature")
reportError("Type ${this.toKotlinType()} is not supported in callback signature")
}
private fun KotlinType.checkCTypeNullability(reportError: (String) -> Nothing) {
if (KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType(this) && this.isMarkedNullable) {
reportError("Type $this must not be nullable when used in C function signature")
private fun IrType.checkCTypeNullability(reportError: (String) -> Nothing) {
if (this.isNullablePrimitiveType()) {
reportError("Type ${this.toKotlinType()} must not be nullable when used in C function signature")
}
if (TypeUtils.getClassDescriptor(this) == interop.cPointer && !this.isMarkedNullable) {
reportError("Type $this must be nullable when used in C function signature")
if (this.getClass() == interop.cPointer && !this.isSimpleTypeWithQuestionMark) {
reportError("Type ${this.toKotlinType()} must be nullable when used in C function signature")
}
}
@@ -986,15 +1014,15 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
}
}
private fun IrCall.getSingleTypeArgument(): KotlinType {
private fun IrCall.getSingleTypeArgument(): IrType {
val typeParameter = descriptor.original.typeParameters.single()
return getTypeArgument(typeParameter)!!
}
private fun IrBuilder.irFloat(value: Float) =
IrConstImpl.float(startOffset, endOffset, context.builtIns.floatType, value)
IrConstImpl.float(startOffset, endOffset, context.irBuiltIns.floatType, value)
private fun IrBuilder.irDouble(value: Double) =
IrConstImpl.double(startOffset, endOffset, context.builtIns.doubleType, value)
IrConstImpl.double(startOffset, endOffset, context.irBuiltIns.doubleType, value)
private fun Annotations.hasAnnotation(descriptor: ClassDescriptor) = this.hasAnnotation(descriptor.fqNameSafe)
@@ -21,23 +21,23 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
@@ -59,6 +59,21 @@ internal class LateinitLowering(
private val isInitializedGetterDescriptor = isInitializedPropertyDescriptor.getter!!
override fun lower(irFile: IrFile) {
val lateinitPropertyToField = mutableMapOf<PropertyDescriptor, IrField>()
irFile.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitProperty(declaration: IrProperty) {
super.visitProperty(declaration)
if (declaration.isLateinit && declaration.descriptor.kind.isReal) {
lateinitPropertyToField[declaration.descriptor] = declaration.backingField!!
}
}
})
irFile.transformChildrenVoid(object : IrBuildingTransformer(context) {
override fun visitVariable(declaration: IrVariable): IrStatement {
@@ -85,10 +100,10 @@ internal class LateinitLowering(
return irBlock(expression) {
// TODO: do data flow analysis to check if value is proved to be not-null.
+irIfThen(
irEqualsNull(irGet(symbol)),
irEqualsNull(irGet(expression.type, symbol)),
throwUninitializedPropertyAccessException(symbol)
)
+irGet(symbol)
+irGet(expression.type, symbol)
}
}
}
@@ -101,19 +116,13 @@ internal class LateinitLowering(
val propertyReference = expression.extensionReceiver!! as IrPropertyReference
assert(propertyReference.extensionReceiver == null, { "'lateinit' modifier is not allowed on extension properties" })
// TODO: Take propertyReference.fieldSymbol as soon as it will show up in IR.
val propertyDescriptor = propertyReference.descriptor.resolveFakeOverride().original
val type = propertyDescriptor.type
assert(!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" })
builder.at(expression).run {
@Suppress("DEPRECATION")
val fieldValue = IrGetFieldImpl(
expression.startOffset,
expression.endOffset,
propertyDescriptor,
propertyReference.dispatchReceiver
)
val field = lateinitPropertyToField[propertyDescriptor]!!
val fieldValue = irGetField(propertyReference.dispatchReceiver, field)
return irNotEquals(fieldValue, irNull())
}
}
@@ -125,7 +134,7 @@ internal class LateinitLowering(
return declaration
val backingField = declaration.backingField!!
transformGetter(backingField.symbol, declaration.getter!!)
transformGetter(backingField, declaration.getter!!)
assert(backingField.initializer == null, { "'lateinit' modifier is not allowed for properties with initializer" })
val irBuilder = context.createIrBuilder(backingField.symbol, declaration.startOffset, declaration.endOffset)
@@ -136,20 +145,20 @@ internal class LateinitLowering(
return declaration
}
private fun transformGetter(backingFieldSymbol: IrFieldSymbol, getter: IrFunction) {
val type = backingFieldSymbol.descriptor.type
private fun transformGetter(backingField: IrField, getter: IrFunction) {
val type = backingField.descriptor.type
assert(!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" })
val irBuilder = context.createIrBuilder(getter.symbol, getter.startOffset, getter.endOffset)
irBuilder.run {
getter.body = irBlockBody {
val resultVar = irTemporary(
irGetField(getter.dispatchReceiverParameter?.let { irGet(it.symbol) }, backingFieldSymbol)
irGetField(getter.dispatchReceiverParameter?.let { irGet(it) }, backingField)
)
+irIfThenElse(
context.builtIns.nothingType,
irNotEquals(irGet(resultVar.symbol), irNull()),
irReturn(irGet(resultVar.symbol)),
throwUninitializedPropertyAccessException(backingFieldSymbol)
context.irBuiltIns.nothingType,
irNotEquals(irGet(resultVar), irNull()),
irReturn(irGet(resultVar)),
throwUninitializedPropertyAccessException(backingField.symbol)
)
}
}
@@ -158,14 +167,14 @@ internal class LateinitLowering(
}
private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(backingFieldSymbol: IrSymbol) =
irCall(throwErrorFunction).apply {
irCall(throwErrorFunction, context.irBuiltIns.nothingType).apply {
if (generateParameterNameInAssertion) {
putValueArgument(
0,
IrConstImpl.string(
startOffset,
endOffset,
context.builtIns.stringType,
context.irBuiltIns.stringType,
backingFieldSymbol.descriptor.name.asString()
)
)
@@ -1,754 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.lower.Closure
import org.jetbrains.kotlin.backend.common.lower.ClosureAnnotator
import org.jetbrains.kotlin.backend.common.lower.callsSuper
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.util.addChild
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
// TODO: Remove as soon as its version is fixed in common code.
class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContainerLoweringPass {
private object DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE :
IrDeclarationOriginImpl("FIELD_FOR_CAPTURED_VALUE") {}
private object STATEMENT_ORIGIN_INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE :
IrStatementOriginImpl("INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE") {}
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
if (irDeclarationContainer is IrDeclaration &&
irDeclarationContainer.descriptor.parents.any { it is CallableDescriptor }) {
// Lowering of non-local declarations handles all local declarations inside.
// This declaration is local and shouldn't be considered.
return
}
// Continuous numbering across all declarations in the container.
lambdasCount = 0
irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
// TODO: may be do the opposite - specify the list of IR elements which need not to be transformed
when (memberDeclaration) {
is IrFunction -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
is IrProperty -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
is IrField -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
is IrAnonymousInitializer -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
else -> null
}
}
}
private var lambdasCount = 0
private abstract class LocalContext {
/**
* @return the expression to get the value for given descriptor, or `null` if [IrGetValue] should be used.
*/
abstract fun irGet(startOffset: Int, endOffset: Int, descriptor: ValueDescriptor): IrExpression?
}
private abstract class LocalContextWithClosureAsParameters : LocalContext() {
abstract val declaration: IrFunction
open val descriptor: FunctionDescriptor
get() = declaration.descriptor
abstract val transformedDescriptor: FunctionDescriptor
abstract val transformedDeclaration: IrFunction
val capturedValueToParameter: MutableMap<ValueDescriptor, IrValueParameterSymbol> = HashMap()
override fun irGet(startOffset: Int, endOffset: Int, descriptor: ValueDescriptor): IrExpression? {
val newSymbol = capturedValueToParameter[descriptor] ?: return null
return IrGetValueImpl(startOffset, endOffset, newSymbol)
}
}
private class LocalFunctionContext(override val declaration: IrFunction) : LocalContextWithClosureAsParameters() {
lateinit var closure: Closure
override lateinit var transformedDescriptor: FunctionDescriptor
override lateinit var transformedDeclaration: IrSimpleFunction
var index: Int = -1
override fun toString(): String =
"LocalFunctionContext for $descriptor"
}
private class LocalClassConstructorContext(override val declaration: IrConstructor) : LocalContextWithClosureAsParameters() {
override val descriptor: ClassConstructorDescriptor
get() = declaration.descriptor
override lateinit var transformedDescriptor: ClassConstructorDescriptor
override lateinit var transformedDeclaration: IrConstructor
override fun toString(): String =
"LocalClassConstructorContext for $descriptor"
}
private class LocalClassContext(val declaration: IrClass) : LocalContext() {
val descriptor: ClassDescriptor
get() = declaration.descriptor
lateinit var closure: Closure
val capturedValueToField: MutableMap<ValueDescriptor, IrField> = HashMap()
override fun irGet(startOffset: Int, endOffset: Int, descriptor: ValueDescriptor): IrExpression? {
val field = capturedValueToField[descriptor] ?: return null
return IrGetFieldImpl(startOffset, endOffset, field.symbol,
receiver = IrGetValueImpl(startOffset, endOffset, declaration.thisReceiver!!.symbol)
)
}
override fun toString(): String =
"LocalClassContext for ${descriptor}"
}
private class LocalClassMemberContext(val member: IrFunction, val classContext: LocalClassContext) : LocalContext() {
override fun irGet(startOffset: Int, endOffset: Int, descriptor: ValueDescriptor): IrExpression? {
val field = classContext.capturedValueToField[descriptor] ?: return null
return IrGetFieldImpl(startOffset, endOffset, field.symbol,
receiver = IrGetValueImpl(startOffset, endOffset, member.dispatchReceiverParameter!!.symbol)
)
}
}
private inner class LocalDeclarationsTransformer(val memberDeclaration: IrDeclaration) {
val localFunctions: MutableMap<FunctionDescriptor, LocalFunctionContext> = LinkedHashMap()
val localClasses: MutableMap<ClassDescriptor, LocalClassContext> = LinkedHashMap()
val localClassConstructors: MutableMap<ClassConstructorDescriptor, LocalClassConstructorContext> = LinkedHashMap()
val transformedDeclarations = mutableMapOf<DeclarationDescriptor, IrSymbol>()
val FunctionDescriptor.transformed: IrFunctionSymbol?
get() = transformedDeclarations[this] as IrFunctionSymbol?
val oldParameterToNew: MutableMap<ParameterDescriptor, IrValueParameterSymbol> = HashMap()
val newParameterToOld: MutableMap<ParameterDescriptor, ParameterDescriptor> = HashMap()
val newParameterToCaptured: MutableMap<ValueParameterDescriptor, IrValueSymbol> = HashMap()
fun lowerLocalDeclarations(): List<IrDeclaration>? {
collectLocalDeclarations()
if (localFunctions.isEmpty() && localClasses.isEmpty()) return null
collectClosures()
transformDescriptors()
rewriteDeclarations()
val result = collectRewrittenDeclarations()
result.forEach { it.parent = memberDeclaration.parent }
return result
}
private fun collectRewrittenDeclarations(): ArrayList<IrDeclaration> =
ArrayList<IrDeclaration>(localFunctions.size + localClasses.size + 1).apply {
add(memberDeclaration)
localFunctions.values.mapTo(this) {
val original = it.declaration
it.transformedDeclaration.apply {
this.body = original.body
original.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument ->
val body = original.getDefault(argument)!!
oldParameterToNew[argument]!!.owner.defaultValue = body
}
}
}
localClasses.values.mapTo(this) {
it.declaration
}
}
private inner class FunctionBodiesRewriter(val localContext: LocalContext?) : IrElementTransformerVoid() {
override fun visitClass(declaration: IrClass): IrStatement {
if (declaration.descriptor in localClasses) {
// Replace local class definition with an empty composite.
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
} else {
return super.visitClass(declaration)
}
}
override fun visitFunction(declaration: IrFunction): IrStatement {
if (declaration.descriptor in localFunctions) {
// Replace local function definition with an empty composite.
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
} else {
if (localContext is LocalClassContext && declaration.parent == localContext.declaration) {
return declaration.apply {
val classMemberLocalContext = LocalClassMemberContext(declaration, localContext)
transformChildrenVoid(FunctionBodiesRewriter(classMemberLocalContext))
}
} else {
return super.visitFunction(declaration)
}
}
}
override fun visitConstructor(declaration: IrConstructor): IrStatement {
// Body is transformed separately. See loop over constructors in rewriteDeclarations().
val constructorContext = localClassConstructors[declaration.descriptor]
if (constructorContext != null) {
return constructorContext.transformedDeclaration.apply {
this.parent = declaration.parent
this.body = declaration.body!!
declaration.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument ->
val body = declaration.getDefault(argument)!!
oldParameterToNew[argument]!!.owner.defaultValue = body
}
}
} else {
return super.visitConstructor(declaration)
}
}
override fun visitGetValue(expression: IrGetValue): IrExpression {
val descriptor = expression.descriptor
localContext?.irGet(expression.startOffset, expression.endOffset, descriptor)?.let {
return it
}
oldParameterToNew[descriptor]?.let {
return IrGetValueImpl(expression.startOffset, expression.endOffset, it)
}
return expression
}
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
val oldCallee = expression.descriptor.original
val newCallee = oldCallee.transformed ?: return expression
val newCall = createNewCall(expression, newCallee).fillArguments(expression)
return newCall
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.transformChildrenVoid(this)
val oldCallee = expression.descriptor.original
val newCallee = transformedDeclarations[oldCallee] as IrConstructorSymbol? ?: return expression
val newExpression = IrDelegatingConstructorCallImpl(
expression.startOffset, expression.endOffset,
newCallee,
newCallee.descriptor,
remapTypeArguments(expression, newCallee.descriptor)
).fillArguments(expression)
return newExpression
}
private fun <T : IrMemberAccessExpression> T.fillArguments(oldExpression: IrMemberAccessExpression): T {
mapValueParameters { newValueParameterDescriptor ->
val oldParameter = newParameterToOld[newValueParameterDescriptor]
if (oldParameter != null) {
oldExpression.getValueArgument(oldParameter as ValueParameterDescriptor)
} else {
// The callee expects captured value as argument.
val capturedValueSymbol =
newParameterToCaptured[newValueParameterDescriptor] ?:
throw AssertionError("Non-mapped parameter $newValueParameterDescriptor")
val capturedValueDescriptor = capturedValueSymbol.descriptor
localContext?.irGet(
oldExpression.startOffset, oldExpression.endOffset,
capturedValueDescriptor
) ?:
// Captured value is directly available for the caller.
IrGetValueImpl(oldExpression.startOffset, oldExpression.endOffset,
oldParameterToNew[capturedValueDescriptor] ?: capturedValueSymbol)
}
}
dispatchReceiver = oldExpression.dispatchReceiver
extensionReceiver = oldExpression.extensionReceiver
return this
}
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
expression.transformChildrenVoid(this)
val oldCallee = expression.descriptor.original
val newCallee = oldCallee.transformed ?: return expression
val newCallableReference = IrFunctionReferenceImpl(
expression.startOffset, expression.endOffset,
expression.type, // TODO functional type for transformed descriptor
newCallee,
newCallee.descriptor,
remapTypeArguments(expression, newCallee.descriptor),
expression.origin
).fillArguments(expression)
return newCallableReference
}
override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid(this)
val oldReturnTarget = expression.returnTarget
val newReturnTarget = oldReturnTarget.transformed ?: return expression
return IrReturnImpl(expression.startOffset, expression.endOffset, newReturnTarget, expression.value)
}
override fun visitDeclarationReference(expression: IrDeclarationReference): IrExpression {
if (expression.descriptor in transformedDeclarations) {
TODO()
}
return super.visitDeclarationReference(expression)
}
override fun visitDeclaration(declaration: IrDeclaration): IrStatement {
if (declaration.descriptor in transformedDeclarations) {
TODO()
}
return super.visitDeclaration(declaration)
}
}
private fun rewriteFunctionBody(irDeclaration: IrDeclaration, localContext: LocalContext?) {
irDeclaration.transformChildrenVoid(FunctionBodiesRewriter(localContext))
}
private fun rewriteClassMembers(irClass: IrClass, localClassContext: LocalClassContext) {
irClass.transformChildrenVoid(FunctionBodiesRewriter(localClassContext))
val classDescriptor = irClass.descriptor
val constructorsCallingSuper = classDescriptor.constructors
.map { localClassConstructors[it]!! }
.filter { it.declaration.callsSuper() }
assert(constructorsCallingSuper.any(), { "Expected at least one constructor calling super; class: $classDescriptor" })
localClassContext.capturedValueToField.forEach { capturedValue, field ->
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
irClass.addChild(field)
for (constructorContext in constructorsCallingSuper) {
val blockBody = constructorContext.declaration.body as? IrBlockBody
?: throw AssertionError("Unexpected constructor body: ${constructorContext.declaration.body}")
val capturedValueExpression = constructorContext.irGet(startOffset, endOffset, capturedValue)!!
blockBody.statements.add(0,
IrSetFieldImpl(startOffset, endOffset, field.symbol,
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol),
capturedValueExpression, STATEMENT_ORIGIN_INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE))
}
}
}
private fun rewriteDeclarations() {
localFunctions.values.forEach {
rewriteFunctionBody(it.declaration, it)
}
localClassConstructors.values.forEach {
rewriteFunctionBody(it.declaration, it)
}
localClasses.values.forEach {
rewriteClassMembers(it.declaration, it)
}
rewriteFunctionBody(memberDeclaration, null)
}
private fun createNewCall(oldCall: IrCall, newCallee: IrFunctionSymbol) =
if (oldCall is IrCallWithShallowCopy)
oldCall.shallowCopy(oldCall.origin, newCallee, oldCall.superQualifierSymbol)
else
IrCallImpl(
oldCall.startOffset, oldCall.endOffset,
newCallee,
newCallee.descriptor,
remapTypeArguments(oldCall, newCallee.descriptor),
oldCall.origin, oldCall.superQualifierSymbol
)
private fun remapTypeArguments(oldExpression: IrMemberAccessExpression, newCallee: CallableDescriptor): Map<TypeParameterDescriptor, KotlinType>? {
val oldCallee = oldExpression.descriptor.original
return if (oldCallee.typeParameters.isEmpty())
null
else oldCallee.typeParameters.associateBy(
{ newCallee.typeParameters[it.index] },
{ oldExpression.getTypeArgumentOrDefault(it) }
)
}
private fun transformDescriptors() {
localFunctions.values.forEach {
createLiftedDescriptor(it)
}
localClasses.values.forEach {
createFieldsForCapturedValues(it)
}
localClassConstructors.values.forEach {
createTransformedConstructorDescriptor(it)
}
}
private fun suggestLocalName(descriptor: DeclarationDescriptor): String {
localFunctions[descriptor]?.let {
if (it.index >= 0)
return "lambda-${it.index}"
}
return descriptor.name.asString()
}
private fun generateNameForLiftedDeclaration(descriptor: DeclarationDescriptor,
newOwner: DeclarationDescriptor): Name =
Name.identifier(
descriptor.parentsWithSelf
.takeWhile { it != newOwner }
.toList().reversed()
.map { suggestLocalName(it) }
.joinToString(separator = "$")
)
private fun createLiftedDescriptor(localFunctionContext: LocalFunctionContext) {
val oldDescriptor = localFunctionContext.descriptor
val memberOwner = memberDeclaration.descriptor.containingDeclaration!!
val newDescriptor = SimpleFunctionDescriptorImpl.create(
memberOwner,
oldDescriptor.annotations,
generateNameForLiftedDeclaration(oldDescriptor, memberOwner),
CallableMemberDescriptor.Kind.SYNTHESIZED,
oldDescriptor.source
).apply {
isTailrec = oldDescriptor.isTailrec
isSuspend = oldDescriptor.isSuspend
// TODO: copy other properties or consider using `FunctionDescriptor.CopyBuilder`.
}
localFunctionContext.transformedDescriptor = newDescriptor
if (oldDescriptor.dispatchReceiverParameter != null) {
throw AssertionError("local functions must not have dispatch receiver")
}
val newDispatchReceiverParameter = null
// Do not substitute type parameters for now.
val newTypeParameters = oldDescriptor.typeParameters
// TODO: consider using fields to access the closure of enclosing class.
val capturedValues = localFunctionContext.closure.capturedValues
val newValueParameters = createTransformedValueParameters(localFunctionContext, capturedValues)
newDescriptor.initialize(
oldDescriptor.extensionReceiverParameter?.type,
newDispatchReceiverParameter,
newTypeParameters,
newValueParameters,
oldDescriptor.returnType,
Modality.FINAL,
Visibilities.PRIVATE
)
oldDescriptor.extensionReceiverParameter?.let {
newParameterToOld.putAbsentOrSame(newDescriptor.extensionReceiverParameter!!, it)
}
localFunctionContext.transformedDeclaration = with(localFunctionContext.declaration) {
IrFunctionImpl(startOffset, endOffset, origin, newDescriptor)
}.apply {
createParameterDeclarations()
recordTransformedValueParameters(localFunctionContext)
transformedDeclarations[oldDescriptor] = this.symbol
}
}
private fun createTransformedValueParameters(localContext: LocalContextWithClosureAsParameters,
capturedValues: List<IrValueSymbol>)
: List<ValueParameterDescriptor> {
val oldDescriptor = localContext.descriptor
val newDescriptor = localContext.transformedDescriptor
val closureParametersCount = capturedValues.size
val newValueParametersCount = closureParametersCount + oldDescriptor.valueParameters.size
val newValueParameters = ArrayList<ValueParameterDescriptor>(newValueParametersCount).apply {
capturedValues.mapIndexedTo(this) { i, capturedValue ->
createUnsubstitutedCapturedValueParameter(newDescriptor, capturedValue.descriptor, i).apply {
newParameterToCaptured[this] = capturedValue
}
}
oldDescriptor.valueParameters.mapIndexedTo(this) { i, oldValueParameterDescriptor ->
createUnsubstitutedParameter(newDescriptor, oldValueParameterDescriptor, closureParametersCount + i).apply {
newParameterToOld.putAbsentOrSame(this, oldValueParameterDescriptor)
}
}
}
return newValueParameters
}
private fun IrFunction.recordTransformedValueParameters(localContext: LocalContextWithClosureAsParameters) {
valueParameters.forEach {
val capturedValue = newParameterToCaptured[it.descriptor]
if (capturedValue != null) {
localContext.capturedValueToParameter[capturedValue.descriptor] = it.symbol
}
}
(listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters).forEach {
val oldParameter = newParameterToOld[it.descriptor]
if (oldParameter != null) {
oldParameterToNew.putAbsentOrSame(oldParameter, it.symbol)
}
}
}
private fun createTransformedConstructorDescriptor(constructorContext: LocalClassConstructorContext) {
val oldDescriptor = constructorContext.descriptor
val localClassContext = localClasses[oldDescriptor.containingDeclaration]!!
val newDescriptor = ClassConstructorDescriptorImpl.create(
localClassContext.descriptor,
Annotations.EMPTY, oldDescriptor.isPrimary, oldDescriptor.source)
constructorContext.transformedDescriptor = newDescriptor
// Do not substitute type parameters for now.
val newTypeParameters = oldDescriptor.typeParameters
val capturedValues = localClasses[oldDescriptor.containingDeclaration]!!.closure.capturedValues
val newValueParameters = createTransformedValueParameters(constructorContext, capturedValues)
newDescriptor.initialize(
newValueParameters,
Visibilities.PRIVATE,
newTypeParameters
)
newDescriptor.returnType = oldDescriptor.returnType
oldDescriptor.dispatchReceiverParameter?.let {
newParameterToOld.putAbsentOrSame(newDescriptor.dispatchReceiverParameter!!, it)
}
oldDescriptor.extensionReceiverParameter?.let {
throw AssertionError("constructors can't have extension receiver")
}
constructorContext.transformedDeclaration = with(constructorContext.declaration) {
IrConstructorImpl(startOffset, endOffset, origin, newDescriptor)
}.apply {
createParameterDeclarations()
recordTransformedValueParameters(constructorContext)
transformedDeclarations[oldDescriptor] = this.symbol
}
}
private fun createFieldsForCapturedValues(localClassContext: LocalClassContext) {
val classDescriptor = localClassContext.descriptor
localClassContext.closure.capturedValues.forEach { capturedValue ->
val fieldDescriptor = PropertyDescriptorImpl.create(
classDescriptor,
Annotations.EMPTY,
Modality.FINAL,
Visibilities.PRIVATE,
/* isVar = */ false,
suggestNameForCapturedValue(capturedValue.descriptor),
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE,
/* lateInit = */ false,
/* isConst = */ false,
/* isExpect = */ false,
/* isActual = */ false,
/* isExternal = */ false,
/* isDelegated = */ false)
fieldDescriptor.initialize(/* getter = */ null, /* setter = */ null)
val extensionReceiverParameter: ReceiverParameterDescriptor? = null
fieldDescriptor.setType(
capturedValue.descriptor.type,
emptyList<TypeParameterDescriptor>(),
classDescriptor.thisAsReceiverParameter,
extensionReceiverParameter)
localClassContext.capturedValueToField[capturedValue.descriptor] = IrFieldImpl(
localClassContext.declaration.startOffset, localClassContext.declaration.endOffset,
DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE,
fieldDescriptor
)
}
}
private fun <K, V> MutableMap<K, V>.putAbsentOrSame(key: K, value: V) {
val current = this.getOrPut(key, { value })
if (current != value) {
error("$current != $value")
}
}
private fun suggestNameForCapturedValue(valueDescriptor: ValueDescriptor): Name =
if (valueDescriptor.name.isSpecial) {
val oldNameStr = valueDescriptor.name.asString()
oldNameStr.substring(1, oldNameStr.length - 1).synthesizedName
} else
valueDescriptor.name
private fun createUnsubstitutedCapturedValueParameter(
newParameterOwner: CallableMemberDescriptor,
valueDescriptor: ValueDescriptor,
index: Int
): ValueParameterDescriptor =
ValueParameterDescriptorImpl(
newParameterOwner, null, index,
valueDescriptor.annotations,
suggestNameForCapturedValue(valueDescriptor),
valueDescriptor.type,
false, false, false, null, valueDescriptor.source
)
private fun createUnsubstitutedParameter(
newParameterOwner: CallableMemberDescriptor,
valueParameterDescriptor: ValueParameterDescriptor,
newIndex: Int
): ValueParameterDescriptor =
valueParameterDescriptor.copy(newParameterOwner, valueParameterDescriptor.name, newIndex)
private fun collectClosures() {
val annotator = ClosureAnnotator(memberDeclaration)
localFunctions.forEach { descriptor, context ->
context.closure = annotator.getFunctionClosure(descriptor)
}
localClasses.forEach { descriptor, context ->
context.closure = annotator.getClassClosure(descriptor)
}
}
private fun collectLocalDeclarations() {
memberDeclaration.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
private fun ClassDescriptor.declaredInFunction() = when (this.containingDeclaration) {
is CallableDescriptor -> true
is ClassDescriptor -> false
is PackageFragmentDescriptor -> false
else -> TODO(this.toString() + "\n" + this.containingDeclaration.toString())
}
override fun visitFunction(declaration: IrFunction) {
declaration.acceptChildrenVoid(this)
val descriptor = declaration.descriptor
if (descriptor.visibility == Visibilities.LOCAL) {
val localFunctionContext = LocalFunctionContext(declaration)
localFunctions[descriptor] = localFunctionContext
if (descriptor.name.isSpecial) {
localFunctionContext.index = lambdasCount++
}
}
}
override fun visitConstructor(declaration: IrConstructor) {
declaration.acceptChildrenVoid(this)
val descriptor = declaration.descriptor
assert(descriptor.visibility != Visibilities.LOCAL)
if (descriptor.constructedClass.isInner) return
localClassConstructors[descriptor] = LocalClassConstructorContext(declaration)
}
override fun visitClass(declaration: IrClass) {
declaration.acceptChildrenVoid(this)
val descriptor = declaration.descriptor
if (descriptor.isInner) return
// Local nested classes can only be inner.
assert(descriptor.declaredInFunction())
val localClassContext = LocalClassContext(declaration)
localClasses[descriptor] = localClassContext
}
})
}
}
}
@@ -20,11 +20,14 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer
import org.jetbrains.kotlin.backend.common.lower.at
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWithStarProjections
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWithoutArguments
import org.jetbrains.kotlin.backend.konan.reportCompilationError
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
/**
@@ -43,7 +46,7 @@ internal class PostInlineLowering(val context: Context) : FileLoweringPass {
expression.transformChildrenVoid()
builder.at(expression)
val typeArgument = expression.descriptor.defaultType
val typeArgument = expression.symbol.typeWithStarProjections
return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply {
putValueArgument(0, builder.irCall(symbols.getClassTypeInfo, listOf(typeArgument)))
@@ -54,7 +57,7 @@ internal class PostInlineLowering(val context: Context) : FileLoweringPass {
expression.transformChildrenVoid()
builder.at(expression)
val typeArgument = expression.type.arguments.single().type
val typeArgument = expression.argument.type
return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply {
val typeInfo = builder.irCall(symbols.getObjectTypeInfo).apply {
putValueArgument(0, expression.argument)
@@ -95,7 +98,7 @@ internal class PostInlineLowering(val context: Context) : FileLoweringPass {
}
expression.putValueArgument(0, IrConstImpl<String>(
expression.startOffset, expression.endOffset,
context.ir.symbols.immutableBinaryBlob.descriptor.defaultType,
context.ir.symbols.immutableBinaryBlob.typeWithoutArguments,
IrConstKind.String, builder.toString()))
}
@@ -24,8 +24,8 @@ import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.typeUtil.isUnit
/**
* This pass runs before inlining and performs the following additional transformations over some operations:
@@ -17,9 +17,7 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.descriptors.getFunction
import org.jetbrains.kotlin.backend.common.descriptors.replace
import org.jetbrains.kotlin.backend.common.ir.createOverriddenDescriptor
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.Context
@@ -27,6 +25,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.IrSuspendableExpressionImpl
import org.jetbrains.kotlin.backend.konan.ir.IrSuspensionPoint
import org.jetbrains.kotlin.backend.konan.ir.IrSuspensionPointImpl
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
@@ -35,12 +34,10 @@ import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
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.*
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
@@ -48,15 +45,12 @@ import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
internal class SuspendFunctionsLowering(val context: Context): DeclarationContainerLoweringPass {
@@ -212,7 +206,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
}
private val symbols = context.ir.symbols
private val getContinuationSymbol = symbols.getContinuation
private val getContinuation = symbols.getContinuation.owner
private val continuationClassSymbol = getContinuation.returnType.classifierOrFail as IrClassSymbol
private val returnIfSuspendedDescriptor = context.getInternalFunctions("returnIfSuspended").single()
private fun removeReturnIfSuspendedCallAndSimplifyDelegatingCall(irFunction: IrFunction, delegatingCall: IrCall) {
@@ -245,7 +240,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
putValueArgument(index, irGet(argument))
}
putValueArgument(functionParameters.size,
irCall(getContinuationSymbol, listOf(descriptor.returnType!!)))
irCall(getContinuation, listOf(irFunction.returnType)))
}
putValueArgument(0, irGetObject(symbols.unit)) // value
putValueArgument(1, irNull()) // exception
@@ -268,59 +263,50 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
private val coroutinesScope = context.irModule!!.descriptor.getPackage(COROUTINES_FQ_NAME).memberScope
private val kotlinPackageScope = context.irModule!!.descriptor.getPackage(KOTLIN_FQ_NAME).memberScope
private val continuationClassDescriptor = coroutinesScope
.getContributedClassifier(Name.identifier("Continuation"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
private inner class CoroutineBuilder(val irFunction: IrFunction, val functionReference: IrFunctionReference?) {
private val functionParameters = irFunction.descriptor.explicitParameters
private val boundFunctionParameters = functionReference?.getArguments()?.map { it.first }
private val functionParameters = irFunction.explicitParameters
private val boundFunctionParameters = functionReference?.getArgumentsWithIr()?.map { it.first }
private val unboundFunctionParameters = boundFunctionParameters?.let { functionParameters - it }
private var tempIndex = 0
private var suspensionPointIdIndex = 0
private lateinit var suspendResult: IrVariableSymbol
private lateinit var dataArgument: IrValueParameterSymbol
private lateinit var exceptionArgument: IrValueParameterSymbol
private lateinit var suspendResult: IrVariable
private lateinit var dataArgument: IrValueParameter
private lateinit var exceptionArgument: IrValueParameter
private lateinit var coroutineClassDescriptor: ClassDescriptorImpl
private lateinit var coroutineClass: IrClassImpl
private lateinit var coroutineClassThis: IrValueParameterSymbol
private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrFieldSymbol>
private lateinit var coroutineClassThis: IrValueParameter
private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrField>
private val coroutineImplSymbol = symbols.coroutineImpl
private val coroutineImplConstructorSymbol = coroutineImplSymbol.constructors.single()
private val coroutineImplClassDescriptor = coroutineImplSymbol.descriptor
private val create1FunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("create"), NoLookupLocation.FROM_BACKEND)
.single { it.valueParameters.size == 1 }
private val create1CompletionParameter = create1FunctionDescriptor.valueParameters[0]
private val create1Function = coroutineImplSymbol.owner.simpleFunctions()
.single { it.name.asString() == "create" && it.valueParameters.size == 1 }
private val create1CompletionParameter = create1Function.valueParameters[0]
private val coroutineImplLabelGetterSymbol = coroutineImplSymbol.getPropertyGetter("label")!!
private val coroutineImplLabelSetterSymbol = coroutineImplSymbol.getPropertySetter("label")!!
fun build(): BuiltCoroutine {
val superTypes = mutableListOf<KotlinType>(coroutineImplClassDescriptor.defaultType)
val superClasses = mutableListOf<IrClass>(coroutineImplSymbol.owner)
var suspendFunctionClassDescriptor: ClassDescriptor? = null
var functionClassDescriptor: ClassDescriptor? = null
var suspendFunctionClassTypeArguments: List<KotlinType>? = null
var functionClassTypeArguments: List<KotlinType>? = null
val superTypes = mutableListOf<IrType>(coroutineImplSymbol.owner.defaultType)
var suspendFunctionClass: IrClass? = null
var functionClass: IrClass? = null
var suspendFunctionClassTypeArguments: List<IrType>? = null
var functionClassTypeArguments: List<IrType>? = null
if (unboundFunctionParameters != null) {
// Suspend lambda inherits SuspendFunction.
val numberOfParameters = unboundFunctionParameters.size
suspendFunctionClassDescriptor = kotlinPackageScope.getContributedClassifier(
Name.identifier("SuspendFunction$numberOfParameters"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
suspendFunctionClass = context.ir.symbols.suspendFunctions[numberOfParameters].owner
val unboundParameterTypes = unboundFunctionParameters.map { it.type }
suspendFunctionClassTypeArguments = unboundParameterTypes + irFunction.descriptor.returnType!!
superTypes += suspendFunctionClassDescriptor.defaultType.replace(suspendFunctionClassTypeArguments)
superClasses += context.ir.symbols.suspendFunctions[numberOfParameters].owner
suspendFunctionClassTypeArguments = unboundParameterTypes + irFunction.returnType
superTypes += suspendFunctionClass.typeWith(suspendFunctionClassTypeArguments)
functionClassDescriptor = kotlinPackageScope.getContributedClassifier(
Name.identifier("Function${numberOfParameters + 1}"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
val continuationType = continuationClassDescriptor.defaultType.replace(listOf(irFunction.descriptor.returnType!!))
functionClassTypeArguments = unboundParameterTypes + continuationType + context.builtIns.nullableAnyType
superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeArguments)
superClasses += context.ir.symbols.functions[numberOfParameters + 1].owner
functionClass = context.ir.symbols.functions[numberOfParameters + 1].owner
val continuationType = continuationClassSymbol.typeWith(irFunction.returnType)
functionClassTypeArguments = unboundParameterTypes + continuationType + context.irBuiltIns.anyNType
superTypes += functionClass.typeWith(functionClassTypeArguments)
}
coroutineClassDescriptor = ClassDescriptorImpl(
@@ -328,11 +314,13 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
/* name = */ "${irFunction.descriptor.name}\$${coroutineId++}".synthesizedName,
/* modality = */ Modality.FINAL,
/* kind = */ ClassKind.CLASS,
/* superTypes = */ superTypes,
/* superTypes = */ superTypes.map { it.toKotlinType() },
/* source = */ SourceElement.NO_SOURCE,
/* isExternal = */ false,
/* storageManager = */ LockBasedStorageManager.NO_LOCKS
)
).also {
it.initialize(stub("coroutine class"), stub("coroutine class constructors"), null)
}
coroutineClass = IrClassImpl(
startOffset = irFunction.startOffset,
endOffset = irFunction.endOffset,
@@ -340,17 +328,19 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
descriptor = coroutineClassDescriptor
)
coroutineClass.parent = irFunction.parent
coroutineClass.createParameterDeclarations()
coroutineClassThis = coroutineClass.thisReceiver!!
val overriddenMap = mutableMapOf<CallableMemberDescriptor, CallableMemberDescriptor>()
val constructors = mutableSetOf<ClassConstructorDescriptor>()
val coroutineConstructorBuilder = createConstructorBuilder()
constructors.add(coroutineConstructorBuilder.symbol.descriptor)
coroutineConstructorBuilder.initialize()
val doResumeFunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("doResume"), NoLookupLocation.FROM_BACKEND).single()
val doResumeMethodBuilder = createDoResumeMethodBuilder(doResumeFunctionDescriptor)
overriddenMap += doResumeFunctionDescriptor to doResumeMethodBuilder.symbol.descriptor
val doResumeFunction = coroutineImplSymbol.owner.simpleFunctions()
.single { it.name.asString() == "doResume" }
val doResumeMethodBuilder = createDoResumeMethodBuilder(doResumeFunction, coroutineClass)
doResumeMethodBuilder.initialize()
overriddenMap += doResumeFunction.descriptor to doResumeMethodBuilder.symbol.descriptor
var coroutineFactoryConstructorBuilder: SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>? = null
var createMethodBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>? = null
@@ -358,7 +348,6 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
if (functionReference != null) {
// Suspend lambda - create factory methods.
coroutineFactoryConstructorBuilder = createFactoryConstructorBuilder(boundFunctionParameters!!)
constructors.add(coroutineFactoryConstructorBuilder.symbol.descriptor)
val createFunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("create"), NoLookupLocation.FROM_BACKEND)
@@ -366,27 +355,24 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
createMethodBuilder = createCreateMethodBuilder(
unboundArgs = unboundFunctionParameters!!,
superFunctionDescriptor = createFunctionDescriptor,
coroutineConstructorSymbol = coroutineConstructorBuilder.symbol)
coroutineConstructor = coroutineConstructorBuilder.ir,
coroutineClass = coroutineClass)
createMethodBuilder.initialize()
if (createFunctionDescriptor != null)
overriddenMap += createFunctionDescriptor to createMethodBuilder.symbol.descriptor
val invokeFunctionDescriptor = functionClassDescriptor!!.getFunction("invoke", functionClassTypeArguments!!)
val suspendInvokeFunctionDescriptor = suspendFunctionClassDescriptor!!.getFunction("invoke", suspendFunctionClassTypeArguments!!)
val invokeFunctionDescriptor = functionClass!!.descriptor
.getFunction("invoke", functionClassTypeArguments!!.map { it.toKotlinType() })
val suspendInvokeFunctionDescriptor = suspendFunctionClass!!.descriptor
.getFunction("invoke", suspendFunctionClassTypeArguments!!.map { it.toKotlinType() })
invokeMethodBuilder = createInvokeMethodBuilder(
suspendFunctionInvokeFunctionDescriptor = suspendInvokeFunctionDescriptor,
functionInvokeFunctionDescriptor = invokeFunctionDescriptor,
createFunctionSymbol = createMethodBuilder.symbol,
doResumeFunctionSymbol = doResumeMethodBuilder.symbol)
createFunction = createMethodBuilder.ir,
doResumeFunction = doResumeMethodBuilder.ir,
coroutineClass = coroutineClass)
}
val memberScope = stub<MemberScope>("coroutine class")
coroutineClassDescriptor.initialize(memberScope, constructors, null)
coroutineClass.createParameterDeclarations()
coroutineClassThis = coroutineClass.thisReceiver!!.symbol
coroutineConstructorBuilder.initialize()
coroutineClass.addChild(coroutineConstructorBuilder.ir)
coroutineFactoryConstructorBuilder?.let {
@@ -395,7 +381,6 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
}
createMethodBuilder?.let {
it.initialize()
coroutineClass.addChild(it.ir)
}
@@ -404,10 +389,9 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
coroutineClass.addChild(it.ir)
}
doResumeMethodBuilder.initialize()
coroutineClass.addChild(doResumeMethodBuilder.ir)
coroutineClass.setSuperSymbolsAndAddFakeOverrides(superClasses)
coroutineClass.setSuperSymbolsAndAddFakeOverrides(superTypes)
return BuiltCoroutine(
coroutineClass = coroutineClass,
@@ -428,21 +412,30 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
)
)
private lateinit var constructorParameters: List<IrValueParameter>
override fun doInitialize() {
val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
val constructorParameters = (
constructorParameters = (
functionParameters
+ coroutineImplConstructorSymbol.descriptor.valueParameters[0] // completion.
).mapIndexed { index, parameter -> parameter.copyAsValueParameter(descriptor, index) }
+ coroutineImplConstructorSymbol.owner.valueParameters[0] // completion.
).mapIndexed { index, parameter ->
descriptor.initialize(constructorParameters, Visibilities.PUBLIC)
val parameterDescriptor = parameter.descriptor.copyAsValueParameter(descriptor, index)
parameter.copy(parameterDescriptor)
}
descriptor.initialize(
constructorParameters.map { it.descriptor as ValueParameterDescriptor },
Visibilities.PUBLIC
)
descriptor.returnType = coroutineClassDescriptor.defaultType
}
override fun buildIr(): IrConstructor {
// Save all arguments to fields.
argumentToPropertiesMap = functionParameters.associate {
it to buildPropertyWithBackingField(it.name, it.type, false)
it.descriptor to addField(it.name, it.type, false)
}
val startOffset = irFunction.startOffset
@@ -453,25 +446,32 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
symbol = symbol).apply {
createParameterDeclarations()
returnType = coroutineClass.defaultType
this.valueParameters += constructorParameters
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody {
val completionParameter = valueParameters.last()
+IrDelegatingConstructorCallImpl(startOffset, endOffset,
context.irBuiltIns.unitType,
coroutineImplConstructorSymbol, coroutineImplConstructorSymbol.descriptor).apply {
putValueArgument(0, irGet(completionParameter.symbol))
putValueArgument(0, irGet(completionParameter))
}
+IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol)
+IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol, context.irBuiltIns.unitType)
functionParameters.forEachIndexed { index, parameter ->
+irSetField(irGet(coroutineClassThis), argumentToPropertiesMap[parameter]!!, irGet(valueParameters[index].symbol))
+irSetField(
irGet(coroutineClassThis),
argumentToPropertiesMap[parameter.descriptor]!!,
irGet(valueParameters[index])
)
}
}
}
}
}
private fun createFactoryConstructorBuilder(boundParams: List<ParameterDescriptor>)
private fun createFactoryConstructorBuilder(boundParams: List<IrValueParameter>)
= object : SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() {
override fun buildSymbol() = IrConstructorSymbolImpl(
@@ -483,12 +483,18 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
)
)
lateinit var constructorParameters: List<IrValueParameter>
override fun doInitialize() {
val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
val constructorParameters = boundParams.mapIndexed { index, parameter ->
parameter.copyAsValueParameter(descriptor, index)
constructorParameters = boundParams.mapIndexed { index, parameter ->
val parameterDescriptor = parameter.descriptor.copyAsValueParameter(descriptor, index)
parameter.copy(parameterDescriptor)
}
descriptor.initialize(constructorParameters, Visibilities.PUBLIC)
descriptor.initialize(
constructorParameters.map { it.descriptor as ValueParameterDescriptor },
Visibilities.PUBLIC
)
descriptor.returnType = coroutineClassDescriptor.defaultType
}
@@ -501,27 +507,32 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
symbol = symbol).apply {
createParameterDeclarations()
returnType = coroutineClass.defaultType
this.valueParameters += constructorParameters
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody {
+IrDelegatingConstructorCallImpl(startOffset, endOffset,
+IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.unitType,
coroutineImplConstructorSymbol, coroutineImplConstructorSymbol.descriptor).apply {
putValueArgument(0, irNull()) // Completion.
}
+IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol)
+IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol,
context.irBuiltIns.unitType)
// Save all arguments to fields.
boundParams.forEachIndexed { index, parameter ->
+irSetField(irGet(coroutineClassThis), argumentToPropertiesMap[parameter]!!, irGet(valueParameters[index].symbol))
+irSetField(irGet(coroutineClassThis), argumentToPropertiesMap[parameter.descriptor]!!,
irGet(valueParameters[index]))
}
}
}
}
}
private fun createCreateMethodBuilder(unboundArgs: List<ParameterDescriptor>,
private fun createCreateMethodBuilder(unboundArgs: List<IrValueParameter>,
superFunctionDescriptor: FunctionDescriptor?,
coroutineConstructorSymbol: IrConstructorSymbol)
coroutineConstructor: IrConstructor,
coroutineClass: IrClass)
= object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
@@ -534,19 +545,21 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
)
)
lateinit var parameters: List<IrValueParameter>
override fun doInitialize() {
val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl
val valueParameters = (
parameters = (
unboundArgs + create1CompletionParameter
).mapIndexed { index, parameter ->
parameter.copyAsValueParameter(descriptor, index)
parameter.copy(parameter.descriptor.copyAsValueParameter(descriptor, index))
}
descriptor.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ coroutineClassDescriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(),
/* unsubstitutedValueParameters = */ valueParameters,
/* unsubstitutedValueParameters = */ parameters.map { it.descriptor as ValueParameterDescriptor },
/* unsubstitutedReturnType = */ coroutineClassDescriptor.defaultType,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE).apply {
@@ -566,25 +579,29 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
symbol = symbol).apply {
createParameterDeclarations()
returnType = coroutineClass.defaultType
parent = coroutineClass
val thisReceiver = this.dispatchReceiverParameter!!.symbol
this.valueParameters += parameters
this.createDispatchReceiverParameter()
val thisReceiver = this.dispatchReceiverParameter!!
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn(
irCall(coroutineConstructorSymbol).apply {
irCall(coroutineConstructor).apply {
var unboundIndex = 0
val unboundArgsSet = unboundArgs.toSet()
functionParameters.map {
if (unboundArgsSet.contains(it))
irGet(valueParameters[unboundIndex++].symbol)
irGet(valueParameters[unboundIndex++])
else
irGetField(irGet(thisReceiver), argumentToPropertiesMap[it]!!)
irGetField(irGet(thisReceiver), argumentToPropertiesMap[it.descriptor]!!)
}.forEachIndexed { index, argument ->
putValueArgument(index, argument)
}
putValueArgument(functionParameters.size, irGet(valueParameters[unboundIndex].symbol))
putValueArgument(functionParameters.size, irGet(valueParameters[unboundIndex]))
assert(unboundIndex == valueParameters.size - 1,
{ "Not all arguments of <create> are used" })
})
@@ -595,8 +612,9 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
private fun createInvokeMethodBuilder(suspendFunctionInvokeFunctionDescriptor: FunctionDescriptor,
functionInvokeFunctionDescriptor: FunctionDescriptor,
createFunctionSymbol: IrFunctionSymbol,
doResumeFunctionSymbol: IrFunctionSymbol)
createFunction: IrFunction,
doResumeFunction: IrFunction,
coroutineClass: IrClass)
= object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
@@ -609,18 +627,20 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
)
)
lateinit var parameters: List<IrValueParameter>
override fun doInitialize() {
val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl
val valueParameters = createFunctionSymbol.descriptor.valueParameters
parameters = createFunction.valueParameters
// Skip completion - invoke() already has it implicitly as a suspend function.
.take(createFunctionSymbol.descriptor.valueParameters.size - 1)
.map { it.copyAsValueParameter(descriptor, it.index) }
.take(createFunction.valueParameters.size - 1)
.map { it.copy(it.descriptor.copyAsValueParameter(descriptor, it.index)) }
descriptor.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ coroutineClassDescriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(),
/* unsubstitutedValueParameters = */ valueParameters,
/* unsubstitutedValueParameters = */ parameters.map { it.descriptor as ValueParameterDescriptor },
/* unsubstitutedReturnType = */ irFunction.descriptor.returnType,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE).apply {
@@ -639,21 +659,25 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
symbol = symbol).apply {
createParameterDeclarations()
returnType = irFunction.returnType
parent = coroutineClass
val thisReceiver = this.dispatchReceiverParameter!!.symbol
valueParameters += parameters
this.createDispatchReceiverParameter()
val thisReceiver = this.dispatchReceiverParameter!!
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn(
irCall(doResumeFunctionSymbol).apply {
dispatchReceiver = irCall(createFunctionSymbol).apply {
irCall(doResumeFunction).apply {
dispatchReceiver = irCall(createFunction).apply {
dispatchReceiver = irGet(thisReceiver)
valueParameters.forEachIndexed { index, parameter ->
putValueArgument(index, irGet(parameter.symbol))
putValueArgument(index, irGet(parameter))
}
putValueArgument(valueParameters.size,
irCall(getContinuationSymbol, listOf(symbol.descriptor.returnType!!)))
irCall(getContinuation, listOf(returnType)))
}
putValueArgument(0, irGetObject(symbols.unit)) // value
putValueArgument(1, irNull()) // exception
@@ -664,27 +688,23 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
}
}
private fun buildPropertyWithBackingField(name: Name, type: KotlinType, isMutable: Boolean): IrFieldSymbol {
val propertyBuilder = context.createPropertyWithBackingFieldBuilder(
startOffset = irFunction.startOffset,
endOffset = irFunction.endOffset,
origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
owner = coroutineClassDescriptor,
name = name,
type = type,
isMutable = isMutable).apply {
initialize()
}
coroutineClass.addChild(propertyBuilder.ir)
return propertyBuilder.symbol
private fun addField(name: Name, type: IrType, isMutable: Boolean): IrField = createField(
irFunction.startOffset,
irFunction.endOffset,
type,
name,
isMutable,
DECLARATION_ORIGIN_COROUTINE_IMPL,
coroutineClassDescriptor
).also {
coroutineClass.addChild(it)
}
private fun createDoResumeMethodBuilder(doResumeFunctionDescriptor: FunctionDescriptor)
private fun createDoResumeMethodBuilder(doResumeFunction: IrFunction, coroutineClass: IrClass)
= object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
doResumeFunctionDescriptor.createOverriddenDescriptor(coroutineClassDescriptor)
doResumeFunction.descriptor.createOverriddenDescriptor(coroutineClassDescriptor)
)
override fun doInitialize() { }
@@ -699,58 +719,76 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
symbol = symbol).apply {
createParameterDeclarations()
returnType = context.irBuiltIns.anyNType
parent = coroutineClass
this.createDispatchReceiverParameter()
doResumeFunction.valueParameters.mapIndexedTo(this.valueParameters) { index, it ->
it.copy(descriptor.valueParameters[index])
}
}
dataArgument = function.valueParameters[0].symbol
exceptionArgument = function.valueParameters[1].symbol
suspendResult = IrVariableSymbolImpl(
IrTemporaryVariableDescriptorImpl(
containingDeclaration = irFunction.descriptor,
name = "suspendResult".synthesizedName,
outType = context.builtIns.nullableAnyType,
isMutable = true)
)
val label = coroutineImplClassDescriptor.unsubstitutedMemberScope
.getContributedVariables(Name.identifier("label"), NoLookupLocation.FROM_BACKEND).single()
dataArgument = function.valueParameters[0]
exceptionArgument = function.valueParameters[1]
val label = coroutineImplSymbol.owner.declarations.filterIsInstance<IrProperty>()
.single { it.name.asString() == "label" }
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
function.body = irBuilder.irBlockBody(startOffset, endOffset) {
suspendResult = irVar(IrTemporaryVariableDescriptorImpl(
containingDeclaration = irFunction.descriptor,
name = "suspendResult".synthesizedName,
outType = context.builtIns.nullableAnyType,
isMutable = true)
, context.irBuiltIns.anyNType)
// Extract all suspend calls to temporaries in order to make correct jumps to them.
originalBody.transformChildrenVoid(ExpressionSlicer(label.type))
originalBody.transformChildrenVoid(ExpressionSlicer(label.getter!!.returnType))
val liveLocals = computeLivenessAtSuspensionPoints(originalBody)
val immutableLiveLocals = liveLocals.values.flatten().filterNot { it.descriptor.isVar }.toSet()
val localsMap = immutableLiveLocals.associate {
// TODO: Remove .descriptor as soon as all symbols are bound.
it.descriptor to IrVariableSymbolImpl(
val symbol = IrVariableSymbolImpl(
IrTemporaryVariableDescriptorImpl(
containingDeclaration = irFunction.descriptor,
name = it.descriptor.name,
outType = it.descriptor.type,
isMutable = true)
name = it.descriptor.name,
outType = it.descriptor.type,
isMutable = true)
)
val variable = IrVariableImpl(
startOffset = it.startOffset,
endOffset = it.endOffset,
origin = it.origin,
symbol = symbol,
type = it.type
)
it.descriptor to variable
}
if (localsMap.isNotEmpty())
transformVariables(originalBody, localsMap) // Make variables mutable in order to save/restore them.
val localToPropertyMap = mutableMapOf<IrVariableSymbol, IrFieldSymbol>()
val localToPropertyMap = mutableMapOf<IrVariableSymbol, IrField>()
// TODO: optimize by using the same property for different locals.
liveLocals.values.forEach { scope ->
scope.forEach {
localToPropertyMap.getOrPut(it) {
buildPropertyWithBackingField(it.descriptor.name, it.descriptor.type, true)
localToPropertyMap.getOrPut(it.symbol) {
addField(it.descriptor.name, it.type, true)
}
}
}
originalBody.transformChildrenVoid(object : IrElementTransformerVoid() {
private val thisReceiver = function.dispatchReceiverParameter!!.symbol
private val thisReceiver = function.dispatchReceiverParameter!!
// Replace returns to refer to the new function.
override fun visitReturn(expression: IrReturn): IrExpression {
@@ -783,23 +821,24 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
expression.transformChildrenVoid(this)
when (expression.symbol) {
saveStateSymbol -> {
saveState.symbol -> {
val scope = liveLocals[suspensionPoint]!!
return irBlock(expression) {
scope.forEach {
+irSetField(irGet(thisReceiver), localToPropertyMap[it]!!, irGet(localsMap[it.descriptor] ?: it))
val variable = localsMap[it.descriptor] ?: it
+irSetField(irGet(thisReceiver), localToPropertyMap[it.symbol]!!, irGet(variable))
}
+irCall(coroutineImplLabelSetterSymbol).apply {
dispatchReceiver = irGet(thisReceiver)
putValueArgument(0, irGet(suspensionPoint.suspensionPointIdParameter.symbol))
putValueArgument(0, irGet(suspensionPoint.suspensionPointIdParameter))
}
}
}
restoreStateSymbol -> {
restoreState.symbol -> {
val scope = liveLocals[suspensionPoint]!!
return irBlock(expression) {
scope.forEach {
+irSetVar(localsMap[it.descriptor] ?: it, irGetField(irGet(thisReceiver), localToPropertyMap[it]!!))
+irSetVar(localsMap[it.descriptor] ?: it, irGetField(irGet(thisReceiver), localToPropertyMap[it.symbol]!!))
}
}
}
@@ -812,26 +851,26 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
}
})
val statements = (originalBody as IrBlockBody).statements
+irVar(suspendResult, null)
+suspendResult
+IrSuspendableExpressionImpl(
startOffset = startOffset,
endOffset = endOffset,
type = context.builtIns.unitType,
type = context.irBuiltIns.unitType,
suspensionPointId = irCall(coroutineImplLabelGetterSymbol).apply {
dispatchReceiver = irGet(function.dispatchReceiverParameter!!.symbol)
dispatchReceiver = irGet(function.dispatchReceiverParameter!!)
},
result = irBlock(startOffset, endOffset) {
+irThrowIfNotNull(exceptionArgument) // Coroutine might start with an exception.
statements.forEach { +it }
})
if (irFunction.descriptor.returnType!!.isUnit())
if (irFunction.returnType.isUnit())
+irReturn(irGetObject(symbols.unit)) // Insert explicit return for Unit functions.
}
return function
}
}
private fun transformVariables(element: IrElement, variablesMap: Map<VariableDescriptor, IrVariableSymbol>) {
private fun transformVariables(element: IrElement, variablesMap: Map<VariableDescriptor, IrVariable>) {
element.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
@@ -843,7 +882,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
return IrGetValueImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
symbol = newVariable,
type = newVariable.type,
symbol = newVariable.symbol,
origin = expression.origin)
}
@@ -856,7 +896,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
return IrSetVariableImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
symbol = newVariable,
type = context.irBuiltIns.unitType,
symbol = newVariable.symbol,
value = expression.value,
origin = expression.origin)
}
@@ -867,21 +908,17 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val newVariable = variablesMap[declaration.symbol.descriptor]
?: return declaration
return IrVariableImpl(
startOffset = declaration.startOffset,
endOffset = declaration.endOffset,
origin = declaration.origin,
symbol = newVariable).apply {
initializer = declaration.initializer
}
newVariable.initializer = declaration.initializer
return newVariable
}
})
}
private fun computeLivenessAtSuspensionPoints(body: IrBody): Map<IrSuspensionPoint, List<IrVariableSymbol>> {
private fun computeLivenessAtSuspensionPoints(body: IrBody): Map<IrSuspensionPoint, List<IrVariable>> {
// TODO: data flow analysis.
// Just save all visible for now.
val result = mutableMapOf<IrSuspensionPoint, List<IrVariableSymbol>>()
val result = mutableMapOf<IrSuspensionPoint, List<IrVariable>>()
body.acceptChildrenVoid(object: VariablesScopeTracker() {
override fun visitExpression(expression: IrExpression) {
@@ -894,7 +931,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
suspensionPoint.result.acceptChildrenVoid(this)
suspensionPoint.resumeResult.acceptChildrenVoid(this)
val visibleVariables = mutableListOf<IrVariableSymbol>()
val visibleVariables = mutableListOf<IrVariable>()
scopeStack.forEach { visibleVariables += it }
result.put(suspensionPoint, visibleVariables)
}
@@ -904,7 +941,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
}
// These are marker descriptors to split up the lowering on two parts.
private val saveStateSymbol = IrSimpleFunctionSymbolImpl(
private val saveState = IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED,
SimpleFunctionDescriptorImpl.create(
irFunction.descriptor,
Annotations.EMPTY,
@@ -912,10 +949,11 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE).apply {
initialize(null, null, emptyList(), emptyList(), context.builtIns.unitType, Modality.ABSTRACT, Visibilities.PRIVATE)
}
)
}).apply {
returnType = context.irBuiltIns.unitType
}
private val restoreStateSymbol = IrSimpleFunctionSymbolImpl(
private val restoreState = IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, IrDeclarationOrigin.DEFINED,
SimpleFunctionDescriptorImpl.create(
irFunction.descriptor,
Annotations.EMPTY,
@@ -923,10 +961,11 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE).apply {
initialize(null, null, emptyList(), emptyList(), context.builtIns.unitType, Modality.ABSTRACT, Visibilities.PRIVATE)
}
)
}).apply {
returnType = context.irBuiltIns.unitType
}
private inner class ExpressionSlicer(val suspensionPointIdType: KotlinType): IrElementTransformerVoid() {
private inner class ExpressionSlicer(val suspensionPointIdType: IrType): IrElementTransformerVoid() {
// TODO: optimize - it has square complexity.
override fun visitSetField(expression: IrSetField): IrExpression {
@@ -983,13 +1022,9 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
newChildren[index] = transformedChild
else {
// Save to temporary in order to save execution order.
val tmp = IrVariableSymbolImpl(
IrTemporaryVariableDescriptorImpl(
containingDeclaration = irFunction.descriptor,
name = "tmp${tempIndex++}".synthesizedName,
outType = transformedChild.type)
)
tempStatements += irVar(tmp, transformedChild)
val tmp = irVar(transformedChild)
tempStatements += tmp
newChildren[index] = irGet(tmp)
}
}
@@ -1001,7 +1036,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
calledSaveState = true
val firstArgument = newChildren[2]!!
newChildren[2] = irBlock(firstArgument) {
+irCall(saveStateSymbol)
+irCall(saveState)
+firstArgument
}
suspendCall = newChildren[2]
@@ -1014,17 +1049,12 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
newChildren[numberOfChildren - 1] =
irBlock(lastChild) {
if (lastChild.isPure()) {
+irCall(saveStateSymbol)
+irCall(saveState)
+lastChild
} else {
val tmp = IrVariableSymbolImpl(
IrTemporaryVariableDescriptorImpl(
containingDeclaration = irFunction.descriptor,
name = "tmp${tempIndex++}".synthesizedName,
outType = lastChild.type)
)
+irVar(tmp, lastChild)
+irCall(saveStateSymbol)
val tmp = irVar(lastChild)
+tmp
+irCall(saveState)
+irGet(tmp)
}
}
@@ -1053,27 +1083,27 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val suspensionPointIdParameter = IrTemporaryVariableDescriptorImpl(
containingDeclaration = irFunction.descriptor,
name = "suspensionPointId${suspensionPointIdIndex++}".synthesizedName,
outType = suspensionPointIdType)
outType = suspensionPointIdType.toKotlinType())
val suspensionPoint = IrSuspensionPointImpl(
startOffset = startOffset,
endOffset = endOffset,
type = context.builtIns.nullableAnyType,
suspensionPointIdParameter = irVar(suspensionPointIdParameter, null),
type = context.irBuiltIns.anyNType,
suspensionPointIdParameter = irVar(suspensionPointIdParameter, suspensionPointIdType),
result = irBlock(startOffset, endOffset) {
if (!calledSaveState)
+irCall(saveStateSymbol)
+irSetVar(suspendResult, suspendCall)
+irCall(saveState)
+irSetVar(suspendResult.symbol, suspendCall)
+irReturnIfSuspended(suspendResult)
+irGet(suspendResult)
},
resumeResult = irBlock(startOffset, endOffset) {
+irCall(restoreStateSymbol)
+irCall(restoreState)
+irThrowIfNotNull(exceptionArgument)
+irGet(dataArgument)
})
val expressionResult = when {
suspendCall.type.isUnit() -> irImplicitCoercionToUnit(suspensionPoint)
else -> irCast(suspensionPoint, suspendCall.type, suspendCall.type)
else -> irAs(suspensionPoint, suspendCall.type)
}
return irBlock(expression) {
tempStatements.forEach { +it }
@@ -1132,27 +1162,31 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
get() = this is IrCall && this.descriptor.original == returnIfSuspendedDescriptor
}
private fun IrBuilderWithScope.irVar(initializer: IrExpression) =
irVar(
IrTemporaryVariableDescriptorImpl(
containingDeclaration = irFunction.descriptor,
name = "tmp${tempIndex++}".synthesizedName,
outType = initializer.type.toKotlinType()
),
initializer.type
).apply { this.initializer = initializer }
private fun IrBuilderWithScope.irVar(descriptor: VariableDescriptor, initializer: IrExpression?) =
IrVariableImpl(startOffset, endOffset, DECLARATION_ORIGIN_COROUTINE_IMPL, descriptor, initializer)
private fun IrBuilderWithScope.irVar(descriptor: VariableDescriptor, type: IrType) =
IrVariableImpl(startOffset, endOffset, DECLARATION_ORIGIN_COROUTINE_IMPL, descriptor, type)
private fun IrBuilderWithScope.irVar(symbol: IrVariableSymbol, initializer: IrExpression?) =
IrVariableImpl(startOffset, endOffset, DECLARATION_ORIGIN_COROUTINE_IMPL, symbol).apply {
this.initializer = initializer
}
private fun IrBuilderWithScope.irReturnIfSuspended(value: IrValueSymbol) =
private fun IrBuilderWithScope.irReturnIfSuspended(value: IrValueDeclaration) =
irIfThen(irEqeqeq(irGet(value), irCall(symbols.coroutineSuspendedGetter)),
irReturn(irGet(value)))
private fun IrBuilderWithScope.irThrowIfNotNull(exception: IrValueSymbol) =
private fun IrBuilderWithScope.irThrowIfNotNull(exception: IrValueDeclaration) =
irIfThen(irNot(irEqeqeq(irGet(exception), irNull())),
irThrow(irImplicitCast(irGet(exception), exception.descriptor.type.makeNotNullable())))
irThrow(irImplicitCast(irGet(exception), exception.type.makeNotNull())))
}
private open class VariablesScopeTracker: IrElementVisitorVoid {
protected val scopeStack = mutableListOf<MutableSet<IrVariableSymbol>>(mutableSetOf())
protected val scopeStack = mutableListOf<MutableSet<IrVariable>>(mutableSetOf())
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
@@ -1174,7 +1208,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
override fun visitVariable(declaration: IrVariable) {
super.visitVariable(declaration)
scopeStack.peek()!!.add(declaration.symbol)
scopeStack.peek()!!.add(declaration)
}
}
}
@@ -25,6 +25,8 @@ import org.jetbrains.kotlin.backend.common.reportWarning
import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWithStarProjections
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWithoutArguments
import org.jetbrains.kotlin.backend.konan.reportCompilationError
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.isFunctionType
@@ -38,15 +40,14 @@ import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -98,50 +99,50 @@ internal class TestProcessor (val context: KonanBackendContext) {
add(TestFunction(function, kind))
private fun <T: IrElement> IrStatementsBuilder<T>.generateFunctionRegistration(
receiver: IrValueSymbol,
receiver: IrValueDeclaration,
registerTestCase: IrFunctionSymbol,
registerFunction: IrFunctionSymbol,
functions: Collection<TestFunction>) {
functions.forEach {
if (it.kind == FunctionKind.TEST) {
// Call registerTestCase(name: String, testFunction: () -> Unit) method.
+irCall(registerTestCase).apply {
+irCall(registerTestCase, registerTestCase.descriptor.returnType!!.toErasedIrType()).apply {
dispatchReceiver = irGet(receiver)
putValueArgument(0, IrConstImpl.string(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
context.builtIns.stringType,
context.irBuiltIns.stringType,
it.function.descriptor.name.identifier)
)
putValueArgument(1, IrFunctionReferenceImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
descriptor.valueParameters[1].type,
descriptor.valueParameters[1].type.toErasedIrType(),
it.function,
it.function.descriptor, emptyMap()))
it.function.descriptor, 0))
putValueArgument(2, IrConstImpl.boolean(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
context.builtIns.booleanType,
context.irBuiltIns.booleanType,
it.ignored
))
}
} else {
// Call registerFunction(kind: TestFunctionKind, () -> Unit) method.
+irCall(registerFunction).apply {
+irCall(registerFunction, registerFunction.descriptor.returnType!!.toErasedIrType()).apply {
dispatchReceiver = irGet(receiver)
val testKindEntry = it.kind.runtimeKind
putValueArgument(0, IrGetEnumValueImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
testKindEntry.descriptor.defaultType,
symbols.testFunctionKind.typeWithoutArguments,
testKindEntry)
)
putValueArgument(1, IrFunctionReferenceImpl(UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
descriptor.valueParameters[1].type,
descriptor.valueParameters[1].type.toErasedIrType(),
it.function,
it.function.descriptor, emptyMap()))
it.function.descriptor, 0))
}
}
}
@@ -282,7 +283,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
//region Symbol and IR builders
/** Base class for getters (createInstance and getCompanion). */
private abstract inner class GetterBuilder(val returnType: KotlinType,
private abstract inner class GetterBuilder(val returnType: IrType,
val testSuite: IrClassSymbol,
val getterName: Name)
: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrFunction>() {
@@ -300,7 +301,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
/* dispatchReceiverParameter = */ testSuite.descriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(),
/* unsubstitutedValueParameters = */ emptyList(),
/* returnType = */ returnType,
/* returnType = */ returnType.toKotlinType(),
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PROTECTED
).apply {
@@ -324,18 +325,21 @@ internal class TestProcessor (val context: KonanBackendContext) {
* returning a reference to an object represented by `[objectSymbol]`.
*/
private inner class ObjectGetterBuilder(val objectSymbol: IrClassSymbol, testSuite: IrClassSymbol, getterName: Name)
: GetterBuilder(objectSymbol.descriptor.defaultType, testSuite, getterName) {
: GetterBuilder(objectSymbol.typeWithoutArguments, testSuite, getterName) {
override fun buildIr(): IrFunction = IrFunctionImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
TEST_SUITE_GENERATED_MEMBER,
symbol).apply {
this.returnType = this@ObjectGetterBuilder.returnType
val builder = context.createIrBuilder(symbol)
createParameterDeclarations()
createParameterDeclarations(context.ir.symbols.symbolTable)
body = builder.irBlockBody {
+irReturn(IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
objectSymbol.descriptor.defaultType, objectSymbol)
objectSymbol.typeWithoutArguments, objectSymbol)
)
}
}
@@ -346,17 +350,20 @@ internal class TestProcessor (val context: KonanBackendContext) {
* returning a new instance of class referenced by [classSymbol].
*/
private inner class InstanceGetterBuilder(val classSymbol: IrClassSymbol, testSuite: IrClassSymbol, getterName: Name)
: GetterBuilder(classSymbol.descriptor.defaultType, testSuite, getterName) {
: GetterBuilder(classSymbol.typeWithStarProjections, testSuite, getterName) {
override fun buildIr() = IrFunctionImpl(
startOffset = UNDEFINED_OFFSET,
endOffset = UNDEFINED_OFFSET,
origin = TEST_SUITE_GENERATED_MEMBER,
symbol = symbol).apply {
this.returnType = this@InstanceGetterBuilder.returnType
val builder = context.createIrBuilder(symbol)
createParameterDeclarations()
createParameterDeclarations(context.ir.symbols.symbolTable)
body = builder.irBlockBody {
val constructor = classSymbol.constructors.single { it.descriptor.valueParameters.isEmpty() }
val constructor = classSymbol.owner.constructors.single { it.valueParameters.isEmpty() }
+irReturn(irCall(constructor))
}
}
@@ -385,15 +392,18 @@ internal class TestProcessor (val context: KonanBackendContext) {
UNDEFINED_OFFSET,
TEST_SUITE_GENERATED_MEMBER,
symbol).apply {
createParameterDeclarations()
val registerTestCase = testSuite.getFunction("registerTestCase") {
returnType = testSuite.typeWithStarProjections
createParameterDeclarations(context.ir.symbols.symbolTable)
val registerTestCase = symbols.baseClassSuite.getFunction("registerTestCase") {
it.valueParameters.size == 3 &&
KotlinBuiltIns.isString(it.valueParameters[0].type) && // name: String
it.valueParameters[1].type.isFunctionType && // function: testClassType.() -> Unit
KotlinBuiltIns.isBoolean(it.valueParameters[2].type) // ignored: Boolean
}
val registerFunction = testSuite.getFunction("registerFunction") {
val registerFunction = symbols.baseClassSuite.getFunction("registerFunction") {
it.valueParameters.size == 2 &&
it.valueParameters[0].type == symbols.testFunctionKind.descriptor.defaultType && // kind: TestFunctionKind
it.valueParameters[1].type.isFunctionType // function: () -> Unit
@@ -404,26 +414,28 @@ internal class TestProcessor (val context: KonanBackendContext) {
+IrDelegatingConstructorCallImpl(
startOffset = UNDEFINED_OFFSET,
endOffset = UNDEFINED_OFFSET,
type = context.irBuiltIns.unitType,
symbol = symbols.symbolTable.referenceConstructor(superConstructor),
descriptor = superConstructor,
typeArgumentsCount = 2
).apply {
copyTypeArgumentsFrom(mapOf(superConstructor.typeParameters[0] to testClassType,
superConstructor.typeParameters[1] to testCompanionType))
putTypeArgument(0, testClassType.toErasedIrType())
putTypeArgument(1, testCompanionType.toErasedIrType())
putValueArgument(0, IrConstImpl.string(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
context.builtIns.stringType,
context.irBuiltIns.stringType,
suiteName)
)
putValueArgument(1, IrConstImpl.boolean(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
context.builtIns.booleanType,
context.irBuiltIns.booleanType,
ignored
))
}
generateFunctionRegistration(testSuite.owner.thisReceiver!!.symbol,
generateFunctionRegistration(testSuite.owner.thisReceiver!!,
registerTestCase, registerFunction, functions)
}
}
@@ -445,6 +457,8 @@ internal class TestProcessor (val context: KonanBackendContext) {
)
}
private fun KotlinType.toErasedIrType(): IrType = context.ir.translateErased(this)
/**
* Builds a test suite class representing a test class (any class in the original IrFile with method(s)
* annotated with @Test). The test suite class is a subclass of ClassTestSuite<T> where T is the test class.
@@ -489,17 +503,17 @@ internal class TestProcessor (val context: KonanBackendContext) {
}
}
override fun buildIr() = IrClassImpl(
override fun buildIr() = symbols.symbolTable.declareClass(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
TEST_SUITE_CLASS,
symbol).apply {
symbol.descriptor).apply {
createParameterDeclarations()
addMember(constructorBuilder.ir)
addMember(instanceGetterBuilder.ir)
companionGetterBuilder?.let { addMember(it.ir) }
addFakeOverrides()
setSuperSymbols(context.ir.symbols.symbolTable)
addFakeOverrides(symbols.symbolTable)
setSuperSymbols(symbols.symbolTable)
}
override fun doInitialize() {
@@ -526,7 +540,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
companionGetterBuilder?.initialize()
}
override fun buildSymbol() = IrClassSymbolImpl(
override fun buildSymbol() = symbols.symbolTable.referenceClass(
ClassDescriptorImpl(
/* containingDeclaration = */ containingDeclaration,
/* name = */ suiteClassName,
@@ -549,8 +563,9 @@ internal class TestProcessor (val context: KonanBackendContext) {
testClass.functions)) {
initialize()
irFile.addChild(ir)
val irConstructor = ir.constructors.single()
irFile.addTopLevelInitializer(
IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, ir.symbol.constructors.single())
IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irConstructor.returnType, irConstructor.symbol)
)
}
@@ -575,10 +590,10 @@ internal class TestProcessor (val context: KonanBackendContext) {
irFile.addTopLevelInitializer(builder.irBlock {
val constructorCall = irCall(symbols.topLevelSuiteConstructor).apply {
putValueArgument(0, IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
context.builtIns.stringType, suiteName))
context.irBuiltIns.stringType, suiteName))
}
val testSuiteVal = irTemporary(constructorCall, "topLevelTestSuite")
generateFunctionRegistration(testSuiteVal.symbol,
generateFunctionRegistration(testSuiteVal,
symbols.topLevelSuiteRegisterTestCase,
symbols.topLevelSuiteRegisterFunction,
functions)
@@ -21,22 +21,27 @@ import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
import org.jetbrains.kotlin.backend.common.lower.at
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark
import org.jetbrains.kotlin.backend.konan.irasdescriptors.containsNull
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isSubtypeOf
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.makeNotNull
import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.makeNullable
/**
* This lowering pass lowers some [IrTypeOperatorCall]s.
@@ -60,22 +65,24 @@ private class TypeOperatorTransformer(val context: CommonBackendContext, val fun
return declaration
}
private fun KotlinType.erasure(): KotlinType {
val descriptor = this.constructor.declarationDescriptor
return when (descriptor) {
is ClassDescriptor -> this
is TypeParameterDescriptor -> {
val upperBound = descriptor.upperBounds.singleOrNull() ?:
TODO("$descriptor : ${descriptor.upperBounds}")
private fun IrType.erasure(): IrType {
if (this !is IrSimpleType) return this
if (this.isMarkedNullable) {
val classifier = this.classifier
return when (classifier) {
is IrClassSymbol -> this
is IrTypeParameterSymbol -> {
val upperBound = classifier.owner.superTypes.singleOrNull() ?:
TODO("${classifier.descriptor} : ${classifier.descriptor.upperBounds}")
if (this.hasQuestionMark) {
// `T?`
upperBound.erasure().makeNullable()
} else {
upperBound.erasure()
}
}
else -> TODO(this.toString())
else -> TODO(classifier.toString())
}
}
@@ -83,32 +90,32 @@ private class TypeOperatorTransformer(val context: CommonBackendContext, val fun
builder.at(expression)
val typeOperand = expression.typeOperand.erasure()
assert (!TypeUtils.hasNullableSuperType(typeOperand)) // So that `isNullable()` <=> `isMarkedNullable`.
// assert (!TypeUtils.hasNullableSuperType(typeOperand)) // So that `isNullable()` <=> `isMarkedNullable`.
// TODO: consider the case when expression type is wrong e.g. due to generics-related unchecked casts.
return when {
expression.argument.type.isSubtypeOf(typeOperand) -> expression.argument
expression.argument.type.isNullable() -> {
expression.argument.type.containsNull() -> {
with (builder) {
irLetS(expression.argument) { argument ->
irIfThenElse(
type = expression.type,
condition = irEqeqeq(irGet(argument), irNull()),
condition = irEqeqeq(irGet(argument.owner), irNull()),
thenPart = if (typeOperand.isMarkedNullable)
thenPart = if (typeOperand.isSimpleTypeWithQuestionMark)
irNull()
else
irCall(throwTypeCastException),
irCall(throwTypeCastException.owner),
elsePart = irAs(irGet(argument), typeOperand.makeNotNullable())
elsePart = irAs(irGet(argument.owner), typeOperand.makeNotNull())
)
}
}
}
typeOperand.isMarkedNullable -> builder.irAs(expression.argument, typeOperand.makeNotNullable())
typeOperand.isSimpleTypeWithQuestionMark -> builder.irAs(expression.argument, typeOperand.makeNotNull())
typeOperand == expression.typeOperand -> expression
@@ -124,8 +131,8 @@ private class TypeOperatorTransformer(val context: CommonBackendContext, val fun
return builder.irBlock(expression) {
+irLetS(expression.argument) { variable ->
irIfThenElse(expression.type,
condition = irIs(irGet(variable), typeOperand),
thenPart = irImplicitCast(irGet(variable), typeOperand),
condition = irIs(irGet(variable.owner), typeOperand),
thenPart = irImplicitCast(irGet(variable.owner), typeOperand),
elsePart = irNull())
}
}
@@ -35,24 +35,23 @@ import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.backend.konan.llvm.localHash
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.utils.constructedClass
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.simpleFunctions
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlin.util.OperatorNameConventions
private fun getClassWithBoxingIncluded(type: KotlinType, ir: KonanIr): ClassDescriptor? {
private fun getClassWithBoxingIncluded(type: IrType, ir: KonanIr): ClassDescriptor? {
/*
* Some primitive types can be null and some can't. Those that can't must be replaced with the corresponding box.
* Int -> Int
@@ -61,29 +60,29 @@ private fun getClassWithBoxingIncluded(type: KotlinType, ir: KonanIr): ClassDesc
* CPointer -> CPointer
* CPointer? -> CPointer
*/
return if (type.correspondingValueType == null && type.makeNotNullable().correspondingValueType != null)
ir.getClass(ir.symbols.getTypeConversion(type.makeNotNullable(), type)!!.descriptor.returnType!!)!!
return if (type.correspondingValueType == null && type.makeNotNull().correspondingValueType != null)
ir.symbols.getTypeConversion(type.makeNotNull(), type)!!.owner.returnType.getClass()!!
else
ir.getClass(type)
type.getClass()
}
private fun computeErasure(type: KotlinType, ir: KonanIr, erasure: MutableList<ClassDescriptor>) {
private fun computeErasure(type: IrType, ir: KonanIr, erasure: MutableList<ClassDescriptor>) {
val irClass = getClassWithBoxingIncluded(type, ir)
if (irClass != null) {
erasure += irClass
} else {
val descriptor = type.constructor.declarationDescriptor
if (descriptor is TypeParameterDescriptor) {
descriptor.upperBounds.forEach {
val classifier = type.classifierOrFail
if (classifier is IrTypeParameterSymbol) {
classifier.owner.superTypes.forEach {
computeErasure(it, ir, erasure)
}
} else {
TODO(descriptor.toString())
TODO(classifier.descriptor.toString())
}
}
}
internal fun KotlinType.erasure(context: Context): List<ClassDescriptor> {
internal fun IrType.erasure(context: Context): List<ClassDescriptor> {
val result = mutableListOf<ClassDescriptor>()
computeErasure(this, context.ir, result)
return result
@@ -163,7 +162,7 @@ private class ExpressionValuesExtractor(val context: Context,
forEachValue(
expression = (expression.statements.last() as? IrExpression)
?: IrGetObjectValueImpl(expression.startOffset, expression.endOffset,
context.builtIns.unitType, context.ir.symbols.unit),
context.irBuiltIns.unitType, context.ir.symbols.unit),
block = block
)
}
@@ -187,7 +186,8 @@ private class ExpressionValuesExtractor(val context: Context,
else { // Propagate cast to sub-values.
forEachValue(expression.argument) { value ->
with(expression) {
block(IrTypeOperatorCallImpl(startOffset, endOffset, type, operator, typeOperand, value))
block(IrTypeOperatorCallImpl(startOffset, endOffset, type, operator, typeOperand,
typeOperand.classifierOrFail, value))
}
}
}
@@ -254,7 +254,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
override fun visitConstructor(declaration: IrConstructor) {
val body = declaration.body
assert (body != null || declaration.symbol.constructedClass.kind == ClassKind.ANNOTATION_CLASS) {
assert (body != null || declaration.constructedClass.kind == ClassKind.ANNOTATION_CLASS) {
"Non-annotation class constructor has empty body"
}
DEBUG_OUTPUT(0) {
@@ -280,7 +280,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
println("Analysing global field ${declaration.descriptor}")
println("IR: ${ir2stringWhole(declaration)}")
}
analyze(declaration, IrSetFieldImpl(it.startOffset, it.endOffset, declaration.symbol, null, it.expression))
analyze(declaration, IrSetFieldImpl(it.startOffset, it.endOffset, declaration.symbol, null,
it.expression, context.irBuiltIns.unitType))
}
}
@@ -379,11 +380,13 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
if (expression is IrCall && expression.symbol == scheduleImplSymbol) {
// Producer and job of scheduleImpl are called externally, we need to reflect this somehow.
val producerInvocation = IrCallImpl(expression.startOffset, expression.endOffset,
scheduleImplProducerInvoke.returnType,
scheduleImplProducerInvoke.symbol, scheduleImplProducerInvoke.descriptor)
producerInvocation.dispatchReceiver = expression.getValueArgument(2)
val jobFunctionReference = expression.getValueArgument(3) as? IrFunctionReference
?: error("A function reference expected")
val jobInvocation = IrCallImpl(expression.startOffset, expression.endOffset,
jobFunctionReference.symbol.owner.returnType,
jobFunctionReference.symbol, jobFunctionReference.descriptor)
jobInvocation.putValueArgument(0, producerInvocation)
@@ -447,6 +450,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
.filterIsInstance<IrSimpleFunction>().single { it.name.asString() == "doResume" }.symbol
private val getContinuationSymbol = context.ir.symbols.getContinuation
private val continuationType = getContinuationSymbol.owner.returnType
private val arrayGetSymbol = context.ir.symbols.arrayGet
private val arraySetSymbol = context.ir.symbols.arraySet
@@ -631,21 +635,27 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
val owner = callee.containingDeclaration as ClassDescriptor
val actualReceiverType = value.dispatchReceiver!!.type
val receiverType =
if (actualReceiverType.constructor.declarationDescriptor is TypeParameterDescriptor
if (actualReceiverType.classifierOrNull is IrTypeParameterSymbol
|| !callee.isReal /* Could be a bridge. */)
symbolTable.mapClass(owner)
else {
val actualClassAtCallsite = actualReceiverType.constructor.declarationDescriptor as org.jetbrains.kotlin.descriptors.ClassDescriptor
assert (DescriptorUtils.isSubclass(actualClassAtCallsite, owner.descriptor)) {
"Expected an inheritor of ${owner.descriptor}, but was $actualClassAtCallsite"
val actualClassAtCallsite =
actualReceiverType.classifierOrFail.descriptor
as org.jetbrains.kotlin.descriptors.ClassDescriptor
// assert (DescriptorUtils.isSubclass(actualClassAtCallsite, owner.descriptor)) {
// "Expected an inheritor of ${owner.descriptor}, but was $actualClassAtCallsite"
// }
if (DescriptorUtils.isSubclass(actualClassAtCallsite, owner.descriptor)) {
symbolTable.mapType(
actualReceiverType.let {
if (it.isValueType()) // A virtual call on a value type - it must be boxed.
context.ir.symbols.getTypeConversion(it, it.makeNullable())!!.owner.returnType
else it
}
)
} else {
symbolTable.mapClass(owner)
}
symbolTable.mapType(
actualReceiverType.let {
if (it.isValueType()) // A virtual call on a value type - it must be boxed.
context.ir.symbols.getTypeConversion(it, it.makeNullable())!!.descriptor.returnType!!
else it
}
)
}
if (owner.isInterface) {
val calleeHash = callee.functionName.localHash.value
@@ -681,8 +691,9 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
}
is IrDelegatingConstructorCall -> {
val thiz = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
(descriptor as ConstructorDescriptor).constructedClass.thisReceiver!!.symbol)
val thisReceiver = (descriptor as ConstructorDescriptor).constructedClass.thisReceiver!!
val thiz = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, thisReceiver.type,
thisReceiver.symbol)
val arguments = listOf(thiz) + value.getArguments().map { it.second }
DataFlowIR.Node.StaticCall(
symbolTable.mapFunction(value.symbol.owner),
@@ -35,6 +35,10 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrGetField
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isNothing
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
@@ -42,10 +46,6 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.IntValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit
internal object DataFlowIR {
@@ -468,7 +468,7 @@ internal object DataFlowIR {
private val pointsToOnWhomDescriptor = pointsToAnnotationDescriptor.unsubstitutedPrimaryConstructor!!.valueParameters.single()
private val getContinuationSymbol = context.ir.symbols.getContinuation
private val continuationType = getContinuationSymbol.descriptor.returnType!!
private val continuationType = getContinuationSymbol.owner.returnType
var privateTypeIndex = 0
var privateFunIndex = 0
@@ -524,7 +524,7 @@ internal object DataFlowIR {
classMap[descriptor] = type
type.superTypes += descriptor.defaultType.immediateSupertypes().map { mapType(it) }
type.superTypes += descriptor.superTypes.map { mapType(it) }
if (!isAbstract) {
val vtableBuilder = context.getVtableBuilder(descriptor)
type.vtable += vtableBuilder.vtableEntries.map { mapFunction(it.getImplementation(context)!!) }
@@ -541,7 +541,7 @@ internal object DataFlowIR {
return erasure.singleOrNull { !it.isInterface } ?: context.ir.symbols.any.owner
}
fun mapType(type: KotlinType) = mapClass(choosePrimary(type.erasure(context)))
fun mapType(type: IrType) = mapClass(choosePrimary(type.erasure(context)))
// TODO: use from LlvmDeclarations.
private fun getFqName(descriptor: DeclarationDescriptor): FqName =
@@ -605,7 +605,7 @@ internal object DataFlowIR {
.map { mapClass(choosePrimary(it.erasure(context))) }
.toTypedArray()
symbol.returnType = mapType(if (descriptor.isSuspend)
context.builtIns.anyType
context.irBuiltIns.anyType
else
descriptor.returnType)
@@ -27,8 +27,7 @@ import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.ir.IrPrivateClassReferenceImpl
import org.jetbrains.kotlin.backend.konan.ir.IrPrivateFunctionCallImpl
import org.jetbrains.kotlin.backend.konan.lower.nullConst
import org.jetbrains.kotlin.backend.konan.objcexport.getErasedTypeClass
import org.jetbrains.kotlin.backend.konan.irasdescriptors.getErasedTypeClass
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement
@@ -40,14 +39,14 @@ import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.getValueArgument
import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrWhenImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.util.addArguments
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.util.explicitParameters
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
import kotlin.collections.ArrayList
@@ -1009,7 +1008,7 @@ internal object Devirtualization {
class PossiblyCoercedValue(val value: IrVariable, val coercion: IrFunctionSymbol?) {
fun getFullValue(irBuilder: IrBuilderWithScope) = irBuilder.run {
irCoerce(irGet(value.symbol), coercion)
irCoerce(irGet(value), coercion)
}
}
@@ -1020,7 +1019,7 @@ internal object Devirtualization {
val coercion = expression as IrCall
PossiblyCoercedValue(
irTemporary(irImplicitCast(coercion.getArguments().single().second,
coercion.descriptor.explicitParameters.single().type))
coercion.symbol.owner.explicitParameters.single().type))
, coercion.symbol)
}
@@ -1041,12 +1040,12 @@ internal object Devirtualization {
val coercion = context.ir.symbols.getTypeConversion(type.correspondingValueType, targetType.correspondingValueType)
?: return possiblyCoercedValue.getFullValue(this)
if (prevCoercion == null)
return irCoerce(irGet(value.symbol), coercion)
return irCoerce(irGet(value), coercion)
assertCoercionsMatch(coercion, prevCoercion)
return irGet(value.symbol)
return irGet(value)
}
fun IrBuilderWithScope.irDevirtualizedCall(callee: IrCall, actualType: KotlinType,
fun IrBuilderWithScope.irDevirtualizedCall(callee: IrCall, actualType: IrType,
devirtualizedCallee: DataFlowIR.FunctionSymbol.Declared) =
IrPrivateFunctionCallImpl(
startOffset = startOffset,
@@ -1062,7 +1061,7 @@ internal object Devirtualization {
virtualCallee = callee
)
fun IrBuilderWithScope.irDevirtualizedCall(callee: IrCall, actualType: KotlinType,
fun IrBuilderWithScope.irDevirtualizedCall(callee: IrCall, actualType: IrType,
actualCallee: DataFlowIR.FunctionSymbol.Declared,
receiver: IrVariable,
extensionReceiver: PossiblyCoercedValue?,
@@ -1070,7 +1069,7 @@ internal object Devirtualization {
actualCallee.bridgeTarget.let {
if (it == null)
irDevirtualizedCall(callee, actualType, actualCallee).apply {
this.dispatchReceiver = irGet(receiver.symbol)
this.dispatchReceiver = irGet(receiver)
this.extensionReceiver = extensionReceiver?.getFullValue(this@irDevirtualizedCall)
callee.descriptor.valueParameters.forEach {
putValueArgument(it.index, parameters[it]!!.getFullValue(this@irDevirtualizedCall))
@@ -1079,7 +1078,7 @@ internal object Devirtualization {
else {
val bridgeTarget = it.resolved() as DataFlowIR.FunctionSymbol.Declared
val callResult = irDevirtualizedCall(callee, actualType, bridgeTarget).apply {
this.dispatchReceiver = irGet(receiver.symbol)
this.dispatchReceiver = irGet(receiver)
this.extensionReceiver = extensionReceiver?.let {
irCoerceIfNeeded(
type = actualCallee.parameterTypes[1].resolved(),
@@ -1140,21 +1139,22 @@ internal object Devirtualization {
val startOffset = expression.startOffset
val endOffset = expression.endOffset
val type = if (descriptor.isSuspend)
context.builtIns.nullableAnyType
else descriptor.original.returnType!!
context.irBuiltIns.anyNType
else expression.symbol.owner.returnType
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, startOffset, endOffset)
irBuilder.run {
val dispatchReceiver = expression.dispatchReceiver!!
return when {
possibleCallees.isEmpty() -> irBlock(expression) {
+irCall(context.ir.symbols.throwInvalidReceiverTypeException).apply {
putValueArgument(0, irCall(context.ir.symbols.kClassImplConstructor, listOf(dispatchReceiver.type)).apply {
putValueArgument(0, irCall(context.ir.symbols.getObjectTypeInfo).apply {
val throwExpr = irCall(context.ir.symbols.throwInvalidReceiverTypeException.owner).apply {
putValueArgument(0, irCall(context.ir.symbols.kClassImplConstructor.owner, listOf(dispatchReceiver.type)).apply {
putValueArgument(0, irCall(context.ir.symbols.getObjectTypeInfo.owner).apply {
putValueArgument(0, dispatchReceiver)
})
})
}
+nullConst(expression, type)
// Insert proper unboxing (unreachable code):
+irCoerce(throwExpr, context.ir.symbols.getTypeConversion(throwExpr.type, type))
}
optimize && possibleCallees.size == 1 -> { // Monomorphic callsite.
@@ -1176,7 +1176,7 @@ internal object Devirtualization {
it to irSplitCoercion(expression.getValueArgument(it)!!)
}
val typeInfo = irTemporary(irCall(context.ir.symbols.getObjectTypeInfo).apply {
putValueArgument(0, irGet(receiver.symbol))
putValueArgument(0, irGet(receiver))
})
val branches = mutableListOf<IrBranchImpl>()
@@ -1186,8 +1186,8 @@ internal object Devirtualization {
val expectedTypeInfo = IrPrivateClassReferenceImpl(
startOffset = startOffset,
endOffset = endOffset,
type = nativePtrType,
symbol = IrClassSymbolImpl(dispatchReceiver.type.getErasedTypeClass()),
type = context.ir.symbols.nativePtrType,
symbol = dispatchReceiver.type.getErasedTypeClass(),
classType = receiver.type,
moduleDescriptor = actualReceiverType.module!!.descriptor,
totalClasses = actualReceiverType.module.numberOfClasses,
@@ -1198,7 +1198,7 @@ internal object Devirtualization {
irTrue() // Don't check last type in optimize mode.
else
irCall(nativePtrEqualityOperatorSymbol).apply {
putValueArgument(0, irGet(typeInfo.symbol))
putValueArgument(0, irGet(typeInfo))
putValueArgument(1, expectedTypeInfo)
}
IrBranchImpl(
@@ -1218,7 +1218,7 @@ internal object Devirtualization {
irCall(context.ir.symbols.kClassImplConstructor,
listOf(dispatchReceiver.type)
).apply {
putValueArgument(0, irGet(typeInfo.symbol))
putValueArgument(0, irGet(typeInfo))
}
)
})
@@ -37,10 +37,10 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.util.addFakeOverrides
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.setOverrides
import org.jetbrains.kotlin.ir.util.setSuperSymbols
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.serialization.KonanDescriptorSerializer
import org.jetbrains.kotlin.metadata.KonanIr
import org.jetbrains.kotlin.metadata.KonanIr.IrConst.ValueCase.*
@@ -82,6 +82,8 @@ internal class IrSerializer(val context: Context,
return irDescriptorSerializer.serializeKotlinType(type)
}
private fun serializeKotlinType(type: IrType) = serializeKotlinType(type.toKotlinType())
private fun serializeDescriptor(descriptor: DeclarationDescriptor): KonanIr.KotlinDescriptor {
context.log{"### serializeDescriptor $descriptor"}
@@ -719,12 +721,12 @@ internal class IrDeserializer(val context: Context,
private fun deserializeDescriptor(proto: KonanIr.KotlinDescriptor)
= descriptorDeserializer.deserializeDescriptor(proto)
private fun deserializeTypeArguments(proto: KonanIr.TypeArguments): List<KotlinType> {
private fun deserializeTypeArguments(proto: KonanIr.TypeArguments): List<IrType> {
context.log{"### deserializeTypeArguments"}
val result = mutableListOf<KotlinType>()
val result = mutableListOf<IrType>()
proto.typeArgumentList.forEach { type ->
val kotlinType = deserializeKotlinType(type)
result.add(kotlinType)
result.add(kotlinType.brokenIr)
context.log{"$kotlinType"}
}
return result
@@ -782,6 +784,9 @@ internal class IrDeserializer(val context: Context,
return element
}
private val KotlinType.ir: IrType get() = context.ir.translateErased(this)
private val KotlinType.brokenIr: IrType get() = context.ir.translateBroken(this)
private fun deserializeBlock(proto: KonanIr.IrBlock, start: Int, end: Int, type: KotlinType): IrBlock {
val statements = mutableListOf<IrStatement>()
val statementProtos = proto.statementList
@@ -791,7 +796,7 @@ internal class IrDeserializer(val context: Context,
val isLambdaOrigin = if (proto.isLambdaOrigin) IrStatementOrigin.LAMBDA else null
return IrBlockImpl(start, end, type, isLambdaOrigin, statements)
return IrBlockImpl(start, end, type.ir, isLambdaOrigin, statements)
}
private fun deserializeMemberAccessCommon(access: IrMemberAccessExpression, proto: KonanIr.MemberAccessCommon) {
@@ -819,7 +824,7 @@ internal class IrDeserializer(val context: Context,
val descriptor = deserializeDescriptor(proto.classDescriptor) as ClassifierDescriptor
/** TODO: [createClassifierSymbolForClassReference] is internal function */
@Suppress("DEPRECATION")
return IrClassReferenceImpl(start, end, type, descriptor, descriptor.defaultType)
return IrClassReferenceImpl(start, end, type.ir, descriptor, descriptor.defaultType.ir)
}
private fun deserializeCall(proto: KonanIr.IrCall, start: Int, end: Int, type: KotlinType): IrCall {
@@ -832,13 +837,13 @@ internal class IrDeserializer(val context: Context,
val call: IrCall = when (proto.kind) {
KonanIr.IrCall.Primitive.NOT_PRIMITIVE ->
// TODO: implement the last three args here.
IrCallImpl(start, end, type, createFunctionSymbol(descriptor), descriptor, proto.memberAccess.typeArguments.typeArgumentCount, null, createClassSymbolOrNull(superDescriptor))
IrCallImpl(start, end, type.ir, createFunctionSymbol(descriptor), descriptor, proto.memberAccess.typeArguments.typeArgumentCount, null, createClassSymbolOrNull(superDescriptor))
KonanIr.IrCall.Primitive.NULLARY ->
IrNullaryPrimitiveImpl(start, end, null, createFunctionSymbol(descriptor))
IrNullaryPrimitiveImpl(start, end, type.ir, null, createFunctionSymbol(descriptor))
KonanIr.IrCall.Primitive.UNARY ->
IrUnaryPrimitiveImpl(start, end, null, createFunctionSymbol(descriptor))
IrUnaryPrimitiveImpl(start, end, type.ir, null, createFunctionSymbol(descriptor))
KonanIr.IrCall.Primitive.BINARY ->
IrBinaryPrimitiveImpl(start, end, null, createFunctionSymbol(descriptor))
IrBinaryPrimitiveImpl(start, end, type.ir, null, createFunctionSymbol(descriptor))
else -> TODO("Unexpected primitive IrCall.")
}
deserializeMemberAccessCommon(call, proto.memberAccess)
@@ -850,7 +855,7 @@ internal class IrDeserializer(val context: Context,
val descriptor = deserializeDescriptor(proto.descriptor) as CallableDescriptor
val callable = when (descriptor) {
is FunctionDescriptor -> IrFunctionReferenceImpl(start, end, type, createFunctionSymbol(descriptor), descriptor, proto.typeArguments.typeArgumentCount, null)
is FunctionDescriptor -> IrFunctionReferenceImpl(start, end, type.ir, createFunctionSymbol(descriptor), descriptor, proto.typeArguments.typeArgumentCount, null)
else -> TODO()
}
@@ -866,12 +871,12 @@ internal class IrDeserializer(val context: Context,
statementProtos.forEach {
statements.add(deserializeStatement(it) as IrStatement)
}
return IrCompositeImpl(start, end, type, null, statements)
return IrCompositeImpl(start, end, type.ir, null, statements)
}
private fun deserializeDelegatingConstructorCall(proto: KonanIr.IrDelegatingConstructorCall, start: Int, end: Int): IrDelegatingConstructorCall {
val descriptor = deserializeDescriptor(proto.descriptor) as ClassConstructorDescriptor
val call = IrDelegatingConstructorCallImpl(start, end, IrConstructorSymbolImpl(descriptor.original), descriptor, proto.memberAccess.typeArguments.typeArgumentCount)
val call = IrDelegatingConstructorCallImpl(start, end, context.irBuiltIns.unitType, IrConstructorSymbolImpl(descriptor.original), descriptor, proto.memberAccess.typeArguments.typeArgumentCount)
deserializeMemberAccessCommon(call, proto.memberAccess)
return call
@@ -879,7 +884,7 @@ internal class IrDeserializer(val context: Context,
private fun deserializeGetClass(proto: KonanIr.IrGetClass, start: Int, end: Int, type: KotlinType): IrGetClass {
val argument = deserializeExpression(proto.argument)
return IrGetClassImpl(start, end, type, argument)
return IrGetClassImpl(start, end, type.ir, argument)
}
private fun deserializeGetField(proto: KonanIr.IrGetField, start: Int, end: Int): IrGetField {
@@ -892,39 +897,39 @@ internal class IrDeserializer(val context: Context,
deserializeExpression(access.receiver)
} else null
return IrGetFieldImpl(start, end, IrFieldSymbolImpl(descriptor), receiver, null, createClassSymbolOrNull(superQualifier))
return IrGetFieldImpl(start, end, IrFieldSymbolImpl(descriptor), descriptor.type.ir, receiver, null, createClassSymbolOrNull(superQualifier))
}
private fun deserializeGetValue(proto: KonanIr.IrGetValue, start: Int, end: Int): IrGetValue {
val descriptor = deserializeDescriptor(proto.descriptor) as ValueDescriptor
// TODO: origin!
return IrGetValueImpl(start, end, createValueSymbol(descriptor), null)
return IrGetValueImpl(start, end, descriptor.type.ir, createValueSymbol(descriptor), null)
}
private fun deserializeGetEnumValue(proto: KonanIr.IrGetEnumValue, start: Int, end: Int): IrGetEnumValue {
val type = deserializeKotlinType(proto.type)
val descriptor = deserializeDescriptor(proto.descriptor) as ClassDescriptor
return IrGetEnumValueImpl(start, end, type, IrEnumEntrySymbolImpl(descriptor))
return IrGetEnumValueImpl(start, end, type.ir, IrEnumEntrySymbolImpl(descriptor))
}
private fun deserializeGetObject(proto: KonanIr.IrGetObject, start: Int, end: Int, type: KotlinType): IrGetObjectValue {
val descriptor = deserializeDescriptor(proto.descriptor) as ClassDescriptor
return IrGetObjectValueImpl(start, end, type, IrClassSymbolImpl(descriptor))
return IrGetObjectValueImpl(start, end, type.ir, IrClassSymbolImpl(descriptor))
}
private fun deserializeInstanceInitializerCall(proto: KonanIr.IrInstanceInitializerCall, start: Int, end: Int): IrInstanceInitializerCall {
val descriptor = deserializeDescriptor(proto.descriptor) as ClassDescriptor
return IrInstanceInitializerCallImpl(start, end, IrClassSymbolImpl(descriptor))
return IrInstanceInitializerCallImpl(start, end, IrClassSymbolImpl(descriptor), context.irBuiltIns.unitType)
}
private fun deserializeReturn(proto: KonanIr.IrReturn, start: Int, end: Int, type: KotlinType): IrReturn {
val descriptor =
deserializeDescriptor(proto.returnTarget) as FunctionDescriptor
val value = deserializeExpression(proto.value)
return IrReturnImpl(start, end, type, createFunctionSymbol(descriptor), value)
return IrReturnImpl(start, end, context.irBuiltIns.nothingType, createFunctionSymbol(descriptor), value)
}
private fun deserializeSetField(proto: KonanIr.IrSetField, start: Int, end: Int): IrSetField {
@@ -938,13 +943,13 @@ internal class IrDeserializer(val context: Context,
} else null
val value = deserializeExpression(proto.value)
return IrSetFieldImpl(start, end, IrFieldSymbolImpl(descriptor), receiver, value, null, createClassSymbolOrNull(superQualifier))
return IrSetFieldImpl(start, end, IrFieldSymbolImpl(descriptor), receiver, value, context.irBuiltIns.unitType, null, createClassSymbolOrNull(superQualifier))
}
private fun deserializeSetVariable(proto: KonanIr.IrSetVariable, start: Int, end: Int): IrSetVariable {
val descriptor = deserializeDescriptor(proto.descriptor) as VariableDescriptor
val value = deserializeExpression(proto.value)
return IrSetVariableImpl(start, end, IrVariableSymbolImpl(descriptor), value, null)
return IrSetVariableImpl(start, end, context.irBuiltIns.unitType, IrVariableSymbolImpl(descriptor), value, null)
}
private fun deserializeSpreadElement(proto: KonanIr.IrSpreadElement): IrSpreadElement {
@@ -959,11 +964,11 @@ internal class IrDeserializer(val context: Context,
argumentProtos.forEach {
arguments.add(deserializeExpression(it))
}
return IrStringConcatenationImpl(start, end, type, arguments)
return IrStringConcatenationImpl(start, end, type.ir, arguments)
}
private fun deserializeThrow(proto: KonanIr.IrThrow, start: Int, end: Int, type: KotlinType): IrThrowImpl {
return IrThrowImpl(start, end, type, deserializeExpression(proto.value))
return IrThrowImpl(start, end, context.irBuiltIns.nothingType, deserializeExpression(proto.value))
}
private fun deserializeTry(proto: KonanIr.IrTry, start: Int, end: Int, type: KotlinType): IrTryImpl {
@@ -974,7 +979,7 @@ internal class IrDeserializer(val context: Context,
}
val finallyExpression =
if (proto.hasFinally()) deserializeExpression(proto.getFinally()) else null
return IrTryImpl(start, end, type, result, catches, finallyExpression)
return IrTryImpl(start, end, type.ir, result, catches, finallyExpression)
}
private fun deserializeTypeOperator(operator: KonanIr.IrTypeOperator): IrTypeOperator {
@@ -999,9 +1004,12 @@ internal class IrDeserializer(val context: Context,
private fun deserializeTypeOp(proto: KonanIr.IrTypeOp, start: Int, end: Int, type: KotlinType) : IrTypeOperatorCall {
val operator = deserializeTypeOperator(proto.operator)
val operand = deserializeKotlinType(proto.operand)
val operand = deserializeKotlinType(proto.operand).brokenIr
val argument = deserializeExpression(proto.argument)
return IrTypeOperatorCallImpl(start, end, type, operator, operand, argument)
return IrTypeOperatorCallImpl(start, end, type.ir, operator, operand).apply {
this.argument = argument
this.typeOperandClassifier = operand.classifierOrFail
}
}
private fun deserializeVararg(proto: KonanIr.IrVararg, start: Int, end: Int, type: KotlinType): IrVararg {
@@ -1011,7 +1019,7 @@ internal class IrDeserializer(val context: Context,
proto.elementList.forEach {
elements.add(deserializeVarargElement(it))
}
return IrVarargImpl(start, end, type, elementType, elements)
return IrVarargImpl(start, end, type.ir, elementType.ir, elements)
}
private fun deserializeVarargElement(element: KonanIr.IrVarargElement): IrVarargElement {
@@ -1033,7 +1041,7 @@ internal class IrDeserializer(val context: Context,
}
// TODO: provide some origin!
return IrWhenImpl(start, end, type, null, branches)
return IrWhenImpl(start, end, type.ir, null, branches)
}
private fun deserializeLoop(proto: KonanIr.Loop, loop: IrLoopBase): IrLoopBase {
@@ -1054,7 +1062,7 @@ internal class IrDeserializer(val context: Context,
private fun deserializeDoWhile(proto: KonanIr.IrDoWhile, start: Int, end: Int, type: KotlinType): IrDoWhileLoop {
// we create the loop before deserializing the body, so that
// IrBreak statements have something to put into 'loop' field.
val loop = IrDoWhileLoopImpl(start, end, type, null)
val loop = IrDoWhileLoopImpl(start, end, type.ir, null)
deserializeLoop(proto.loop, loop)
return loop
}
@@ -1062,7 +1070,7 @@ internal class IrDeserializer(val context: Context,
private fun deserializeWhile(proto: KonanIr.IrWhile, start: Int, end: Int, type: KotlinType): IrWhileLoop {
// we create the loop before deserializing the body, so that
// IrBreak statements have something to put into 'loop' field.
val loop = IrWhileLoopImpl(start, end, type, null)
val loop = IrWhileLoopImpl(start, end, type.ir, null)
deserializeLoop(proto.loop, loop)
return loop
}
@@ -1071,7 +1079,7 @@ internal class IrDeserializer(val context: Context,
val label = if(proto.hasLabel()) proto.label else null
val loopId = proto.loopId
val loop = loopIndex[loopId]!!
val irBreak = IrBreakImpl(start, end, type, loop)
val irBreak = IrBreakImpl(start, end, type.ir, loop)
irBreak.label = label
return irBreak
@@ -1081,7 +1089,7 @@ internal class IrDeserializer(val context: Context,
val label = if(proto.hasLabel()) proto.label else null
val loopId = proto.loopId
val loop = loopIndex[loopId]!!
val irContinue = IrContinueImpl(start, end, type, loop)
val irContinue = IrContinueImpl(start, end, type.ir, loop)
irContinue.label = label
return irContinue
@@ -1090,23 +1098,23 @@ internal class IrDeserializer(val context: Context,
private fun deserializeConst(proto: KonanIr.IrConst, start: Int, end: Int, type: KotlinType): IrExpression =
when(proto.valueCase) {
NULL
-> IrConstImpl.constNull(start, end, type)
-> IrConstImpl.constNull(start, end, type.ir)
BOOLEAN
-> IrConstImpl.boolean(start, end, type, proto.boolean)
-> IrConstImpl.boolean(start, end, type.ir, proto.boolean)
BYTE
-> IrConstImpl.byte(start, end, type, proto.byte.toByte())
-> IrConstImpl.byte(start, end, type.ir, proto.byte.toByte())
SHORT
-> IrConstImpl.short(start, end, type, proto.short.toShort())
-> IrConstImpl.short(start, end, type.ir, proto.short.toShort())
INT
-> IrConstImpl.int(start, end, type, proto.int)
-> IrConstImpl.int(start, end, type.ir, proto.int)
LONG
-> IrConstImpl.long(start, end, type, proto.long)
-> IrConstImpl.long(start, end, type.ir, proto.long)
STRING
-> IrConstImpl.string(start, end, type, proto.string)
-> IrConstImpl.string(start, end, type.ir, proto.string)
FLOAT
-> IrConstImpl.float(start, end, type, proto.float)
-> IrConstImpl.float(start, end, type.ir, proto.float)
DOUBLE
-> IrConstImpl.double(start, end, type, proto.double)
-> IrConstImpl.double(start, end, type.ir, proto.double)
else -> {
TODO("Not all const types have been implemented")
}
@@ -1191,9 +1199,10 @@ internal class IrDeserializer(val context: Context,
val clazz = IrClassImpl(start, end, origin, descriptor, members)
clazz.createParameterDeclarations()
clazz.addFakeOverrides()
clazz.setSuperSymbols(context.ir.symbols.symbolTable)
val symbolTable = context.ir.symbols.symbolTable
clazz.createParameterDeclarations(symbolTable)
clazz.addFakeOverrides(symbolTable)
clazz.setSuperSymbols(symbolTable)
return clazz
@@ -1203,10 +1212,12 @@ internal class IrDeserializer(val context: Context,
start: Int, end: Int, origin: IrDeclarationOrigin): IrFunction {
val body = deserializeStatement(proto.body)
val function = IrFunctionImpl(start, end, origin,
descriptor, body as IrBody)
val function = IrFunctionImpl(start, end, origin, descriptor)
function.createParameterDeclarations()
function.returnType = descriptor.returnType!!.ir
function.body = body as IrBody
function.createParameterDeclarations(context.ir.symbols.symbolTable)
function.setOverrides(context.ir.symbols.symbolTable)
proto.defaultArgumentList.forEach {
@@ -1226,7 +1237,7 @@ internal class IrDeserializer(val context: Context,
deserializeExpression(proto.initializer)
} else null
return IrVariableImpl(start, end, origin, descriptor, initializer)
return IrVariableImpl(start, end, origin, descriptor, descriptor.type.ir, initializer)
}
private fun deserializeIrEnumEntry(proto: KonanIr.IrEnumEntry, descriptor: ClassDescriptor,
@@ -19,6 +19,8 @@ package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWithStarProjections
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
@@ -26,6 +28,7 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.visitors.*
@Deprecated("")
@@ -47,11 +50,15 @@ internal fun IrModuleFragment.replaceUnboundSymbols(context: Context) {
val symbolTable = context.ir.symbols.symbolTable
this.transformChildrenVoid(IrUnboundSymbolReplacer(symbolTable, collector.descriptorToSymbol))
this.transformChildrenVoid(IrUnboundSymbolReplacer(symbolTable, collector.descriptorToSymbol, context))
// Generate missing external stubs:
@Suppress("DEPRECATION")
ExternalDependenciesGenerator(symbolTable = context.psi2IrGeneratorContext.symbolTable, irBuiltIns = context.irBuiltIns).generateUnboundSymbolsAsDependencies(this)
ExternalDependenciesGenerator(
context.moduleDescriptor,
symbolTable = context.psi2IrGeneratorContext.symbolTable,
irBuiltIns = context.irBuiltIns
).generateUnboundSymbolsAsDependencies(this)
// Merge duplicated module and package declarations:
this.acceptVoid(object : IrElementVisitorVoid {
@@ -111,7 +118,8 @@ private class DeclarationSymbolCollector : IrElementVisitorVoid {
private class IrUnboundSymbolReplacer(
val symbolTable: SymbolTable,
val descriptorToSymbol: Map<DeclarationDescriptor, IrSymbol>
val descriptorToSymbol: Map<DeclarationDescriptor, IrSymbol>,
val context: Context
) : IrElementTransformerVoid() {
private val localDescriptorToSymbol = mutableMapOf<DeclarationDescriptor, MutableList<IrSymbol>>()
@@ -163,7 +171,7 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this)
return with(expression) {
IrGetValueImpl(startOffset, endOffset, symbol, origin)
IrGetValueImpl(startOffset, endOffset, expression.type, symbol, origin)
}
}
@@ -172,7 +180,7 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this)
return with(expression) {
IrSetVariableImpl(startOffset, endOffset, symbol, value, origin)
IrSetVariableImpl(startOffset, endOffset, expression.type, symbol, value, origin)
}
}
@@ -202,17 +210,11 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this)
return with(expression) {
IrClassReferenceImpl(startOffset, endOffset, type, symbol, symbol.descriptor.defaultType)
IrClassReferenceImpl(startOffset, endOffset, type, symbol, symbol.typeWithStarProjections)
}
}
override fun visitClass(declaration: IrClass): IrStatement {
declaration.superClasses.forEachIndexed { index, symbol ->
val newSymbol = symbol.replace(SymbolTable::referenceClass)
if (newSymbol != null) {
declaration.superClasses[index] = newSymbol
}
}
withLocal(declaration.thisReceiver?.symbol) {
return super.visitClass(declaration)
}
@@ -229,7 +231,7 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this)
return with(expression) {
IrGetFieldImpl(startOffset, endOffset, symbol, receiver, origin, superQualifierSymbol)
IrGetFieldImpl(startOffset, endOffset, symbol, type, receiver, origin, superQualifierSymbol)
}
}
@@ -244,11 +246,13 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this)
return with(expression) {
IrSetFieldImpl(startOffset, endOffset, symbol, receiver, value, origin, superQualifierSymbol)
IrSetFieldImpl(startOffset, endOffset, symbol, receiver, value, type, origin, superQualifierSymbol)
}
}
override fun visitCall(expression: IrCall): IrExpression {
expression.replaceTypeArguments()
val symbol = expression.symbol.replace(SymbolTable::referenceFunction) ?: expression.symbol
val superQualifierSymbol = expression.superQualifierSymbol?.replaceOrSame(SymbolTable::referenceClass)
@@ -259,17 +263,21 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid()
return with(expression) {
IrCallImpl(startOffset, endOffset, symbol, descriptor,
getTypeArgumentsMap(),
IrCallImpl(startOffset, endOffset, type, symbol, descriptor,
typeArgumentsCount,
origin, superQualifierSymbol).also {
it.copyArgumentsFrom(this)
it.copyTypeArgumentsFrom(this)
}
}
}
private fun IrMemberAccessExpression.getTypeArgumentsMap() =
descriptor.original.typeParameters.associate { it to getTypeArgumentOrDefault(it) }
private fun IrMemberAccessExpression.replaceTypeArguments() {
repeat(typeArgumentsCount) {
putTypeArgument(it, getTypeArgument(it)?.toKotlinType()?.let { context.ir.translateErased(it) })
}
}
private fun IrMemberAccessExpressionBase.copyArgumentsFrom(original: IrMemberAccessExpression) {
dispatchReceiver = original.dispatchReceiver
@@ -284,37 +292,45 @@ private class IrUnboundSymbolReplacer(
return super.visitEnumConstructorCall(expression)
return with(expression) {
IrEnumConstructorCallImpl(startOffset, endOffset, symbol, null).also {
IrEnumConstructorCallImpl(startOffset, endOffset, expression.type, symbol, 0).also {
it.copyArgumentsFrom(this)
}
}
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.replaceTypeArguments()
val symbol = expression.symbol.replace(SymbolTable::referenceConstructor) ?:
return super.visitDelegatingConstructorCall(expression)
expression.transformChildrenVoid()
return with(expression) {
IrDelegatingConstructorCallImpl(startOffset, endOffset, symbol, descriptor, getTypeArgumentsMap()).also {
IrDelegatingConstructorCallImpl(startOffset, endOffset, type, symbol, descriptor, typeArgumentsCount).also {
it.copyArgumentsFrom(this)
it.copyTypeArgumentsFrom(this)
}
}
}
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
expression.replaceTypeArguments()
val symbol = expression.symbol.replace(SymbolTable::referenceFunction) ?:
return super.visitFunctionReference(expression)
expression.transformChildrenVoid(this)
return with(expression) {
IrFunctionReferenceImpl(startOffset, endOffset, type, symbol, descriptor, getTypeArgumentsMap()).also {
IrFunctionReferenceImpl(startOffset, endOffset, type, symbol, descriptor, 0).also {
it.copyArgumentsFrom(this)
it.copyTypeArgumentsFrom(this)
}
}
}
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
expression.replaceTypeArguments()
val field = expression.field?.replaceOrSame(SymbolTable::referenceField)
val getter = expression.getter?.replace(SymbolTable::referenceFunction) ?: expression.getter
val setter = expression.setter?.replace(SymbolTable::referenceFunction) ?: expression.setter
@@ -325,13 +341,14 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this)
return with(expression) {
IrPropertyReferenceImpl(startOffset, endOffset, type, descriptor,
IrPropertyReferenceImpl(startOffset, endOffset, type, descriptor, 0,
field,
getter,
setter,
getTypeArgumentsMap(), origin).also {
origin).also {
it.copyArgumentsFrom(this)
it.copyTypeArgumentsFrom(this)
}
}
}
@@ -413,7 +430,19 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this)
return with(expression) {
IrInstanceInitializerCallImpl(startOffset, endOffset, classSymbol)
IrInstanceInitializerCallImpl(startOffset, endOffset, classSymbol, type)
}
}
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
expression.transformChildrenVoid(this)
return with(expression) {
val newTypeOperand = context.ir.translateErased(typeOperand.toKotlinType())
IrTypeOperatorCallImpl(startOffset, endOffset, type, operator, newTypeOperand).also {
it.argument = argument
it.typeOperandClassifier = newTypeOperand.classifier
}
}
}
}
@@ -17,26 +17,40 @@
package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.descriptors.substitute
import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.KonanCompilationException
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingStrategy
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
import java.lang.reflect.Proxy
//TODO: delete file on next kotlin dependency update
@@ -63,25 +77,20 @@ internal fun IrFile.addTopLevelInitializer(expression: IrExpression) {
)
val builtIns = fieldDescriptor.builtIns
fieldDescriptor.setType(builtIns.unitType, emptyList(), null, null as KotlinType?)
fieldDescriptor.setType(expression.type.toKotlinType(), emptyList(), null, null as KotlinType?)
fieldDescriptor.initialize(null, null)
val irField = IrFieldImpl(
expression.startOffset, expression.endOffset,
IrDeclarationOrigin.DEFINED, fieldDescriptor
IrDeclarationOrigin.DEFINED, fieldDescriptor, expression.type
)
val initializer = IrTypeOperatorCallImpl(
expression.startOffset, expression.endOffset, builtIns.unitType,
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, builtIns.unitType, expression
)
irField.initializer = IrExpressionBodyImpl(expression.startOffset, expression.endOffset, initializer)
irField.initializer = IrExpressionBodyImpl(expression.startOffset, expression.endOffset, expression)
this.addChild(irField)
}
fun IrClass.addFakeOverrides() {
fun IrClass.addFakeOverrides(symbolTable: SymbolTable) {
val startOffset = this.startOffset
val endOffset = this.endOffset
@@ -90,17 +99,23 @@ fun IrClass.addFakeOverrides() {
.filterIsInstance<CallableMemberDescriptor>()
.filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
.forEach {
this.addChild(createFakeOverride(it, startOffset, endOffset))
this.addChild(createFakeOverride(it, startOffset, endOffset, symbolTable))
}
}
private fun createFakeOverride(descriptor: CallableMemberDescriptor, startOffset: Int, endOffset: Int): IrDeclaration {
private fun createFakeOverride(
descriptor: CallableMemberDescriptor,
startOffset: Int,
endOffset: Int,
symbolTable: SymbolTable
): IrDeclaration {
fun FunctionDescriptor.createFunction(): IrFunction = IrFunctionImpl(
fun FunctionDescriptor.createFunction(): IrSimpleFunction = IrFunctionImpl(
startOffset, endOffset,
IrDeclarationOrigin.FAKE_OVERRIDE, this
).apply {
createParameterDeclarations()
returnType = symbolTable.translateErased(this@createFunction.returnType!!)
createParameterDeclarations(symbolTable)
}
return when (descriptor) {
@@ -115,11 +130,13 @@ private fun createFakeOverride(descriptor: CallableMemberDescriptor, startOffset
}
}
fun IrFunction.createParameterDeclarations() {
fun IrFunction.createParameterDeclarations(symbolTable: SymbolTable) {
fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl(
innerStartOffset(this), innerEndOffset(this),
IrDeclarationOrigin.DEFINED,
this
this, symbolTable.translateErased(this.type),
(this as? ValueParameterDescriptor)?.varargElementType?.let { symbolTable.translateErased(it) }
).also {
it.parent = this@createParameterDeclarations
}
@@ -138,18 +155,84 @@ fun IrFunction.createParameterDeclarations() {
it
).also { typeParameter ->
typeParameter.parent = this
typeParameter.descriptor.upperBounds.mapTo(typeParameter.superTypes, symbolTable::translateErased)
}
}
}
private fun createFakeOverride(
descriptor: CallableMemberDescriptor,
overriddenDeclarations: List<IrDeclaration>,
irClass: IrClass
): IrDeclaration {
// TODO: this function doesn't substitute types.
fun IrSimpleFunction.copyFake(descriptor: FunctionDescriptor): IrSimpleFunction = IrFunctionImpl(
irClass.startOffset, irClass.endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, descriptor
).also {
it.returnType = returnType
it.parent = irClass
it.createDispatchReceiverParameter()
it.extensionReceiverParameter = this.extensionReceiverParameter?.let {
IrValueParameterImpl(
it.startOffset,
it.endOffset,
IrDeclarationOrigin.DEFINED,
it.descriptor.extensionReceiverParameter!!,
it.type,
null
)
}
this.valueParameters.mapTo(it.valueParameters) { oldParameter ->
IrValueParameterImpl(
oldParameter.startOffset,
oldParameter.endOffset,
IrDeclarationOrigin.DEFINED,
it.descriptor.valueParameters[oldParameter.index],
oldParameter.type,
(oldParameter as? IrValueParameter)?.varargElementType
)
}
this.typeParameters.mapTo(it.typeParameters) { oldParameter ->
IrTypeParameterImpl(
irClass.startOffset,
irClass.endOffset,
IrDeclarationOrigin.DEFINED,
it.descriptor.typeParameters[oldParameter.index]
).apply {
superTypes += oldParameter.superTypes
}
}
}
val copiedDeclaration = overriddenDeclarations.first()
return when (copiedDeclaration) {
is IrSimpleFunction -> copiedDeclaration.copyFake(descriptor as FunctionDescriptor)
is IrProperty -> IrPropertyImpl(
irClass.startOffset,
irClass.endOffset,
IrDeclarationOrigin.FAKE_OVERRIDE,
descriptor as PropertyDescriptor
).apply {
parent = irClass
getter = copiedDeclaration.getter?.copyFake(descriptor.getter!!)
setter = copiedDeclaration.setter?.copyFake(descriptor.setter!!)
}
else -> error(copiedDeclaration)
}
}
fun IrSimpleFunction.setOverrides(symbolTable: SymbolTable) {
assert(this.overriddenSymbols.isEmpty())
this.descriptor.overriddenDescriptors.mapTo(this.overriddenSymbols) {
symbolTable.referenceSimpleFunction(it.original)
}
this.typeParameters.forEach { it.setSupers(symbolTable) }
}
fun IrClass.simpleFunctions(): List<IrSimpleFunction> = this.declarations.flatMap {
@@ -161,32 +244,56 @@ fun IrClass.simpleFunctions(): List<IrSimpleFunction> = this.declarations.flatMa
}
fun IrClass.createParameterDeclarations() {
descriptor.thisAsReceiverParameter.let {
thisReceiver = IrValueParameterImpl(
innerStartOffset(it), innerEndOffset(it),
IrDeclarationOrigin.INSTANCE_RECEIVER,
it
).also { valueParameter ->
valueParameter.parent = this
}
thisReceiver = IrValueParameterImpl(
startOffset, endOffset,
IrDeclarationOrigin.INSTANCE_RECEIVER,
descriptor.thisAsReceiverParameter,
this.symbol.typeWith(this.typeParameters.map { it.defaultType }),
null
).also { valueParameter ->
valueParameter.parent = this
}
assert(typeParameters.isEmpty())
descriptor.declaredTypeParameters.mapTo(typeParameters) {
IrTypeParameterImpl(
innerStartOffset(it), innerEndOffset(it),
IrDeclarationOrigin.DEFINED,
it
).also { typeParameter ->
typeParameter.parent = this
}
}
assert(descriptor.declaredTypeParameters.isEmpty())
}
fun IrClass.setSuperSymbols(supers: List<IrClass>) {
fun IrFunction.createDispatchReceiverParameter() {
assert(this.dispatchReceiverParameter == null)
val descriptor = this.descriptor.dispatchReceiverParameter ?: return
this.dispatchReceiverParameter = IrValueParameterImpl(
startOffset,
endOffset,
IrDeclarationOrigin.DEFINED,
descriptor,
(parent as IrClass).defaultType,
null
).also { it.parent = this }
}
fun IrClass.createParameterDeclarations(symbolTable: SymbolTable) {
this.descriptor.declaredTypeParameters.mapTo(this.typeParameters) {
IrTypeParameterImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, it).apply {
it.upperBounds.mapTo(this.superTypes, symbolTable::translateErased)
}
}
this.thisReceiver = IrValueParameterImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
this.descriptor.thisAsReceiverParameter,
this.symbol.typeWith(this.typeParameters.map { it.defaultType }),
null
)
}
fun IrClass.setSuperSymbols(superTypes: List<IrType>) {
val supers = superTypes.map { it.getClass()!! }
assert(this.superDescriptors().toSet() == supers.map { it.descriptor }.toSet())
assert(this.superClasses.isEmpty())
supers.mapTo(this.superClasses) { it.symbol }
assert(this.superTypes.isEmpty())
this.superTypes += superTypes
val superMembers = supers.flatMap {
it.simpleFunctions()
@@ -206,48 +313,38 @@ private fun IrClass.superDescriptors() =
this.descriptor.typeConstructor.supertypes.map { it.constructor.declarationDescriptor as ClassDescriptor }
fun IrClass.setSuperSymbols(symbolTable: SymbolTable) {
assert(this.superClasses.isEmpty())
this.superDescriptors().mapTo(this.superClasses) { symbolTable.referenceClass(it) }
assert(this.superTypes.isEmpty())
this.descriptor.typeConstructor.supertypes.mapTo(this.superTypes) { symbolTable.translateErased(it) }
this.simpleFunctions().forEach {
it.setOverrides(symbolTable)
}
this.typeParameters.forEach {
it.setSupers(symbolTable)
}
}
fun IrTypeParameter.setSupers(symbolTable: SymbolTable) {
assert(this.superClassifiers.isEmpty())
this.descriptor.upperBounds.mapNotNullTo(this.superClassifiers) {
it.constructor.declarationDescriptor?.let {
if (it is TypeParameterDescriptor) {
IrTypeParameterSymbolImpl(it) // Workaround for deserialized inline functions
} else {
symbolTable.referenceClassifier(it)
}
}
}
}
fun IrClass.setSuperSymbolsAndAddFakeOverrides(supers: List<IrClass>) {
fun IrClass.setSuperSymbolsAndAddFakeOverrides(superTypes: List<IrType>) {
val overriddenSuperMembers = this.declarations.map { it.descriptor }
.filterIsInstance<CallableMemberDescriptor>().flatMap { it.overriddenDescriptors.map { it.original } }
.filterIsInstance<CallableMemberDescriptor>().flatMap { it.overriddenDescriptors.map { it.original } }.toSet()
val unoverriddenSuperMembers = supers.flatMap {
it.declarations.mapNotNull {
val unoverriddenSuperMembers = superTypes.map { it.getClass()!! }.flatMap {
it.declarations.filter { it.descriptor !in overriddenSuperMembers }.mapNotNull {
when (it) {
is IrSimpleFunction -> it.descriptor
is IrProperty -> it.descriptor
is IrSimpleFunction -> it.descriptor to it
is IrProperty -> it.descriptor to it
else -> null
}
}
} - overriddenSuperMembers
}.toMap()
val irClass = this
val overridingStrategy = object : OverridingStrategy() {
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) {
irClass.addChild(createFakeOverride(fakeOverride, startOffset, endOffset))
val overriddenDeclarations =
fakeOverride.overriddenDescriptors.map { unoverriddenSuperMembers[it]!! }
assert(overriddenDeclarations.isNotEmpty())
irClass.declarations.add(createFakeOverride(fakeOverride, overriddenDeclarations, irClass))
}
override fun inheritanceConflict(first: CallableMemberDescriptor, second: CallableMemberDescriptor) {
@@ -259,7 +356,7 @@ fun IrClass.setSuperSymbolsAndAddFakeOverrides(supers: List<IrClass>) {
}
}
unoverriddenSuperMembers.groupBy { it.name }.forEach { (name, members) ->
unoverriddenSuperMembers.keys.groupBy { it.name }.forEach { (name, members) ->
OverridingUtil.generateOverridesInFunctionGroup(
name,
members,
@@ -269,7 +366,7 @@ fun IrClass.setSuperSymbolsAndAddFakeOverrides(supers: List<IrClass>) {
)
}
this.setSuperSymbols(supers)
this.setSuperSymbols(superTypes)
}
private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int =
@@ -327,7 +424,7 @@ object CheckDeclarationParentsVisitor : IrElementVisitor<Unit, IrDeclarationPare
}
override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclarationParent?) {
if (declaration !is IrVariable) {
if (declaration !is IrVariable && declaration !is IrValueParameter && declaration !is IrTypeParameter) {
checkParent(declaration, data)
} else {
// Don't check IrVariable parent.
@@ -376,7 +473,7 @@ internal fun KonanBackendContext.report(declaration: IrDeclaration, message: Str
}
fun IrBuilderWithScope.irForceNotNull(expression: IrExpression): IrExpression {
if (!TypeUtils.isNullableType(expression.type)) {
if (!expression.type.containsNull()) {
return expression
}
@@ -384,9 +481,263 @@ fun IrBuilderWithScope.irForceNotNull(expression: IrExpression): IrExpression {
val temporary = irTemporaryVar(expression)
+irIfNull(
expression.type,
subject = irGet(temporary.symbol),
subject = irGet(temporary),
thenPart = irThrowNpe(IrStatementOrigin.EXCLEXCL),
elsePart = irGet(temporary.symbol)
elsePart = irGet(temporary)
)
}
}
fun IrFunctionAccessExpression.addArguments(args: Map<IrValueParameter, IrExpression>) {
val unhandledParameters = args.keys.toMutableSet()
fun getArg(parameter: IrValueParameter) = args[parameter]?.also { unhandledParameters -= parameter }
symbol.owner.dispatchReceiverParameter?.let {
val arg = getArg(it)
if (arg != null) {
this.dispatchReceiver = arg
}
}
symbol.owner.extensionReceiverParameter?.let {
val arg = getArg(it)
if (arg != null) {
this.extensionReceiver = arg
}
}
symbol.owner.valueParameters.forEach {
val arg = getArg(it)
if (arg != null) {
this.putValueArgument(it.index, arg)
}
}
}
private fun FunctionDescriptor.substitute(
typeArguments: List<IrType>
): FunctionDescriptor = if (typeArguments.isEmpty()) {
this
} else {
this.substitute(*typeArguments.map { it.toKotlinType() }.toTypedArray())
}
fun IrType.substitute(map: Map<IrTypeParameterSymbol, IrType>): IrType {
if (this !is IrSimpleType) return this
val classifier = this.classifier
return when (classifier) {
is IrTypeParameterSymbol ->
map[classifier]?.let { if (this.hasQuestionMark) it.makeNullable() else it }
?: this
is IrClassSymbol -> if (this.arguments.isEmpty()) {
this // Fast path.
} else {
val newArguments = this.arguments.map {
when (it) {
is IrTypeProjection -> makeTypeProjection(it.type.substitute(map), it.variance)
is IrStarProjection -> it
else -> error(it)
}
}
IrSimpleTypeImpl(classifier, hasQuestionMark, newArguments, annotations)
}
else -> error(classifier)
}
}
private fun IrFunction.substitutedReturnType(typeArguments: List<IrType>): IrType {
val unsubstituted = this.returnType
if (typeArguments.isEmpty()) return unsubstituted // Fast path.
if (this is IrConstructor) {
// Workaround for missing type parameters in constructors. TODO: remove.
return this.returnType.classifierOrFail.typeWith(typeArguments)
}
assert(this.typeParameters.size >= typeArguments.size) // TODO: check equality.
// TODO: receiver type must also be considered.
return unsubstituted.substitute(this.typeParameters.map { it.symbol }.zip(typeArguments).toMap())
}
// TODO: this function must be avoided since it takes symbol's owner implicitly.
fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol, typeArguments: List<IrType> = emptyList()) =
irCall(symbol.owner, typeArguments)
fun IrBuilderWithScope.irCall(
irFunction: IrFunction,
typeArguments: List<IrType> = emptyList()
): IrCall = irCall(this.startOffset, this.endOffset, irFunction, typeArguments)
internal fun irCall(startOffset: Int, endOffset: Int, irFunction: IrFunction, typeArguments: List<IrType>): IrCall =
IrCallImpl(
startOffset, endOffset, irFunction.substitutedReturnType(typeArguments),
irFunction.symbol, irFunction.descriptor.substitute(typeArguments), typeArguments.size
).apply {
typeArguments.forEachIndexed { index, irType ->
this.putTypeArgument(index, irType)
}
}
fun IrBuilderWithScope.irCall(
irFunction: IrFunctionSymbol,
type: IrType,
typeArguments: List<IrType> = emptyList()
): IrCall = IrCallImpl(
startOffset, endOffset, type,
irFunction, irFunction.descriptor.substitute(typeArguments), typeArguments.size
).apply {
typeArguments.forEachIndexed { index, irType ->
this.putTypeArgument(index, irType)
}
}
fun IrBuilderWithScope.irCallOp(
callee: IrFunction,
dispatchReceiver: IrExpression,
argument: IrExpression
): IrCall =
irCall(callee).apply {
this.dispatchReceiver = dispatchReceiver
putValueArgument(0, argument)
}
fun IrBuilderWithScope.irSetVar(variable: IrVariable, value: IrExpression) =
irSetVar(variable.symbol, value)
fun IrBuilderWithScope.irSetField(receiver: IrExpression, irField: IrField, value: IrExpression): IrExpression =
IrSetFieldImpl(
startOffset,
endOffset,
irField.symbol,
receiver = receiver,
value = value,
type = context.irBuiltIns.unitType
)
/**
* Binds the arguments explicitly represented in the IR to the parameters of the accessed function.
* The arguments are to be evaluated in the same order as they appear in the resulting list.
*/
fun IrMemberAccessExpression.getArgumentsWithIr(): List<Pair<IrValueParameter, IrExpression>> {
val res = mutableListOf<Pair<IrValueParameter, IrExpression>>()
val irFunction = when (this) {
is IrFunctionAccessExpression -> this.symbol.owner
is IrFunctionReference -> this.symbol.owner
else -> error(this)
}
dispatchReceiver?.let {
res += (irFunction.dispatchReceiverParameter!! to it)
}
extensionReceiver?.let {
res += (irFunction.extensionReceiverParameter!! to it)
}
irFunction.valueParameters.forEachIndexed { index, it ->
val arg = getValueArgument(index)
if (arg != null) {
res += (it to arg)
}
}
return res
}
fun CallableMemberDescriptor.createValueParameter(
index: Int,
name: String,
type: IrType,
startOffset: Int,
endOffset: Int
): IrValueParameter {
val descriptor = ValueParameterDescriptorImpl(
this, null,
index,
Annotations.EMPTY,
Name.identifier(name),
type.toKotlinType(),
false, false, false, null, SourceElement.NO_SOURCE
)
return IrValueParameterImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, descriptor, type, null)
}
fun SymbolTable.translateErased(type: KotlinType): IrSimpleType {
val descriptor = TypeUtils.getClassDescriptor(type)
if (descriptor == null) return translateErased(type.immediateSupertypes().first())
val classSymbol = this.referenceClass(descriptor)
val nullable = type.isMarkedNullable
val arguments = type.arguments.map { IrStarProjectionImpl }
return classSymbol.createType(nullable, arguments)
}
fun CommonBackendContext.createArrayOfExpression(
arrayElementType: IrType,
arrayElements: List<IrExpression>,
startOffset: Int, endOffset: Int
): IrExpression {
val arrayType = ir.symbols.array.typeWith(arrayElementType)
val arg0 = IrVarargImpl(startOffset, endOffset, arrayType, arrayElementType, arrayElements)
return irCall(startOffset, endOffset, ir.symbols.arrayOf.owner, listOf(arrayElementType)).apply {
putValueArgument(0, arg0)
}
}
fun createField(
startOffset: Int,
endOffset: Int,
type: IrType,
name: Name,
isMutable: Boolean,
origin: IrDeclarationOrigin,
owner: ClassDescriptor
): IrField {
val descriptor = PropertyDescriptorImpl.create(
/* containingDeclaration = */ owner,
/* annotations = */ Annotations.EMPTY,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE,
/* isVar = */ isMutable,
/* name = */ name,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE,
/* lateInit = */ false,
/* isConst = */ false,
/* isExpect = */ false,
/* isActual = */ false,
/* isExternal = */ false,
/* isDelegated = */ false
).apply {
initialize(null, null)
val receiverType: KotlinType? = null
setType(type.toKotlinType(), emptyList(), owner.thisAsReceiverParameter, receiverType)
}
return IrFieldImpl(startOffset, endOffset, origin, descriptor, type)
}
fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter {
assert(this.descriptor.type == newDescriptor.type)
return IrValueParameterImpl(
startOffset,
endOffset,
IrDeclarationOrigin.DEFINED,
newDescriptor,
type,
varargElementType
)
}
val IrTypeArgument.typeOrNull: IrType? get() = (this as? IrTypeProjection)?.type
val IrType.isSimpleTypeWithQuestionMark: Boolean
get() = this is IrSimpleType && this.hasQuestionMark
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: NATIVE
//For KT-6020
import kotlin.reflect.KProperty1
import kotlin.reflect.KMutableProperty1
@@ -47,7 +47,7 @@ class Worker(val id: WorkerId) {
* until all scheduled jobs processed, or terminate immediately.
*/
fun requestTermination(processScheduledJobs: Boolean = true) =
Future<FutureId>(requestTerminationInternal(id, processScheduledJobs))
Future<Nothing?>(requestTerminationInternal(id, processScheduledJobs))
/**
* Schedule a job for further execution in the worker. Schedule is a two-phase operation,