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 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.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFunction 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.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.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.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid 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. * 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.useAsStatement(): IrExpression = this
protected open fun IrExpression.useInTypeOperator(operator: IrTypeOperator, typeOperand: KotlinType): IrExpression = protected open fun IrExpression.useInTypeOperator(operator: IrTypeOperator, typeOperand: IrType): IrExpression =
this 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 = protected open fun IrExpression.useAsArgument(parameter: ParameterDescriptor): IrExpression =
this.useAsValue(parameter) this.useAsValue(parameter)
protected open fun IrExpression.useAsDispatchReceiver(expression: IrMemberAccessExpression): IrExpression = protected open fun IrExpression.useAsDispatchReceiver(expression: IrFunctionAccessExpression): IrExpression =
this.useAsArgument(expression.descriptor.dispatchReceiverParameter!!) this.useAsArgument(expression.symbol.owner.dispatchReceiverParameter!!)
protected open fun IrExpression.useAsExtensionReceiver(expression: IrMemberAccessExpression): IrExpression = protected open fun IrExpression.useAsExtensionReceiver(expression: IrFunctionAccessExpression): IrExpression =
this.useAsArgument(expression.descriptor.extensionReceiverParameter!!) this.useAsArgument(expression.symbol.owner.extensionReceiverParameter!!)
protected open fun IrExpression.useAsValueArgument(expression: IrMemberAccessExpression, protected open fun IrExpression.useAsValueArgument(expression: IrFunctionAccessExpression,
parameter: ValueParameterDescriptor): IrExpression = parameter: ValueParameterDescriptor): IrExpression =
this.useAsArgument(parameter) this.useAsArgument(parameter)
protected open fun IrExpression.useForVariable(variable: VariableDescriptor): IrExpression = private fun IrExpression.useForVariable(variable: VariableDescriptor): IrExpression =
this.useAsValue(variable) this.useAsValue(variable)
protected open fun IrExpression.useForField(field: PropertyDescriptor): IrExpression = private fun IrExpression.useForField(field: IrField): IrExpression =
this.useForVariable(field) this.useAs(field.type)
protected open fun IrExpression.useAsReturnValue(returnTarget: CallableDescriptor): IrExpression { protected open fun IrExpression.useAsReturnValue(returnTarget: IrReturnTargetSymbol): IrExpression =
val returnType = returnTarget.returnType ?: return this when (returnTarget) {
return this.useAs(returnType) 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 = protected open fun IrExpression.useAsResult(enclosing: IrExpression): IrExpression =
this.useAs(enclosing.type) 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) expression.transformChildrenVoid(this)
with(expression) { with(expression) {
@@ -86,7 +109,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
extensionReceiver = extensionReceiver?.useAsExtensionReceiver(expression) extensionReceiver = extensionReceiver?.useAsExtensionReceiver(expression)
for (index in descriptor.valueParameters.indices) { for (index in descriptor.valueParameters.indices) {
val argument = getValueArgument(index) ?: continue val argument = getValueArgument(index) ?: continue
val parameter = descriptor.valueParameters[index] val parameter = symbol.owner.valueParameters[index]
putValueArgument(index, argument.useAsValueArgument(expression, parameter)) putValueArgument(index, argument.useAsValueArgument(expression, parameter))
} }
} }
@@ -130,7 +153,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
override fun visitReturn(expression: IrReturn): IrExpression { override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
expression.value = expression.value.useAsReturnValue(expression.returnTarget) expression.value = expression.value.useAsReturnValue(expression.returnTargetSymbol)
return expression return expression
} }
@@ -138,7 +161,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
override fun visitSetVariable(expression: IrSetVariable): IrExpression { override fun visitSetVariable(expression: IrSetVariable): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
expression.value = expression.value.useForVariable(expression.descriptor) expression.value = expression.value.useForVariable(expression.symbol.owner)
return expression return expression
} }
@@ -146,7 +169,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
override fun visitSetField(expression: IrSetField): IrExpression { override fun visitSetField(expression: IrSetField): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
expression.value = expression.value.useForField(expression.descriptor) expression.value = expression.value.useForField(expression.symbol.owner)
return expression return expression
} }
@@ -155,7 +178,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
declaration.transformChildrenVoid(this) declaration.transformChildrenVoid(this)
declaration.initializer?.let { declaration.initializer?.let {
it.expression = it.expression.useForField(declaration.descriptor) it.expression = it.expression.useForField(declaration)
} }
return declaration return declaration
@@ -164,7 +187,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
override fun visitVariable(declaration: IrVariable): IrVariable { override fun visitVariable(declaration: IrVariable): IrVariable {
declaration.transformChildrenVoid(this) declaration.transformChildrenVoid(this)
declaration.initializer = declaration.initializer?.useForVariable(declaration.descriptor) declaration.initializer = declaration.initializer?.useForVariable(declaration)
return declaration return declaration
} }
@@ -173,7 +196,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
for (irBranch in expression.branches) { 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) irBranch.result = irBranch.result.useAsResult(expression)
} }
@@ -183,7 +206,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
override fun visitLoop(loop: IrLoop): IrExpression { override fun visitLoop(loop: IrLoop): IrExpression {
loop.transformChildrenVoid(this) loop.transformChildrenVoid(this)
loop.condition = loop.condition.useAs(builtIns.booleanType) loop.condition = loop.condition.useAs(irBuiltIns.booleanType)
loop.body = loop.body?.useAsStatement() loop.body = loop.body?.useAsStatement()
@@ -193,7 +216,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
override fun visitThrow(expression: IrThrow): IrExpression { override fun visitThrow(expression: IrThrow): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
expression.value = expression.value.useAs(builtIns.throwable.defaultType) expression.value = expression.value.useAs(symbols.throwable.owner.defaultType)
return expression return expression
} }
@@ -238,8 +261,8 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
override fun visitFunction(declaration: IrFunction): IrStatement { override fun visitFunction(declaration: IrFunction): IrStatement {
declaration.transformChildrenVoid(this) declaration.transformChildrenVoid(this)
declaration.descriptor.valueParameters.forEach { parameter -> declaration.valueParameters.forEach { parameter ->
val defaultValue = declaration.getDefault(parameter) val defaultValue = parameter.defaultValue
if (defaultValue is IrExpressionBody) { if (defaultValue is IrExpressionBody) {
defaultValue.expression = defaultValue.expression.useAsArgument(parameter) defaultValue.expression = defaultValue.expression.useAsArgument(parameter)
} }
@@ -247,7 +270,7 @@ abstract class AbstractValueUsageTransformer(val builtIns: KotlinBuiltIns): IrEl
declaration.body?.let { declaration.body?.let {
if (it is IrExpressionBody) { 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.ir.KonanSymbols
import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol 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.defaultType
import org.jetbrains.kotlin.ir.util.getPropertyGetter import org.jetbrains.kotlin.ir.util.getPropertyGetter
import org.jetbrains.kotlin.konan.target.KonanTarget 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) = internal fun KonanSymbols.getTypeConversion(actualType: KotlinType, expectedType: KotlinType) =
getTypeConversion(actualType.correspondingValueType, expectedType.correspondingValueType) getTypeConversion(actualType.correspondingValueType, expectedType.correspondingValueType)
internal fun KonanSymbols.getTypeConversion(actualType: IrType, expectedType: IrType) =
getTypeConversion(actualType.correspondingValueType, expectedType.correspondingValueType)
internal fun KonanSymbols.getTypeConversion( internal fun KonanSymbols.getTypeConversion(
actualValueType: ValueType?, actualValueType: ValueType?,
expectedValueType: ValueType? expectedValueType: ValueType?
@@ -18,18 +18,16 @@ package org.jetbrains.kotlin.backend.konan
import llvm.LLVMDumpModule import llvm.LLVMDumpModule
import llvm.LLVMModuleRef import llvm.LLVMModuleRef
import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor
import org.jetbrains.kotlin.backend.common.ReflectionTypes import org.jetbrains.kotlin.backend.common.ReflectionTypes
import org.jetbrains.kotlin.backend.common.validateIrModule 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.konan.descriptors.*
import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor
import org.jetbrains.kotlin.backend.common.descriptors.DescriptorsFactory import org.jetbrains.kotlin.backend.common.descriptors.DescriptorsFactory
import org.jetbrains.kotlin.backend.konan.ir.KonanIr import org.jetbrains.kotlin.backend.konan.ir.KonanIr
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryWriter import org.jetbrains.kotlin.backend.konan.library.KonanLibraryWriter
import org.jetbrains.kotlin.backend.konan.library.LinkData import org.jetbrains.kotlin.backend.konan.library.LinkData
import org.jetbrains.kotlin.backend.konan.llvm.* 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.DECLARATION_ORIGIN_BRIDGE_METHOD
import org.jetbrains.kotlin.backend.konan.lower.bridgeTarget
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations 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.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.util.endOffsetOrUndefined import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.startOffsetOrUndefined 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.IrElementVisitor
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
import org.jetbrains.kotlin.metadata.KonanLinkData import org.jetbrains.kotlin.metadata.KonanLinkData
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext 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.resolve.scopes.receivers.ImplicitClassReceiver
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
import org.jetbrains.kotlin.serialization.deserialization.getName import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.types.KotlinType
import java.lang.System.out import java.lang.System.out
import kotlin.LazyThreadSafetyMode.PUBLICATION import kotlin.LazyThreadSafetyMode.PUBLICATION
@@ -66,72 +64,49 @@ internal class SpecialDeclarationsFactory(val context: Context) {
private val enumSpecialDeclarationsFactory by lazy { EnumSpecialDeclarationsFactory(context) } private val enumSpecialDeclarationsFactory by lazy { EnumSpecialDeclarationsFactory(context) }
private val outerThisFields = mutableMapOf<ClassDescriptor, IrField>() private val outerThisFields = mutableMapOf<ClassDescriptor, IrField>()
private val bridgesDescriptors = mutableMapOf<Pair<IrSimpleFunction, BridgeDirections>, IrSimpleFunction>() private val bridgesDescriptors = mutableMapOf<Pair<IrSimpleFunction, BridgeDirections>, IrSimpleFunction>()
private val loweredEnums = mutableMapOf<ClassDescriptor, LoweredEnum>() private val loweredEnums = mutableMapOf<IrClass, LoweredEnum>()
private val ordinals = mutableMapOf<IrClass, Map<ClassDescriptor, Int>>() private val ordinals = mutableMapOf<ClassDescriptor, Map<ClassDescriptor, Int>>()
object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS : object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS :
IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS") IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS")
fun getOuterThisField(innerClassDescriptor: ClassDescriptor): IrField = fun getOuterThisField(innerClass: IrClass): IrField =
if (!innerClassDescriptor.isInner) throw AssertionError("Class is not inner: $innerClassDescriptor") if (!innerClass.descriptor.isInner) throw AssertionError("Class is not inner: ${innerClass.descriptor}")
else outerThisFields.getOrPut(innerClassDescriptor) { else outerThisFields.getOrPut(innerClass.descriptor) {
val outerClassDescriptor = DescriptorUtils.getContainingClass(innerClassDescriptor) ?: val outerClass = innerClass.parent as? IrClass
throw AssertionError("No containing class for inner class $innerClassDescriptor") ?: 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( val descriptor = PropertyDescriptorImpl.create(
innerClassDescriptor, Annotations.EMPTY, Modality.FINAL, innerClass.descriptor, Annotations.EMPTY, Modality.FINAL,
Visibilities.PRIVATE, false, "this$0".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, Visibilities.PRIVATE, false, "this$0".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE, false, false, false, false, false, false 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( IrFieldImpl(
innerClassDescriptor.startOffsetOrUndefined, innerClass.descriptor.startOffsetOrUndefined,
innerClassDescriptor.endOffsetOrUndefined, innerClass.descriptor.endOffsetOrUndefined,
DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS, DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS,
descriptor descriptor,
outerClass.defaultType
) )
} }
fun getBridgeDescriptor(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): IrSimpleFunction { fun getLoweredEnum(enumClass: IrClass): LoweredEnum {
val irFunction = overriddenFunctionDescriptor.descriptor assert(enumClass.kind == ClassKind.ENUM_CLASS, { "Expected enum class but was: ${enumClass.descriptor}" })
val descriptor = irFunction.descriptor return loweredEnums.getOrPut(enumClass) {
assert(overriddenFunctionDescriptor.needBridge, enumSpecialDeclarationsFactory.createLoweredEnum(enumClass)
{ "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(enumClassDescriptor: ClassDescriptor): LoweredEnum { private fun assignOrdinalsToEnumEntries(classDescriptor: ClassDescriptor): Map<ClassDescriptor, Int> {
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> {
val enumEntryOrdinals = mutableMapOf<ClassDescriptor, Int>() val enumEntryOrdinals = mutableMapOf<ClassDescriptor, Int>()
irClass.declarations.filterIsInstance<IrEnumEntry>().forEachIndexed { index, entry -> classDescriptor.enumEntries.forEachIndexed { index, entry ->
enumEntryOrdinals[entry.descriptor] = index enumEntryOrdinals[entry] = index
} }
return enumEntryOrdinals return enumEntryOrdinals
} }
@@ -145,54 +120,130 @@ internal class SpecialDeclarationsFactory(val context: Context) {
.first { entryDescriptor.name == enumClassDescriptor.c.nameResolver.getName(it.name) } .first { entryDescriptor.name == enumClassDescriptor.c.nameResolver.getName(it.name) }
.getExtension(KonanLinkData.enumEntryOrdinal) .getExtension(KonanLinkData.enumEntryOrdinal)
} }
val enumClass = context.ir.getEnum(enumClassDescriptor) return ordinals.getOrPut(enumClassDescriptor) { assignOrdinalsToEnumEntries(enumClassDescriptor) }[entryDescriptor]!!
return ordinals.getOrPut(enumClass) { assignOrdinalsToEnumEntries(enumClass) }[entryDescriptor]!!
} }
private fun initializeBridgeDescriptor(bridgeDescriptor: SimpleFunctionDescriptorImpl, fun getBridge(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): IrSimpleFunction {
descriptor: FunctionDescriptor, val irFunction = overriddenFunctionDescriptor.descriptor
bridgeDirections: Array<BridgeDirection>) { assert(overriddenFunctionDescriptor.needBridge,
val returnType = when (bridgeDirections[0]) { { "Function ${irFunction.descriptor} is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor.descriptor}" })
BridgeDirection.TO_VALUE_TYPE -> descriptor.returnType!! val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections
BridgeDirection.NOT_NEEDED -> descriptor.returnType return bridgesDescriptors.getOrPut(irFunction to bridgeDirections) {
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.nullableAnyType 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]) { val extensionReceiverType = when (bridgeDirections.array[1]) {
BridgeDirection.TO_VALUE_TYPE -> descriptor.extensionReceiverParameter!!.type BridgeDirection.TO_VALUE_TYPE -> function.extensionReceiverParameter!!.type
BridgeDirection.NOT_NEEDED -> descriptor.extensionReceiverParameter?.type BridgeDirection.NOT_NEEDED -> function.extensionReceiverParameter?.type
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.nullableAnyType 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 valueParameters = descriptor.valueParameters.mapIndexed { index, valueParameterDescriptor ->
val outType = when (bridgeDirections[index + 2]) { ValueParameterDescriptorImpl(
BridgeDirection.TO_VALUE_TYPE -> valueParameterDescriptor.type
BridgeDirection.NOT_NEEDED -> valueParameterDescriptor.type
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.nullableAnyType
}
ValueParameterDescriptorImpl(
containingDeclaration = valueParameterDescriptor.containingDeclaration, containingDeclaration = valueParameterDescriptor.containingDeclaration,
original = null, original = null,
index = index, index = index,
annotations = Annotations.EMPTY, annotations = Annotations.EMPTY,
name = valueParameterDescriptor.name, name = valueParameterDescriptor.name,
outType = outType, outType = valueParameterTypes[index].toKotlinType(),
declaresDefaultValue = valueParameterDescriptor.declaresDefaultValue(), declaresDefaultValue = valueParameterDescriptor.declaresDefaultValue(),
isCrossinline = valueParameterDescriptor.isCrossinline, isCrossinline = valueParameterDescriptor.isCrossinline,
isNoinline = valueParameterDescriptor.isNoinline, isNoinline = valueParameterDescriptor.isNoinline,
varargElementType = valueParameterDescriptor.varargElementType, varargElementType = valueParameterDescriptor.varargElementType,
source = SourceElement.NO_SOURCE) source = SourceElement.NO_SOURCE)
} }
bridgeDescriptor.initialize( bridgeDescriptor.initialize(
/* receiverParameterType = */ extensionReceiverType, /* receiverParameterType = */ extensionReceiverType?.toKotlinType(),
/* dispatchReceiverParameter = */ descriptor.dispatchReceiverParameter, /* dispatchReceiverParameter = */ descriptor.dispatchReceiverParameter,
/* typeParameters = */ descriptor.typeParameters, /* typeParameters = */ descriptor.typeParameters,
/* unsubstitutedValueParameters = */ valueParameters, /* unsubstitutedValueParameters = */ valueParameters,
/* unsubstitutedReturnType = */ returnType, /* unsubstitutedReturnType = */ returnType.toKotlinType(),
/* modality = */ descriptor.modality, /* modality = */ descriptor.modality,
/* visibility = */ descriptor.visibility).apply { /* visibility = */ descriptor.visibility).apply {
isSuspend = descriptor.isSuspend isSuspend = descriptor.isSuspend
} }
return bridgeDescriptor
} }
} }
@@ -16,10 +16,10 @@
package org.jetbrains.kotlin.backend.konan 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.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.descriptors.enumEntries
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWith
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.* 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.MemberScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.replace
internal object DECLARATION_ORIGIN_ENUM : internal object DECLARATION_ORIGIN_ENUM :
@@ -48,36 +45,45 @@ internal data class LoweredEnum(val implObject: IrClass,
val entriesMap: Map<Name, Int>) val entriesMap: Map<Name, Int>)
internal class EnumSpecialDeclarationsFactory(val context: Context) { 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 startOffset = enumClass.startOffset
val endOffset = enumClassDescriptor.endOffsetOrUndefined val endOffset = enumClass.endOffset
val implObjectDescriptor = ClassDescriptorImpl(enumClassDescriptor, "OBJECT".synthesizedName, Modality.FINAL, val implObjectDescriptor = ClassDescriptorImpl(enumClassDescriptor, "OBJECT".synthesizedName, Modality.FINAL,
ClassKind.OBJECT, listOf(context.builtIns.anyType), SourceElement.NO_SOURCE, false, LockBasedStorageManager.NO_LOCKS) 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 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 valuesGetterDescriptor = createValuesGetterDescriptor(enumClassDescriptor, implObjectDescriptor)
val valuesGetter = IrFunctionImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, valuesGetterDescriptor).apply { val valuesGetter = IrFunctionImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, valuesGetterDescriptor).also {
createParameterDeclarations() it.returnType = valuesType
it.parent = implObject
it.createDispatchReceiverParameter()
} }
val memberScope = MemberScope.Empty val memberScope = MemberScope.Empty
val constructorOfAny = context.builtIns.any.constructors.first() val constructorOfAny = context.irBuiltIns.anyClass.owner.constructors.first()
// TODO: why primary? // 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) implObjectDescriptor.initialize(memberScope, setOf(constructorDescriptor), constructorDescriptor)
val implObject = IrClassImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, implObjectDescriptor).apply { implObject.setSuperSymbolsAndAddFakeOverrides(listOf(context.irBuiltIns.anyType))
createParameterDeclarations() implObject.parent = enumClass
addFakeOverrides()
setSuperSymbols(listOf(context.ir.symbols.any.owner))
}
implObject.parent = context.ir.getEnum(enumClassDescriptor)
valuesGetter.parent = implObject
valuesField.parent = implObject valuesField.parent = implObject
val (itemGetterSymbol, itemGetterDescriptor) = getEnumItemGetter(enumClassDescriptor) val (itemGetterSymbol, itemGetterDescriptor) = getEnumItemGetter(enumClassDescriptor)
@@ -115,7 +121,12 @@ internal class EnumSpecialDeclarationsFactory(val context: Context) {
val receiver = ReceiverParameterDescriptorImpl(implObjectDescriptor, ImplicitClassReceiver(implObjectDescriptor)) val receiver = ReceiverParameterDescriptorImpl(implObjectDescriptor, ImplicitClassReceiver(implObjectDescriptor))
return PropertyDescriptorImpl.create(implObjectDescriptor, Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC, return PropertyDescriptorImpl.create(implObjectDescriptor, Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC,
false, "VALUES".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE, 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 private val genericArrayType = context.ir.symbols.array.descriptor
@@ -79,7 +79,7 @@ fun runTopLevelPhases(konanConfig: KonanConfig, environment: KotlinCoreEnvironme
context.irModule = module context.irModule = module
context.ir.symbols = symbols context.ir.symbols = symbols
validateIrModule(context, module) // validateIrModule(context, module)
} }
phaser.phase(KonanPhase.SERIALIZER) { phaser.phase(KonanPhase.SERIALIZER) {
markBackingFields(context) 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.runOnFilePostfix
import org.jetbrains.kotlin.backend.common.lower.* 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.*
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.InitializersLowering
import org.jetbrains.kotlin.backend.konan.lower.LateinitLowering 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.backend.konan.lower.SharedVariablesLowering
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
@@ -83,12 +79,10 @@ internal class KonanLower(val context: Context) {
} }
val symbolTable = context.ir.symbols.symbolTable val symbolTable = context.ir.symbols.symbolTable
irModule.referenceAllTypeExternalClassifiers(symbolTable)
do { do {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
irModule.replaceUnboundSymbols(context) irModule.replaceUnboundSymbols(context)
irModule.referenceAllTypeExternalClassifiers(symbolTable)
} while (symbolTable.unboundClasses.isNotEmpty()) } while (symbolTable.unboundClasses.isNotEmpty())
irModule.patchDeclarationParents() irModule.patchDeclarationParents()
@@ -17,7 +17,14 @@
package org.jetbrains.kotlin.backend.konan package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.builtins.KotlinBuiltIns 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.name.FqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
/** /**
@@ -96,3 +103,69 @@ val KotlinType.correspondingValueType: ValueType?
get() = ValueType.values().firstOrNull { get() = ValueType.values().firstOrNull {
isRepresentedAs(it) 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 { } else {
descriptor descriptor
} }
context.specialDeclarationsFactory.getBridgeDescriptor(OverriddenFunctionDescriptor(bridgeOwner, overriddenDescriptor)) context.specialDeclarationsFactory.getBridge(OverriddenFunctionDescriptor(bridgeOwner, overriddenDescriptor))
} }
return if (implementation.modality == Modality.ABSTRACT) null else implementation 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.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.SimpleType 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) * 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.common.descriptors.SharedVariablesManager
import org.jetbrains.kotlin.backend.konan.KonanBackendContext 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.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor 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.IrCompositeImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol 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.constructors
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
internal class KonanSharedVariablesManager(val context: KonanBackendContext) : SharedVariablesManager { internal class KonanSharedVariablesManager(val context: KonanBackendContext) : SharedVariablesManager {
@@ -55,7 +56,7 @@ internal class KonanSharedVariablesManager(val context: KonanBackendContext) : S
} }
private fun refType(elementType: KotlinType): KotlinType { 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 { private fun getElementPropertyDescriptor(sharedVariableDescriptor: VariableDescriptor): PropertyDescriptor {
@@ -74,18 +75,19 @@ internal class KonanSharedVariablesManager(val context: KonanBackendContext) : S
false, false, variableDescriptor.source false, false, variableDescriptor.source
) )
val valueType = originalDeclaration.descriptor.type val valueType = originalDeclaration.type
val refConstructorTypeArguments = mapOf(refClassConstructor.descriptor.typeParameters[0] to valueType)
val refConstructorCall = IrCallImpl( val refConstructorCall = IrCallImpl(
originalDeclaration.startOffset, originalDeclaration.endOffset, originalDeclaration.startOffset, originalDeclaration.endOffset,
refClassConstructor, refConstructor(valueType), refConstructorTypeArguments refClass.typeWith(valueType),
) refClassConstructor, refConstructor(valueType.toKotlinType()), 1
).apply {
putTypeArgument(0, valueType)
}
return IrVariableImpl( return IrVariableImpl(
originalDeclaration.startOffset, originalDeclaration.endOffset, originalDeclaration.origin, originalDeclaration.startOffset, originalDeclaration.endOffset, originalDeclaration.origin,
sharedVariableDescriptor sharedVariableDescriptor, refConstructorCall.type
).apply { ).apply {
initializer = refConstructorCall initializer = refConstructorCall
} }
@@ -97,16 +99,18 @@ internal class KonanSharedVariablesManager(val context: KonanBackendContext) : S
val elementPropertyDescriptor = getElementPropertyDescriptor(sharedVariableDeclaration.descriptor) val elementPropertyDescriptor = getElementPropertyDescriptor(sharedVariableDeclaration.descriptor)
val sharedVariableInitialization = val sharedVariableInitialization =
IrCallImpl(initializer.startOffset, initializer.endOffset, elementProperty.setter!!.symbol, IrCallImpl(initializer.startOffset, initializer.endOffset,
context.irBuiltIns.unitType, elementProperty.setter!!.symbol,
elementPropertyDescriptor.setter!!) elementPropertyDescriptor.setter!!)
sharedVariableInitialization.dispatchReceiver = sharedVariableInitialization.dispatchReceiver =
IrGetValueImpl(initializer.startOffset, initializer.endOffset, sharedVariableDeclaration.symbol) IrGetValueImpl(initializer.startOffset, initializer.endOffset,
sharedVariableDeclaration.type, sharedVariableDeclaration.symbol)
sharedVariableInitialization.putValueArgument(0, initializer) sharedVariableInitialization.putValueArgument(0, initializer)
return IrCompositeImpl( return IrCompositeImpl(
originalDeclaration.startOffset, originalDeclaration.endOffset, context.builtIns.unitType, null, originalDeclaration.startOffset, originalDeclaration.endOffset, context.irBuiltIns.unitType, null,
listOf(sharedVariableDeclaration, sharedVariableInitialization) listOf(sharedVariableDeclaration, sharedVariableInitialization)
) )
} }
@@ -115,18 +119,25 @@ internal class KonanSharedVariablesManager(val context: KonanBackendContext) : S
val elementPropertyDescriptor = getElementPropertyDescriptor(sharedVariableSymbol.descriptor) 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 { 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 { override fun setSharedValue(sharedVariableSymbol: IrVariableSymbol, originalSet: IrSetVariable): IrExpression {
val elementPropertyDescriptor = getElementPropertyDescriptor(sharedVariableSymbol.descriptor) val elementPropertyDescriptor = getElementPropertyDescriptor(sharedVariableSymbol.descriptor)
return IrCallImpl(originalSet.startOffset, originalSet.endOffset, elementProperty.setter!!.symbol, return IrCallImpl(originalSet.startOffset, originalSet.endOffset, context.irBuiltIns.unitType,
elementPropertyDescriptor.setter!!).apply { elementProperty.setter!!.symbol, elementPropertyDescriptor.setter!!).apply {
dispatchReceiver = IrGetValueImpl(originalSet.startOffset, originalSet.endOffset, sharedVariableSymbol) dispatchReceiver = IrGetValueImpl(
originalSet.startOffset, originalSet.endOffset,
sharedVariableSymbol.owner.type, sharedVariableSymbol
)
putValueArgument(0, originalSet.value) 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.KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS
import org.jetbrains.kotlin.backend.konan.ValueType import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.descriptors.konanInternal 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.llvm.findMainEntryPoint
import org.jetbrains.kotlin.backend.konan.lower.TestProcessor import org.jetbrains.kotlin.backend.konan.lower.TestProcessor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns 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.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol 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.SymbolTable
import org.jetbrains.kotlin.ir.util.constructors 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.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import kotlin.properties.Delegates import kotlin.properties.Delegates
@@ -58,9 +66,6 @@ internal class KonanIr(context: Context, irModule: IrModuleFragment): Ir<Context
override var symbols: KonanSymbols by Delegates.notNull() 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 { fun get(descriptor: FunctionDescriptor): IrFunction {
return moduleIndexForCodegen.functions[descriptor] return moduleIndexForCodegen.functions[descriptor]
?: symbols.symbolTable.referenceFunction(descriptor).owner ?: symbols.symbolTable.referenceFunction(descriptor).owner
@@ -90,10 +95,35 @@ internal class KonanIr(context: Context, irModule: IrModuleFragment): Ir<Context
?: symbols.symbolTable.referenceEnumEntry(descriptor).owner ?: symbols.symbolTable.referenceEnumEntry(descriptor).owner
} }
fun getEnum(descriptor: ClassDescriptor): IrClass { fun translateErased(type: KotlinType): IrSimpleType = symbols.symbolTable.translateErased(type)
assert(descriptor.kind == ClassKind.ENUM_CLASS)
return originalModuleIndex.classes[descriptor] fun translateBroken(type: KotlinType): IrType {
?: symbols.symbolTable.referenceClass(descriptor).owner 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 throwable = symbolTable.referenceClass(builtIns.throwable)
val string = symbolTable.referenceClass(builtIns.string) val string = symbolTable.referenceClass(builtIns.string)
val enum = symbolTable.referenceClass(builtIns.enum) 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)) val arrayList = symbolTable.referenceClass(getArrayListClassDescriptor(context))
@@ -225,19 +257,25 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
val getProgressionLast = context.getInternalFunctions("getProgressionLast") val getProgressionLast = context.getInternalFunctions("getProgressionLast")
.map { Pair(it.returnType, symbolTable.referenceSimpleFunction(it)) }.toMap() .map { Pair(it.returnType, symbolTable.referenceSimpleFunction(it)) }.toMap()
val arrayContentToString = arrayTypes.associateBy({ it }, { findArrayExtension(it, "contentToString") }) val arrayContentToString = arrays.associateBy(
val arrayContentHashCode = arrayTypes.associateBy({ it }, { findArrayExtension(it, "contentHashCode") }) { it },
{ findArrayExtension(it.descriptor, "contentToString") }
)
val arrayContentHashCode = arrays.associateBy(
{ it },
{ findArrayExtension(it.descriptor, "contentHashCode") }
)
fun findArrayExtension(type: KotlinType, name: String): IrSimpleFunctionSymbol { fun findArrayExtension(descriptor: ClassDescriptor, name: String): IrSimpleFunctionSymbol {
val descriptor = builtInsPackage("kotlin", "collections") val functionDescriptor = builtInsPackage("kotlin", "collections")
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND) .getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND)
.singleOrNull { .singleOrNull {
it.valueParameters.isEmpty() it.valueParameters.isEmpty()
&& (it.extensionReceiverParameter?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.defaultType == type && it.extensionReceiverParameter?.type?.constructor?.declarationDescriptor == descriptor
&& !it.isExpect && !it.isExpect
} }
?: throw Error(type.toString()) ?: throw Error(descriptor.toString())
return symbolTable.referenceSimpleFunction(descriptor) return symbolTable.referenceSimpleFunction(functionDescriptor)
} }
override val copyRangeTo = arrays.map { symbol -> 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) val kFunctions = (0 .. KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS)
.map { symbolTable.referenceClass(context.reflectionTypes.getKFunction(it)) } .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) val suspendFunctions = (0 .. KONAN_FUNCTION_INTERFACES_MAX_PARAMETERS)
.map { symbolTable.referenceClass(builtIns.getSuspendFunction(it)) } .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.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol 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.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.file.File
@@ -148,7 +149,7 @@ interface IrSuspendableExpression : IrExpression {
var result: 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 suspensionPointIdParameter: IrVariable,
override var result: IrExpression, override var result: IrExpression,
override var resumeResult: 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) override var suspensionPointId: IrExpression, override var result: IrExpression)
: IrExpressionBase(startOffset, endOffset, type), IrSuspendableExpression { : IrExpressionBase(startOffset, endOffset, type), IrSuspendableExpression {
@@ -198,7 +199,7 @@ internal interface IrPrivateFunctionCall : IrCall {
internal class IrPrivateFunctionCallImpl(startOffset: Int, internal class IrPrivateFunctionCallImpl(startOffset: Int,
endOffset: Int, endOffset: Int,
type: KotlinType, type: IrType,
override val symbol: IrFunctionSymbol, override val symbol: IrFunctionSymbol,
override val descriptor: FunctionDescriptor, override val descriptor: FunctionDescriptor,
override val virtualCallee: IrCall?, override val virtualCallee: IrCall?,
@@ -235,9 +236,9 @@ internal interface IrPrivateClassReference : IrClassReference {
internal class IrPrivateClassReferenceImpl(startOffset: Int, internal class IrPrivateClassReferenceImpl(startOffset: Int,
endOffset: Int, endOffset: Int,
type: KotlinType, type: IrType,
symbol: IrClassifierSymbol, symbol: IrClassifierSymbol,
override val classType: KotlinType, override val classType: IrType,
override val moduleDescriptor: ModuleDescriptor, override val moduleDescriptor: ModuleDescriptor,
override val totalClasses: Int, override val totalClasses: Int,
override val classIndex: 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.*
import org.jetbrains.kotlin.backend.konan.llvm.llvmSymbolOrigin import org.jetbrains.kotlin.backend.konan.llvm.llvmSymbolOrigin
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.idea.MainFunctionDetector import org.jetbrains.kotlin.idea.MainFunctionDetector
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils 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 import org.jetbrains.kotlin.resolve.descriptorUtil.module
// This file contains some IR utilities which actually use descriptors. // This file contains some IR utilities which actually use descriptors.
// TODO: port this code to IR. // 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 IrDeclaration.isAnonymousObject get() = DescriptorUtils.isAnonymousObject(this.descriptor)
internal val IrFunction.isExternal get() = this.descriptor.isExternal internal val IrFunction.isExternal get() = this.descriptor.isExternal
internal val IrDeclaration.isLocal get() = DescriptorUtils.isLocal(this.descriptor) 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 IrFunction.isMain() = MainFunctionDetector.isMain(this.descriptor)
internal fun IrTypeOperatorCall.getTypeOperandClass(context: Context): IrClass? = internal fun IrType.isObjCObjectType() = this.toKotlinType().isObjCObjectType()
context.ir.getClass(this.typeOperand)
internal fun IrCatch.getCatchParameterTypeClass(context: Context): IrClass? =
context.ir.getClass(this.catchParameter.type)
@@ -27,5 +27,7 @@ internal typealias ConstructorDescriptor = IrConstructor
internal typealias ClassConstructorDescriptor = IrConstructor internal typealias ClassConstructorDescriptor = IrConstructor
internal typealias PackageFragmentDescriptor = IrPackageFragment internal typealias PackageFragmentDescriptor = IrPackageFragment
internal typealias VariableDescriptor = IrVariable internal typealias VariableDescriptor = IrVariable
internal typealias ValueDescriptor = IrSymbolDeclaration<IrValueSymbol> internal typealias ValueDescriptor = IrValueDeclaration
internal typealias ParameterDescriptor = IrValueParameter 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.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities 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.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.expressions.getTypeArgumentOrDefault import org.jetbrains.kotlin.ir.util.explicitParameters
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.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name 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.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 val IrConstructor.constructedClass get() = this.parent as IrClass
@@ -88,26 +75,6 @@ val IrFunction.allParameters: List<IrValueParameter>
explicitParameters 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 IrValueParameter.isVararg get() = this.varargElementType != null
val IrFunction.isSuspend get() = this is IrSimpleFunction && this.isSuspend 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() 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.getSuperClassNotAny() = this.superClasses.map { it.owner }.atMostOne { !it.isInterface && !it.isAny() }
fun IrClass.isAny() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.any.toSafe() fun IrClass.isAny() = this.fqNameSafe == KotlinBuiltIns.FQ_NAMES.any.toSafe()
@@ -132,7 +100,8 @@ val IrProperty.konanBackingField: IrField?
this.startOffset, this.startOffset,
this.endOffset, this.endOffset,
IrDeclarationOrigin.PROPERTY_BACKING_FIELD, 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 { ).also {
it.parent = this.parent it.parent = this.parent
} }
@@ -143,9 +112,6 @@ val IrProperty.konanBackingField: IrField?
return null return null
} }
val IrClass.defaultType: KotlinType
get() = this.thisReceiver!!.type
val IrField.containingClass get() = this.parent as? IrClass val IrField.containingClass get() = this.parent as? IrClass
val IrFunction.isReal get() = this.origin != IrDeclarationOrigin.FAKE_OVERRIDE 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() fun IrClass.isSpecialClassWithNoSupertypes() = this.isAny() || this.isNothing()
val IrClass.constructors get() = this.declarations.filterIsInstance<IrConstructor>()
internal val IrValueParameter.isValueParameter get() = this.index >= 0 internal val IrValueParameter.isValueParameter get() = this.index >= 0
fun IrModuleFragment.referenceAllTypeExternalClassifiers(symbolTable: SymbolTable) { private val IrCall.annotationClass
val moduleDescriptor = this.descriptor get() = (this.symbol.owner as IrConstructor).constructedClass
fun KotlinType.referenceAllClassifiers() { fun List<IrCall>.hasAnnotation(fqName: FqName): Boolean =
TypeUtils.getClassDescriptor(this)?.let { this.any { it.annotationClass.fqNameSafe == fqName }
if (!ErrorUtils.isError(it) && it.module != moduleDescriptor) {
if (it.kind == ClassKind.ENUM_ENTRY) {
symbolTable.referenceEnumEntry(it)
} else {
symbolTable.referenceClass(it)
}
}
}
this.constructor.supertypes.forEach { fun IrAnnotationContainer.hasAnnotation(fqName: FqName) =
it.referenceAllClassifiers() this.annotations.hasAnnotation(fqName)
}
}
val visitor = object : IrElementVisitorVoid { fun List<IrCall>.findAnnotation(fqName: FqName): IrCall? = this.firstOrNull {
override fun visitElement(element: IrElement) { it.annotationClass.fqNameSafe == fqName
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)
}
}
}
@@ -17,25 +17,19 @@
package org.jetbrains.kotlin.backend.konan.llvm package org.jetbrains.kotlin.backend.konan.llvm
import llvm.LLVMTypeRef 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.descriptors.isAbstract
import org.jetbrains.kotlin.backend.konan.irasdescriptors.* import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.isValueType import org.jetbrains.kotlin.backend.konan.isValueType
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR 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.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.declarations.* 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.name.FqName
import org.jetbrains.kotlin.resolve.constants.StringValue 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 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 val inlineExposedAnnotation = FqName("kotlin.internal.InlineExposed")
private fun acyclicTypeMangler(visited: MutableSet<TypeParameterDescriptor>, type: KotlinType): String { private fun acyclicTypeMangler(visited: MutableSet<TypeParameterDescriptor>, type: IrType): String {
val descriptor = TypeUtils.getTypeParameterDescriptorOrNull(type) val descriptor = (type.classifierOrNull as? IrTypeParameterSymbol)?.owner
if (descriptor != null) { if (descriptor != null) {
val upperBounds = if (visited.contains(descriptor)) "" else { val upperBounds = if (visited.contains(descriptor)) "" else {
visited.add(descriptor) visited.add(descriptor)
descriptor.upperBounds.map { descriptor.superTypes.map {
val bound = acyclicTypeMangler(visited, it) val bound = acyclicTypeMangler(visited, it)
if (bound == "kotlin.Any?") "" else "_$bound" if (bound == "kotlin.Any?") "" else "_$bound"
}.joinToString("") }.joinToString("")
@@ -143,24 +137,27 @@ private fun acyclicTypeMangler(visited: MutableSet<TypeParameterDescriptor>, typ
return "#GENERIC" + upperBounds 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()) { if (!type.arguments.isEmpty()) {
hashString += "<${type.arguments.map { hashString += "<${type.arguments.map {
if (it.isStarProjection()) { when (it) {
"#STAR" is IrStarProjection -> "#STAR"
} else { is IrTypeProjection -> {
val variance = it.projectionKind.label val variance = it.variance.label
val projection = if (variance == "") "" else "${variance}_" val projection = if (variance == "") "" else "${variance}_"
projection + acyclicTypeMangler(visited, it.type) projection + acyclicTypeMangler(visited, it.type)
}
else -> error(it)
} }
}.joinToString(",")}>" }.joinToString(",")}>"
} }
if (type.isMarkedNullable) hashString += "?" if (type.hasQuestionMark) hashString += "?"
return hashString return hashString
} }
private fun typeToHashString(type: KotlinType) private fun typeToHashString(type: IrType)
= acyclicTypeMangler(mutableSetOf<TypeParameterDescriptor>(), type) = acyclicTypeMangler(mutableSetOf<TypeParameterDescriptor>(), type)
private val FunctionDescriptor.signature: String private val FunctionDescriptor.signature: String
@@ -175,7 +172,7 @@ private val FunctionDescriptor.signature: String
when { when {
this.typeParameters.isNotEmpty() -> "Generic" this.typeParameters.isNotEmpty() -> "Generic"
returnType.isValueType() -> "ValueType" returnType.isValueType() -> "ValueType"
!KotlinBuiltIns.isUnitOrNullableUnit(returnType) -> typeToHashString(returnType) !returnType.isUnitOrNullableUnit() -> typeToHashString(returnType)
else -> "" else -> ""
} }
return "$extensionReceiverPart($argsPart)$signatureSuffix" return "$extensionReceiverPart($argsPart)$signatureSuffix"
@@ -188,7 +185,7 @@ internal val FunctionDescriptor.functionName: String
this.getObjCMethodInfo()?.let { this.getObjCMethodInfo()?.let {
return buildString { return buildString {
if (extensionReceiverParameter != null) { if (extensionReceiverParameter != null) {
append(TypeUtils.getClassDescriptor(extensionReceiverParameter!!.type)!!.name) append(extensionReceiverParameter!!.type.getClass()!!.name)
append(".") 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 { return annotation.allValueArguments.values.ifNotEmpty {
val stringValue = single() as? StringValue val stringValue = single() as? StringValue
stringValue?.value stringValue?.value
@@ -25,6 +25,8 @@ import org.jetbrains.kotlin.backend.konan.descriptors.stdlibModule
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.backend.konan.irasdescriptors.* import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.llvm.objc.ObjCDataGenerator 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 import org.jetbrains.kotlin.konan.target.KonanTarget
internal class CodeGenerator(override val context: Context) : ContextUtils { 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 { fun getEnumEntry(descriptor: IrEnumEntry, exceptionHandler: ExceptionHandler): LLVMValueRef {
val enumClassDescriptor = descriptor.containingDeclaration as ClassDescriptor 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 ordinal = loweredEnum.entriesMap[descriptor.name]!!
val values = call( val values = call(
@@ -20,9 +20,8 @@ import llvm.*
import org.jetbrains.kotlin.backend.konan.ValueType import org.jetbrains.kotlin.backend.konan.ValueType
import org.jetbrains.kotlin.backend.konan.isRepresentedAs import org.jetbrains.kotlin.backend.konan.isRepresentedAs
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.types.typeUtil.isNothing import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.types.typeUtil.isUnit
private val valueTypes = ValueType.values().associate { private val valueTypes = ValueType.values().associate {
it to when (it) { it to when (it) {
@@ -41,7 +40,7 @@ private val valueTypes = ValueType.values().associate {
internal val ValueType.llvmType internal val ValueType.llvmType
get() = valueTypes[this]!! get() = valueTypes[this]!!
internal fun RuntimeAware.getLLVMType(type: KotlinType): LLVMTypeRef { internal fun RuntimeAware.getLLVMType(type: IrType): LLVMTypeRef {
for ((valueType, llvmType) in valueTypes) { for ((valueType, llvmType) in valueTypes) {
if (type.isRepresentedAs(valueType)) { if (type.isRepresentedAs(valueType)) {
return llvmType return llvmType
@@ -54,13 +53,11 @@ internal fun RuntimeAware.getLLVMType(type: KotlinType): LLVMTypeRef {
internal fun RuntimeAware.getLLVMType(type: DataFlowIR.Type) = internal fun RuntimeAware.getLLVMType(type: DataFlowIR.Type) =
type.correspondingValueType?.let { valueTypes[it]!! } ?: this.kObjHeaderPtr type.correspondingValueType?.let { valueTypes[it]!! } ?: this.kObjHeaderPtr
internal fun RuntimeAware.getLLVMReturnType(type: KotlinType): LLVMTypeRef { internal fun RuntimeAware.getLLVMReturnType(type: IrType): LLVMTypeRef {
return when { return when {
type.isUnit() -> LLVMVoidType()!! type.isUnit() -> LLVMVoidType()!!
// TODO: stdlib have methods taking Nothing, such as kotlin.collections.EmptySet.contains(). // TODO: stdlib have methods taking Nothing, such as kotlin.collections.EmptySet.contains().
// KotlinBuiltIns.isNothing(type) -> LLVMVoidType() // KotlinBuiltIns.isNothing(type) -> LLVMVoidType()
else -> getLLVMType(type) 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> internal val FunctionDescriptor.types:List<KotlinType>
get() { get() {
val parameters = valueParameters.map{it.type} val parameters = descriptor.valueParameters.map{it.type}
return listOf(returnType, *parameters.toTypedArray()) return listOf(descriptor.returnType!!, *parameters.toTypedArray())
} }
internal fun KotlinType.size(context:Context) = context.debugInfo.llvmTypeSizes.getOrDefault(this, context.debugInfo.otherTypeSize) 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.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.optimizations.* import org.jetbrains.kotlin.backend.konan.optimizations.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrElement 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.*
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
import org.jetbrains.kotlin.ir.symbols.* 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.util.getArguments
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid 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.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe 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 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 * Creates new [ContinuationBlock] that receives the value of given Kotlin type
* and generates [code] starting from its beginning. * and generates [code] starting from its beginning.
*/ */
private fun continuationBlock(type: KotlinType, private fun continuationBlock(type: IrType,
locationInfo: LocationInfo?, code: (ContinuationBlock) -> Unit = {}): ContinuationBlock { locationInfo: LocationInfo?, code: (ContinuationBlock) -> Unit = {}): ContinuationBlock {
val entry = functionGenerationContext.basicBlock("continuation_block", locationInfo) 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") 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. // 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). // 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 { private val handler by lazy {
using(outerContext) { using(outerContext) {
continuationBlock(context.builtIns.throwable.defaultType, endLocationInfoFromScope()) { continuationBlock(context.ir.symbols.throwable.owner.defaultType, endLocationInfoFromScope()) {
genHandler(it.value) genHandler(it.value)
} }
} }
@@ -1008,7 +1004,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
genCatchBlock() genCatchBlock()
return // Remaining catch clauses are unreachable. return // Remaining catch clauses are unreachable.
} else { } else {
val isInstance = genInstanceOf(exception, catch.getCatchParameterTypeClass(context)!!) val isInstance = genInstanceOf(exception, catch.catchParameter.type.getClass()!!)
val body = functionGenerationContext.basicBlock("catch", catch.startLocation) val body = functionGenerationContext.basicBlock("catch", catch.startLocation)
val nextCheck = functionGenerationContext.basicBlock("catchCheck", catch.endLocation) val nextCheck = functionGenerationContext.basicBlock("catchCheck", catch.endLocation)
functionGenerationContext.condBr(isInstance, body, nextCheck) 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 { private fun evaluateWhen(expression: IrWhen): LLVMValueRef {
context.log{"evaluateWhen : ${ir2string(expression)}"} context.log{"evaluateWhen : ${ir2string(expression)}"}
var bbExit: LLVMBasicBlockRef? = null // By default "when" does not have "exit". var bbExit: LLVMBasicBlockRef? = null // By default "when" does not have "exit".
val isUnit = KotlinBuiltIns.isUnit(expression.type) val isUnit = expression.type.isUnit()
val isNothing = KotlinBuiltIns.isNothing(expression.type) val isNothing = expression.type.isNothing()
// We may not cover all cases if IrWhen is used as statement. // We may not cover all cases if IrWhen is used as statement.
val coverAllCases = isUnconditional(expression.branches.last()) 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 { private fun evaluateGetValue(value: IrGetValue): LLVMValueRef {
context.log{"evaluateGetValue : ${ir2string(value)}"} context.log{"evaluateGetValue : ${ir2string(value)}"}
val symbol = value.symbol return currentCodeContext.genGetValue(value.symbol.owner)
val ir: IrSymbolDeclaration<IrValueSymbol> = when (symbol) {
is IrVariableSymbol -> symbol.owner
is IrValueParameterSymbol -> symbol.owner
else -> error(symbol)
}
return currentCodeContext.genGetValue(ir)
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -1221,11 +1210,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun KotlinType.isPrimitiveInteger(): Boolean { private fun IrType.isPrimitiveInteger(): Boolean {
return isPrimitiveNumberType() && return this.isPrimitiveType() &&
!KotlinBuiltIns.isFloat(this) && !this.isBoolean() &&
!KotlinBuiltIns.isDouble(this) && !this.isFloat() &&
!KotlinBuiltIns.isChar(this) !this.isDouble() &&
!this.isChar()
} }
private fun evaluateIntegerCoercion(value: IrTypeOperatorCall): LLVMValueRef { 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 { private fun evaluateCast(value: IrTypeOperatorCall): LLVMValueRef {
context.log{"evaluateCast : ${ir2string(value)}"} context.log{"evaluateCast : ${ir2string(value)}"}
val dstDescriptor = value.getTypeOperandClass(context)!! val dstDescriptor = value.typeOperand.getClass()!!
assert(!KotlinBuiltIns.isPrimitiveType(dstDescriptor.defaultType) && assert(!dstDescriptor.defaultType.isValueType() &&
!KotlinBuiltIns.isPrimitiveType(value.argument.type)) !value.argument.type.isValueType())
val srcArg = evaluateExpression(value.argument) // Evaluate src expression. 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.condBr(condition, bbNull, bbInstanceOf)
functionGenerationContext.positionAtEnd(bbNull) functionGenerationContext.positionAtEnd(bbNull)
val resultNull = if (TypeUtils.isNullableType(type)) kTrue else kFalse val resultNull = if (type.containsNull()) kTrue else kFalse
functionGenerationContext.br(bbExit) functionGenerationContext.br(bbExit)
functionGenerationContext.positionAtEnd(bbInstanceOf) functionGenerationContext.positionAtEnd(bbInstanceOf)
val typeOperandClass = value.getTypeOperandClass(context) val typeOperandClass = value.typeOperand.getClass()
val resultInstanceOf = if (typeOperandClass != null) { val resultInstanceOf = if (typeOperandClass != null) {
genInstanceOf(srcArg, typeOperandClass) genInstanceOf(srcArg, typeOperandClass)
} else { } 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. * 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 { private fun evaluateFunctionReference(expression: IrFunctionReference): LLVMValueRef {
// TODO: consider creating separate IR element for pointer to function. // 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()) 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 { private fun evaluateIntrinsicCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
val descriptor = callee.descriptor.original val descriptor = callee.descriptor.original
val function = callee.symbol.owner
val name = descriptor.fqNameUnsafe.asString() val name = descriptor.fqNameUnsafe.asString()
when (name) { when (name) {
@@ -2137,13 +2128,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
interop.nativePointedGetRawPointer, interop.cPointerGetRawValue -> args.single() interop.nativePointedGetRawPointer, interop.cPointerGetRawValue -> args.single()
in interop.readPrimitive -> { in interop.readPrimitive -> {
val pointerType = pointerType(codegen.getLLVMType(descriptor.returnType!!)) val pointerType = pointerType(codegen.getLLVMType(function.returnType))
val rawPointer = args.last() val rawPointer = args.last()
val pointer = functionGenerationContext.bitcast(pointerType, rawPointer) val pointer = functionGenerationContext.bitcast(pointerType, rawPointer)
functionGenerationContext.load(pointer) functionGenerationContext.load(pointer)
} }
in interop.writePrimitive -> { 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 rawPointer = args[1]
val pointer = functionGenerationContext.bitcast(pointerType, rawPointer) val pointer = functionGenerationContext.bitcast(pointerType, rawPointer)
functionGenerationContext.store(args[2], pointer) 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 interop.getPointerSize -> Int32(LLVMPointerSize(codegen.llvmTargetData)).llvm
context.builtIns.nativePtrToLong -> { context.builtIns.nativePtrToLong -> {
val intPtrValue = functionGenerationContext.ptrToInt(args.single(), codegen.intPtrType) val intPtrValue = functionGenerationContext.ptrToInt(args.single(), codegen.intPtrType)
val resultType = functionGenerationContext.getLLVMType(descriptor.returnType!!) val resultType = functionGenerationContext.getLLVMType(function.returnType)
if (resultType == intPtrValue.type) { if (resultType == intPtrValue.type) {
intPtrValue intPtrValue
@@ -2169,7 +2160,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
interop.getObjCClass -> { interop.getObjCClass -> {
val typeArgument = callee.getTypeArgument(descriptor.typeParameters.single()) val typeArgument = callee.getTypeArgument(descriptor.typeParameters.single())
val irClass = context.ir.getClass(typeArgument!!)!! val irClass = typeArgument!!.getClass()!!
genGetObjCClass(irClass) genGetObjCClass(irClass)
} }
@@ -2184,8 +2175,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
interop.writeBits -> genWriteBits(args) interop.writeBits -> genWriteBits(args)
context.ir.symbols.getClassTypeInfo.descriptor -> { context.ir.symbols.getClassTypeInfo.descriptor -> {
val typeArgument = callee.getTypeArgumentOrDefault(descriptor.typeParameters.single()) val typeArgument = callee.getTypeArgument(0)!!
val typeArgumentClass = context.ir.getClass(typeArgument) val typeArgumentClass = typeArgument.getClass()
if (typeArgumentClass == null) { if (typeArgumentClass == null) {
// E.g. for `T::class` in a body of an inline function itself. // E.g. for `T::class` in a body of an inline function itself.
functionGenerationContext.unreachable() functionGenerationContext.unreachable()
@@ -2202,7 +2193,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
context.ir.symbols.createUninitializedInstance.descriptor -> { context.ir.symbols.createUninitializedInstance.descriptor -> {
val typeParameterT = context.ir.symbols.createUninitializedInstance.descriptor.typeParameters[0] val typeParameterT = context.ir.symbols.createUninitializedInstance.descriptor.typeParameters[0]
val enumClass = callee.getTypeArgument(typeParameterT)!! val enumClass = callee.getTypeArgument(typeParameterT)!!
val enumIrClass = context.ir.getClass(enumClass)!! val enumIrClass = enumClass.getClass()!!
functionGenerationContext.allocInstance(enumIrClass, resultLifetime(callee)) 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.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction 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.ir.util.simpleFunctions
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe 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.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* 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.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.name.FqName 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 { private fun ContextUtils.createClassBodyType(name: String, fields: List<IrField>): LLVMTypeRef {
val fieldTypes = fields.map { val fieldTypes = fields.map {
@Suppress("DEPRECATION") @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)!! 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?) { private fun exportTypeInfoIfRequired(classDesc: ClassDescriptor, typeInfoGlobal: LLVMValueRef?) {
val annot = classDesc.descriptor.annotations.findAnnotation(FqName("konan.ExportTypeInfo")) val annot = classDesc.descriptor.annotations.findAnnotation(FqName("konan.ExportTypeInfo"))
if (annot != null) { if (annot != null) {
val nameValue = annot.allValueArguments.values.single() as StringValue val name = getStringValue(annot)!!
// TODO: use LLVMAddAlias? // 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) LLVMSetInitializer(global, typeInfoGlobal)
} }
} }
@@ -18,9 +18,6 @@ package org.jetbrains.kotlin.backend.konan.llvm
import kotlinx.cinterop.* import kotlinx.cinterop.*
import llvm.* import llvm.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit
interface RuntimeAware { interface RuntimeAware {
val runtime: Runtime val runtime: Runtime
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.backend.konan.llvm
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.types.KotlinType
/** /**
* Provides utilities to create static data. * Provides utilities to create static data.
@@ -20,7 +20,6 @@ import llvm.LLVMLinkage
import llvm.LLVMSetLinkage import llvm.LLVMSetLinkage
import llvm.LLVMTypeRef import llvm.LLVMTypeRef
import llvm.LLVMValueRef 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.fqNameSafe
import org.jetbrains.kotlin.backend.konan.irasdescriptors.llvmSymbolOrigin import org.jetbrains.kotlin.backend.konan.irasdescriptors.llvmSymbolOrigin
import org.jetbrains.kotlin.descriptors.ClassDescriptor 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.ir.declarations.IrClass
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name 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 { 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) 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 llvm.*
import org.jetbrains.kotlin.backend.konan.descriptors.CurrentKonanModule import org.jetbrains.kotlin.backend.konan.descriptors.CurrentKonanModule
import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.util.OperatorNameConventions 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`. // TODO: consider also overriding methods of `Any`.
val numberOfParameters = invokeMethod.valueParameters.size val numberOfParameters = invokeMethod.valueParameters.size
val function = generateFunction( val function = generateFunction(
codegen, codegen,
codegen.getLlvmFunctionType(context.ir.get(invokeMethod)), codegen.getLlvmFunctionType(invokeMethod),
"invokeFunction$numberOfParameters" "invokeFunction$numberOfParameters"
) { ) {
val args = (0 until numberOfParameters).map { index -> kotlinReferenceToObjC(param(index + 1)) } 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>() val invokeMethod = irInterface.declarations.filterIsInstance<IrSimpleFunction>()
.single { it.name == OperatorNameConventions.INVOKE } .single { it.name == OperatorNameConventions.INVOKE }
val invokeImpl = generateKotlinFunctionImpl(invokeMethod.descriptor) val invokeImpl = generateKotlinFunctionImpl(invokeMethod)
return rttiGenerator.generateSyntheticInterfaceImpl( return rttiGenerator.generateSyntheticInterfaceImpl(
irInterface, 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.AbstractValueUsageTransformer
import org.jetbrains.kotlin.backend.common.FileLoweringPass 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.*
import org.jetbrains.kotlin.backend.konan.descriptors.target 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.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction 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.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl 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.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid 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. * 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) { private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTransformer(
context.builtIns,
val symbols = context.ir.symbols context.ir.symbols,
context.irBuiltIns
) {
// TODO: should we handle the cases when expression type // TODO: should we handle the cases when expression type
// is not equal to e.g. called function return 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`) * @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 { ValueType.values().forEach {
if (type.notNullableIsRepresentedAs(it)) { if (type.notNullableIsRepresentedAs(it)) {
return getBoxType(it).makeNullableAsSpecified(TypeUtils.isNullableType(type)) return getBoxType(it).makeNullableAsSpecified(type.containsNull())
} }
} }
return type 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 || return if (operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT ||
operator == IrTypeOperator.IMPLICIT_INTEGER_COERCION) { operator == IrTypeOperator.IMPLICIT_INTEGER_COERCION) {
this this
} else { } else {
// Codegen expects the argument of type-checking operator to be an object reference: // 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 newTypeOperand = getRuntimeReferenceType(expression.typeOperand)
val newTypeOperandClassifier = newTypeOperand.classifierOrFail
return when (expression.operator) { return when (expression.operator) {
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
@@ -101,7 +107,7 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
} }
IrTypeOperatorCallImpl(expression.startOffset, expression.endOffset, IrTypeOperatorCallImpl(expression.startOffset, expression.endOffset,
newExpressionType, expression.operator, newTypeOperand, newExpressionType, expression.operator, newTypeOperand, newTypeOperandClassifier,
expression.argument).useAs(expression.type) expression.argument).useAs(expression.type)
} }
@@ -110,40 +116,49 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
expression expression
} else { } else {
IrTypeOperatorCallImpl(expression.startOffset, expression.endOffset, 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 { override fun visitFunction(declaration: IrFunction): IrStatement {
currentFunctionDescriptor = declaration.descriptor currentFunctionDescriptor = declaration
val result = super.visitFunction(declaration) val result = super.visitFunction(declaration)
currentFunctionDescriptor = null currentFunctionDescriptor = null
return result return result
} }
override fun IrExpression.useAsReturnValue(returnTarget: CallableDescriptor): IrExpression { override fun IrExpression.useAsReturnValue(returnTarget: IrReturnTargetSymbol): IrExpression = when (returnTarget) {
if (returnTarget.isSuspend && returnTarget == currentFunctionDescriptor) is IrSimpleFunctionSymbol -> if (returnTarget.owner.isSuspend && returnTarget == currentFunctionDescriptor?.symbol) {
return this.useAs(context.builtIns.nullableAnyType) this.useAs(irBuiltIns.anyNType)
val returnType = returnTarget.returnType } else {
?: return this this.useAs(returnTarget.owner.returnType)
return this.useAs(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 val interop = context.interopBuiltIns
if (this.isNullConst() && interop.nullableInteropValueTypes.any { type.isRepresentedAs(it) }) { 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) { val actualType = when (this) {
is IrCall -> { is IrCall -> {
if (this.descriptor.isSuspend) context.builtIns.nullableAnyType if (this.symbol.owner.isSuspend) irBuiltIns.anyNType
else this.callTarget.returnType ?: this.type else this.callTarget.returnType
} }
is IrGetField -> this.descriptor.original.type is IrGetField -> this.symbol.owner.type
is IrTypeOperatorCall -> when (this.operator) { is IrTypeOperatorCall -> when (this.operator) {
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> IrTypeOperator.IMPLICIT_INTEGER_COERCION ->
@@ -159,65 +174,63 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
return this.adaptIfNecessary(actualType, type) 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 IrCall -> this.callTarget
is IrDelegatingConstructorCall -> this.descriptor.original is IrDelegatingConstructorCall -> this.symbol.owner
else -> TODO(this.render()) else -> TODO(this.render())
} }
private val IrCall.callTarget: FunctionDescriptor private val IrCall.callTarget: IrFunction
get() = if (superQualifier == null && descriptor.isOverridable) { get() = if (superQualifier == null && symbol.owner.isOverridable) {
// A virtual call. // A virtual call.
descriptor.original symbol.owner
} else { } 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!!) 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!!) return this.useAsArgument(expression.target.extensionReceiverParameter!!)
} }
override fun IrExpression.useAsValueArgument(expression: IrMemberAccessExpression, override fun IrExpression.useAsValueArgument(expression: IrFunctionAccessExpression,
parameter: ValueParameterDescriptor): IrExpression { parameter: IrValueParameter): IrExpression {
return this.useAsArgument(expression.target.valueParameters[parameter.index]) return this.useAsArgument(expression.target.valueParameters[parameter.index])
} }
override fun IrExpression.useForField(field: PropertyDescriptor): IrExpression { private fun IrExpression.adaptIfNecessary(actualType: IrType, expectedType: IrType): IrExpression {
return this.useForVariable(field.original)
}
private fun IrExpression.adaptIfNecessary(actualType: KotlinType, expectedType: KotlinType): IrExpression {
val conversion = symbols.getTypeConversion(actualType, expectedType) val conversion = symbols.getTypeConversion(actualType, expectedType)
return if (conversion == null) { return if (conversion == null) {
this this
} else { } else {
val parameter = conversion.descriptor.explicitParameters.single() val parameter = conversion.owner.explicitParameters.single()
val argument = this.uncheckedCast(parameter.type) val argument = this.uncheckedCast(parameter.type)
IrCallImpl(startOffset, endOffset, conversion).apply { IrCallImpl(startOffset, endOffset, conversion.owner.returnType, conversion).apply {
addArguments(listOf(parameter to argument)) addArguments(mapOf(parameter to argument))
}.uncheckedCast(this.type) // Try not to bring new type incompatibilities. }.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. * Casts this expression to `type` without changing its representation in generated code.
*/ */
@Suppress("UNUSED_PARAMETER") @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. // TODO: apply some cast if types are incompatible; not required currently.
return this return this
} }
private val ValueType.shortName private fun getBoxType(valueType: ValueType) = symbols.boxClasses[valueType]!!.owner.defaultType
get() = this.classFqName.shortName()
private fun getBoxType(valueType: ValueType) =
context.getInternalClass("${valueType.shortName}Box").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.common.lower.irIfThen
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl 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.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol 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.simpleFunctions
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
import org.jetbrains.kotlin.types.KotlinType
internal class WorkersBridgesBuilding(val context: Context) : DeclarationContainerLoweringPass, IrElementTransformerVoid() { internal class WorkersBridgesBuilding(val context: Context) : DeclarationContainerLoweringPass, IrElementTransformerVoid() {
@@ -100,7 +101,16 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
IrDeclarationOrigin.DEFINED, IrDeclarationOrigin.DEFINED,
runtimeJobDescriptor runtimeJobDescriptor
).also { ).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) val overriddenJobDescriptor = OverriddenFunctionDescriptor(jobFunction, runtimeJobFunction)
@@ -118,7 +128,7 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
type = job.type, type = job.type,
symbol = bridge.symbol, symbol = bridge.symbol,
descriptor = bridge.descriptor, descriptor = bridge.descriptor,
typeArguments = null) typeArgumentsCount = 0)
) )
return expression return expression
} }
@@ -158,7 +168,7 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass {
val irBuilder = context.createIrBuilder(declaration.symbol, declaration.startOffset, declaration.endOffset) val irBuilder = context.createIrBuilder(declaration.symbol, declaration.startOffset, declaration.endOffset)
declaration.body = irBuilder.irBlockBody(declaration) { declaration.body = irBuilder.irBlockBody(declaration) {
buildTypeSafeBarrier(declaration, descriptor, typeSafeBarrierDescription) buildTypeSafeBarrier(declaration, declaration, typeSafeBarrierDescription)
body.statements.forEach { +it } body.statements.forEach { +it }
} }
return declaration return declaration
@@ -187,7 +197,7 @@ internal val IrFunction.bridgeTarget: IrFunction?
get() = (origin as? DECLARATION_ORIGIN_BRIDGE_METHOD)?.bridgeTarget get() = (origin as? DECLARATION_ORIGIN_BRIDGE_METHOD)?.bridgeTarget
private fun IrBuilderWithScope.returnIfBadType(value: IrExpression, private fun IrBuilderWithScope.returnIfBadType(value: IrExpression,
type: KotlinType, type: IrType,
returnValueOnFail: IrExpression) returnValueOnFail: IrExpression)
= irIfThen(irNotIs(value, type), irReturn(returnValueOnFail)) = irIfThen(irNotIs(value, type), irReturn(returnValueOnFail))
@@ -199,18 +209,18 @@ private fun IrBuilderWithScope.irConst(value: Any?) = when (value) {
} }
private fun IrBlockBodyBuilder.buildTypeSafeBarrier(function: IrFunction, private fun IrBlockBodyBuilder.buildTypeSafeBarrier(function: IrFunction,
originalDescriptor: FunctionDescriptor, originalFunction: IrFunction,
typeSafeBarrierDescription: BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription) { typeSafeBarrierDescription: BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription) {
val valueParameters = function.valueParameters val valueParameters = function.valueParameters
val originalValueParameters = originalDescriptor.valueParameters val originalValueParameters = originalFunction.valueParameters
for (i in valueParameters.indices) { for (i in valueParameters.indices) {
if (!typeSafeBarrierDescription.checkParameter(i)) if (!typeSafeBarrierDescription.checkParameter(i))
continue continue
val type = originalValueParameters[i].type val type = originalValueParameters[i].type
if (type != context.builtIns.nullableAnyType) { if (!type.isNullableAny()) {
+returnIfBadType(irGet(valueParameters[i].symbol), type, +returnIfBadType(irGet(valueParameters[i]), type,
if (typeSafeBarrierDescription == BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT) if (typeSafeBarrierDescription == BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT)
irGet(valueParameters[2].symbol) irGet(valueParameters[2])
else irConst(typeSafeBarrierDescription.defaultValue) else irConst(typeSafeBarrierDescription.defaultValue)
) )
} }
@@ -221,7 +231,7 @@ private fun Context.buildBridge(startOffset: Int, endOffset: Int,
descriptor: OverriddenFunctionDescriptor, targetSymbol: IrFunctionSymbol, descriptor: OverriddenFunctionDescriptor, targetSymbol: IrFunctionSymbol,
superQualifierSymbol: IrClassSymbol? = null): IrFunction { superQualifierSymbol: IrClassSymbol? = null): IrFunction {
val bridge = specialDeclarationsFactory.getBridgeDescriptor(descriptor) val bridge = specialDeclarationsFactory.getBridge(descriptor)
if (bridge.modality == Modality.ABSTRACT) { if (bridge.modality == Modality.ABSTRACT) {
return bridge return bridge
@@ -230,23 +240,28 @@ private fun Context.buildBridge(startOffset: Int, endOffset: Int,
val irBuilder = createIrBuilder(bridge.symbol, startOffset, endOffset) val irBuilder = createIrBuilder(bridge.symbol, startOffset, endOffset)
bridge.body = irBuilder.irBlockBody(bridge) { bridge.body = irBuilder.irBlockBody(bridge) {
val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor.overriddenDescriptor.descriptor) 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 */ superQualifierSymbol = superQualifierSymbol /* Call non-virtually */
).apply { ).apply {
bridge.dispatchReceiverParameter?.let { bridge.dispatchReceiverParameter?.let {
dispatchReceiver = irGet(it.symbol) dispatchReceiver = irGet(it)
} }
bridge.extensionReceiverParameter?.let { bridge.extensionReceiverParameter?.let {
extensionReceiver = irGet(it.symbol) extensionReceiver = irGet(it)
} }
bridge.valueParameters.forEachIndexed { index, parameter -> 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 +delegatingCall
else else
+irReturn(delegatingCall) +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.at
import org.jetbrains.kotlin.backend.common.lower.irNot import org.jetbrains.kotlin.backend.common.lower.irNot
import org.jetbrains.kotlin.backend.konan.Context 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.backend.konan.isValueType
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.builders.* 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.IrTypeOperatorCall
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol 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.util.isNullConst
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid 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. * 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.eqeqeq -> lowerEqeqeq(expression)
irBuiltins.throwNpe -> IrCallImpl(expression.startOffset, expression.endOffset, irBuiltins.throwNpe -> IrCallImpl(expression.startOffset, expression.endOffset,
context.ir.symbols.ThrowNullPointerException.owner.returnType,
context.ir.symbols.ThrowNullPointerException) context.ir.symbols.ThrowNullPointerException)
irBuiltins.noWhenBranchMatchedException -> IrCallImpl(expression.startOffset, expression.endOffset, irBuiltins.noWhenBranchMatchedException -> IrCallImpl(expression.startOffset, expression.endOffset,
context.ir.symbols.ThrowNoWhenBranchMatchedException.owner.returnType,
context.ir.symbols.ThrowNoWhenBranchMatchedException) context.ir.symbols.ThrowNoWhenBranchMatchedException)
else -> expression else -> expression
@@ -148,8 +152,8 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass,
putValueArgument(0, rhs) putValueArgument(0, rhs)
} }
val lhsIsNotNullable = !lhs.type.isNullable() val lhsIsNotNullable = !lhs.type.containsNull()
val rhsIsNotNullable = !rhs.type.isNullable() val rhsIsNotNullable = !rhs.type.containsNull()
return if (expression.descriptor in ieee754EqualsDescriptors()) { return if (expression.descriptor in ieee754EqualsDescriptors()) {
if (lhsIsNotNullable && rhsIsNotNullable) if (lhsIsNotNullable && rhsIsNotNullable)
@@ -159,15 +163,15 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass,
val rhsTemp = irTemporary(rhs) val rhsTemp = irTemporary(rhs)
if (lhsIsNotNullable xor rhsIsNotNullable) { // Exactly one nullable. if (lhsIsNotNullable xor rhsIsNotNullable) { // Exactly one nullable.
+irLogicalAnd( +irLogicalAnd(
irIsNotNull(irGet((if (lhsIsNotNullable) rhsTemp else lhsTemp).symbol)), irIsNotNull(irGet(if (lhsIsNotNullable) rhsTemp else lhsTemp)),
callEquals(irGet(lhsTemp.symbol), irGet(rhsTemp.symbol)) callEquals(irGet(lhsTemp), irGet(rhsTemp))
) )
} else { // Both are nullable. } else { // Both are nullable.
+irIfThenElse(builtIns.booleanType, irIsNull(irGet(lhsTemp.symbol)), +irIfThenElse(context.irBuiltIns.booleanType, irIsNull(irGet(lhsTemp)),
irIsNull(irGet(rhsTemp.symbol)), irIsNull(irGet(rhsTemp)),
irLogicalAnd( irLogicalAnd(
irIsNotNull(irGet(rhsTemp.symbol)), irIsNotNull(irGet(rhsTemp)),
callEquals(irGet(lhsTemp.symbol), irGet(rhsTemp.symbol)) callEquals(irGet(lhsTemp), irGet(rhsTemp))
) )
) )
} }
@@ -179,12 +183,12 @@ internal class BuiltinOperatorLowering(val context: Context) : FileLoweringPass,
irBlock { irBlock {
val lhsTemp = irTemporary(lhs) val lhsTemp = irTemporary(lhs)
if (rhsIsNotNullable) if (rhsIsNotNullable)
+irLogicalAnd(irIsNotNull(irGet(lhsTemp.symbol)), callEquals(irGet(lhsTemp.symbol), rhs)) +irLogicalAnd(irIsNotNull(irGet(lhsTemp)), callEquals(irGet(lhsTemp), rhs))
else { else {
val rhsTemp = irTemporary(rhs) val rhsTemp = irTemporary(rhs)
+irIfThenElse(builtIns.booleanType, irIsNull(irGet(lhsTemp.symbol)), +irIfThenElse(irBuiltins.booleanType, irIsNull(irGet(lhsTemp)),
irIsNull(irGet(rhsTemp.symbol)), irIsNull(irGet(rhsTemp)),
callEquals(irGet(lhsTemp.symbol), irGet(rhsTemp.symbol)) 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 { from.atMostOne {
val leftParamType = it.owner.valueParameters[0].type val leftParamType = it.owner.valueParameters[0].type
val rightParamType = it.owner.valueParameters[1].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.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext 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.common.lower.*
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.pop import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe 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.backend.konan.llvm.functionName
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations 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.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol 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.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl 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.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager 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 { internal class CallableReferenceLowering(val context: Context): FileLoweringPass {
@@ -161,15 +160,16 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
val parent: IrDeclarationParent, val parent: IrDeclarationParent,
val functionReference: IrFunctionReference) { val functionReference: IrFunctionReference) {
private val functionDescriptor = functionReference.descriptor private val functionDescriptor = functionReference.descriptor.original
private val functionParameters = functionDescriptor.explicitParameters private val irFunction = functionReference.symbol.owner
private val boundFunctionParameters = functionReference.getArguments().map { it.first } private val functionParameters = irFunction.explicitParameters
private val boundFunctionParameters = functionReference.getArgumentsWithIr().map { it.first }
private val unboundFunctionParameters = functionParameters - boundFunctionParameters private val unboundFunctionParameters = functionParameters - boundFunctionParameters
private lateinit var functionReferenceClassDescriptor: ClassDescriptorImpl private lateinit var functionReferenceClassDescriptor: ClassDescriptorImpl
private lateinit var functionReferenceClass: IrClassImpl private lateinit var functionReferenceClass: IrClassImpl
private lateinit var functionReferenceThis: IrValueParameterSymbol 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 private val kFunctionImplSymbol = context.ir.symbols.kFunctionImpl
@@ -177,29 +177,26 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
val startOffset = functionReference.startOffset val startOffset = functionReference.startOffset
val endOffset = functionReference.endOffset val endOffset = functionReference.endOffset
val returnType = functionDescriptor.returnType!! val returnType = irFunction.returnType
val superTypes = mutableListOf( val superTypes = mutableListOf(kFunctionImplSymbol.typeWith(returnType))
kFunctionImplSymbol.owner.defaultType.replace(listOf(returnType))
)
val superClasses = mutableListOf(kFunctionImplSymbol.owner)
val numberOfParameters = unboundFunctionParameters.size 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 functionParameterTypes = unboundFunctionParameters.map { it.type }
val functionClassTypeParameters = functionParameterTypes + returnType val functionClassTypeParameters = functionParameterTypes + returnType
superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeParameters) superTypes += functionIrClass.symbol.typeWith(functionClassTypeParameters)
superClasses += context.ir.symbols.kFunctions[numberOfParameters].owner
var suspendFunctionClassDescriptor: ClassDescriptor? = null var suspendFunctionIrClass: IrClass? = null
var suspendFunctionClassTypeParameters: List<KotlinType>? = null var suspendFunctionClassTypeParameters: List<IrType>? = null
val lastParameterType = unboundFunctionParameters.lastOrNull()?.type 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. // If the last parameter is Continuation<> inherit from SuspendFunction.
suspendFunctionClassDescriptor = kotlinPackageScope.getContributedClassifier( suspendFunctionIrClass = context.ir.symbols.suspendFunctions[numberOfParameters - 1].owner
Name.identifier("SuspendFunction${numberOfParameters - 1}"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) +
suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) + lastParameterType.arguments.single().type (lastParameterType.arguments.single().typeOrNull ?: context.irBuiltIns.anyNType)
superTypes += suspendFunctionClassDescriptor.defaultType.replace(suspendFunctionClassTypeParameters) superTypes += suspendFunctionIrClass.symbol.typeWith(suspendFunctionClassTypeParameters)
superClasses += context.ir.symbols.suspendFunctions[numberOfParameters - 1].owner
} }
functionReferenceClassDescriptor = object : ClassDescriptorImpl( functionReferenceClassDescriptor = object : ClassDescriptorImpl(
@@ -207,7 +204,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
/* name = */ "${functionDescriptor.name}\$${functionReferenceCount++}".synthesizedName, /* name = */ "${functionDescriptor.name}\$${functionReferenceCount++}".synthesizedName,
/* modality = */ Modality.FINAL, /* modality = */ Modality.FINAL,
/* kind = */ ClassKind.CLASS, /* kind = */ ClassKind.CLASS,
/* superTypes = */ superTypes, /* superTypes = */ superTypes.map { it.toKotlinType() },
/* source = */ SourceElement.NO_SOURCE, /* source = */ SourceElement.NO_SOURCE,
/* isExternal = */ false, /* isExternal = */ false,
/* storageManager = */ LockBasedStorageManager.NO_LOCKS /* storageManager = */ LockBasedStorageManager.NO_LOCKS
@@ -225,13 +222,15 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
val constructorBuilder = createConstructorBuilder() val constructorBuilder = createConstructorBuilder()
val invokeFunctionDescriptor = functionClassDescriptor.getFunction("invoke", functionClassTypeParameters) val invokeFunctionSymbol =
val invokeMethodBuilder = createInvokeMethodBuilder(invokeFunctionDescriptor) functionIrClass.simpleFunctions().single { it.name.asString() == "invoke" }.symbol
val invokeMethodBuilder = createInvokeMethodBuilder(invokeFunctionSymbol, functionReferenceClass)
var suspendInvokeMethodBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>? = null var suspendInvokeMethodBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>? = null
if (suspendFunctionClassDescriptor != null) { if (suspendFunctionIrClass != null) {
val suspendInvokeFunctionDescriptor = suspendFunctionClassDescriptor.getFunction("invoke", suspendFunctionClassTypeParameters!!) val suspendInvokeFunctionSymbol =
suspendInvokeMethodBuilder = createInvokeMethodBuilder(suspendInvokeFunctionDescriptor) suspendFunctionIrClass.simpleFunctions().single { it.name.asString() == "invoke" }.symbol
suspendInvokeMethodBuilder = createInvokeMethodBuilder(suspendInvokeFunctionSymbol, functionReferenceClass)
} }
val memberScope = stub<MemberScope>("callable reference class") val memberScope = stub<MemberScope>("callable reference class")
@@ -253,7 +252,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
functionReferenceClass.addChild(it.ir) functionReferenceClass.addChild(it.ir)
} }
functionReferenceClass.setSuperSymbolsAndAddFakeOverrides(superClasses) functionReferenceClass.setSuperSymbolsAndAddFakeOverrides(superTypes)
return BuiltFunctionReference(functionReferenceClass, constructorBuilder.ir) return BuiltFunctionReference(functionReferenceClass, constructorBuilder.ir)
} }
@@ -275,15 +274,19 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
override fun doInitialize() { override fun doInitialize() {
val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
val constructorParameters = boundFunctionParameters.mapIndexed { index, parameter -> val constructorParameters = boundFunctionParameters.mapIndexed { index, parameter ->
parameter.copyAsValueParameter(descriptor, index) parameter.descriptor.copyAsValueParameter(descriptor, index)
} }
descriptor.initialize(constructorParameters, Visibilities.PUBLIC) descriptor.initialize(constructorParameters, Visibilities.PUBLIC)
descriptor.returnType = functionReferenceClassDescriptor.defaultType descriptor.returnType = functionReferenceClassDescriptor.defaultType
} }
override fun buildIr(): IrConstructor { override fun buildIr(): IrConstructor {
val symbols = this@CallableReferenceLowering.context.ir.symbols
val irBuiltIns = context.irBuiltIns
argumentToPropertiesMap = boundFunctionParameters.associate { argumentToPropertiesMap = boundFunctionParameters.associate {
it to buildPropertyWithBackingField(it.name, it.type, false) it.descriptor to buildField(it.name, it.type, false)
} }
val startOffset = functionReference.startOffset val startOffset = functionReference.startOffset
@@ -294,30 +297,36 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
symbol = symbol).apply { symbol = symbol).apply {
returnType = functionReferenceClass.defaultType
val irBuilder = context.createIrBuilder(this.symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(this.symbol, startOffset, endOffset)
createParameterDeclarations() boundFunctionParameters.mapIndexedTo(this.valueParameters) { index, parameter ->
parameter.copy(descriptor.valueParameters[index])
}
body = irBuilder.irBlockBody { body = irBuilder.irBlockBody {
+IrDelegatingConstructorCallImpl(startOffset, endOffset, +IrDelegatingConstructorCallImpl(startOffset, endOffset,
kFunctionImplConstructorSymbol, kFunctionImplConstructorSymbol.descriptor).apply { context.irBuiltIns.unitType,
val name = IrConstImpl(startOffset, endOffset, context.builtIns.stringType, kFunctionImplConstructorSymbol, kFunctionImplConstructorSymbol.descriptor, 0).apply {
val stringType = irBuiltIns.stringType
val name = IrConstImpl(startOffset, endOffset, stringType,
IrConstKind.String, functionDescriptor.name.asString()) IrConstKind.String, functionDescriptor.name.asString())
putValueArgument(0, name) 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) (functionReference.symbol.owner).fullName)
putValueArgument(1, fqName) putValueArgument(1, fqName)
val bound = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType, val bound = IrConstImpl.boolean(startOffset, endOffset, context.irBuiltIns.booleanType,
boundFunctionParameters.isNotEmpty()) boundFunctionParameters.isNotEmpty())
putValueArgument(2, bound) putValueArgument(2, bound)
val needReceiver = boundFunctionParameters.singleOrNull() is ReceiverParameterDescriptor val needReceiver = boundFunctionParameters.singleOrNull()?.descriptor is ReceiverParameterDescriptor
val receiver = if (needReceiver) irGet(valueParameters.single().symbol) else irNull() val receiver = if (needReceiver) irGet(valueParameters.single()) else irNull()
putValueArgument(3, receiver) putValueArgument(3, receiver)
} }
+IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol) +IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, irBuiltIns.unitType)
// Save all arguments to fields. // Save all arguments to fields.
boundFunctionParameters.forEachIndexed { index, parameter -> 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 private val IrFunction.fullName: String
get() = parent.fqNameSafe.child(Name.identifier(functionName)).asString() get() = parent.fqNameSafe.child(Name.identifier(functionName)).asString()
private fun createInvokeMethodBuilder(superFunctionDescriptor: FunctionDescriptor) private fun createInvokeMethodBuilder(superFunctionSymbol: IrSimpleFunctionSymbol, parent: IrClass)
= object : SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() { = object : SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
val superFunctionDescriptor: FunctionDescriptor = superFunctionSymbol.descriptor
override fun buildSymbol() = IrSimpleFunctionSymbolImpl( override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create( SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ functionReferenceClassDescriptor, /* containingDeclaration = */ functionReferenceClassDescriptor,
@@ -368,10 +379,18 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
symbol = ourSymbol).apply { symbol = ourSymbol).apply {
returnType = superFunctionSymbol.owner.returnType // FIXME: substitute
val function = this val function = this
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) 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) { body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn( +irReturn(
@@ -383,21 +402,21 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
if (!unboundArgsSet.contains(it)) if (!unboundArgsSet.contains(it))
// Bound parameter - read from field. // Bound parameter - read from field.
irGetField( irGetField(
irGet(function.dispatchReceiverParameter!!.symbol), irGet(function.dispatchReceiverParameter!!),
argumentToPropertiesMap[it]!! argumentToPropertiesMap[it.descriptor]!!
) )
else { else {
if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size) if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size)
// For suspend functions the last argument is continuation and it is implicit. // For suspend functions the last argument is continuation and it is implicit.
irCall(getContinuationSymbol, irCall(getContinuationSymbol.owner,
listOf(ourSymbol.descriptor.returnType!!)) listOf(returnType))
else else
irGet(valueParameters[unboundIndex++].symbol) irGet(valueParameters[unboundIndex++])
} }
when (it) { when (it) {
functionDescriptor.dispatchReceiverParameter -> dispatchReceiver = argument irFunction.dispatchReceiverParameter -> dispatchReceiver = argument
functionDescriptor.extensionReceiverParameter -> extensionReceiver = argument irFunction.extensionReceiverParameter -> extensionReceiver = argument
else -> putValueArgument((it as ValueParameterDescriptor).index, argument) else -> putValueArgument(it.index, argument)
} }
} }
assert(unboundIndex == valueParameters.size, { "Not all arguments of <invoke> are used" }) 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 { private fun buildField(name: Name, type: IrType, isMutable: Boolean): IrField = createField(
val propertyBuilder = context.createPropertyWithBackingFieldBuilder( functionReference.startOffset,
startOffset = functionReference.startOffset, functionReference.endOffset,
endOffset = functionReference.endOffset, type,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, name,
owner = functionReferenceClassDescriptor, isMutable,
name = name, DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
type = type, functionReferenceClassDescriptor
isMutable = isMutable).apply { ).also {
initialize() functionReferenceClass.addChild(it)
}
functionReferenceClass.addChild(propertyBuilder.ir)
return propertyBuilder.ir.backingField!!.symbol
} }
} }
} }
@@ -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.IrBuildingTransformer
import org.jetbrains.kotlin.backend.common.lower.at import org.jetbrains.kotlin.backend.common.lower.at
import org.jetbrains.kotlin.backend.konan.Context 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.builders.irCall
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.* 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.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
@@ -29,14 +30,14 @@ internal class CompileTimeEvaluateLowering(val context: Context): FileLoweringPa
// TODO: refer functions more reliably. // TODO: refer functions more reliably.
if (elementsArr.elements.any { it is IrSpreadElement } 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 return expression
builder.at(expression) builder.at(expression)
val typeArguments = descriptor.typeParameters.map { expression.getTypeArgument(it)!! } val typeArgument = expression.getTypeArgument(0)!!
return builder.irCall(context.ir.symbols.listOfInternal, typeArguments).apply { return builder.irCall(context.ir.symbols.listOfInternal.owner, listOf(typeArgument)).apply {
putValueArgument(0, elementsArr) 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.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.backend.konan.Context 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.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression 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.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid 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 { internal class DataClassOperatorsLowering(val context: Context): FunctionLoweringPass {
@@ -45,40 +45,37 @@ internal class DataClassOperatorsLowering(val context: Context): FunctionLowerin
return expression return expression
val argument = expression.getValueArgument(0)!! val argument = expression.getValueArgument(0)!!
val argumentType = argument.type.makeNotNullable() val argumentClassifier = argument.type.classifierOrFail
val genericType =
if (argumentType.arguments.isEmpty()) val isToString = expression.symbol == irBuiltins.dataClassArrayMemberToStringSymbol
argumentType val newCalleeSymbol = if (isToString)
else context.ir.symbols.arrayContentToString[argumentClassifier]!!
(argumentType.constructor.declarationDescriptor as ClassDescriptor).defaultType
val isToString = descriptor == irBuiltins.dataClassArrayMemberToString
val newSymbol = if (isToString)
context.ir.symbols.arrayContentToString[genericType]!!
else else
context.ir.symbols.arrayContentHashCode[genericType]!! context.ir.symbols.arrayContentHashCode[argumentClassifier]!!
val newCallee = newCalleeSymbol.owner
val startOffset = expression.startOffset val startOffset = expression.startOffset
val endOffset = expression.endOffset val endOffset = expression.endOffset
val irBuilder = context.createIrBuilder(irFunction.symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(irFunction.symbol, startOffset, endOffset)
return irBuilder.run { return irBuilder.run {
val typeArguments = // TODO: use more precise type arguments.
if (argumentType.arguments.isEmpty()) val typeArguments = (0 until newCallee.typeParameters.size).map { irBuiltins.anyNType }
emptyList<KotlinType>()
else argumentType.arguments.map { it.type } if (!argument.type.isSimpleTypeWithQuestionMark) {
if (!argument.type.isMarkedNullable) { irCall(newCallee, typeArguments).apply {
irCall(newSymbol, typeArguments).apply {
extensionReceiver = argument extensionReceiver = argument
} }
} else { } else {
val tmp = scope.createTemporaryVariable(argument) val tmp = scope.createTemporaryVariable(argument)
val call = irCall(newSymbol, typeArguments).apply { val call = irCall(newCallee, typeArguments).apply {
extensionReceiver = irGet(tmp.symbol) extensionReceiver = irGet(tmp)
} }
irBlock(argument) { irBlock(argument) {
+tmp +tmp
+irIfThenElse(call.type, +irIfThenElse(call.type,
irEqeqeq(irGet(tmp.symbol), irNull()), irEqeqeq(irGet(tmp), irNull()),
if (isToString) if (isToString)
irString("null") irString("null")
else else
@@ -24,14 +24,17 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.createClassSymbolOrNull import org.jetbrains.kotlin.ir.symbols.impl.createClassSymbolOrNull
import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.createValueSymbol 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.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid 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.TypeSubstitutor
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.typeUtil.makeNullable
internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor, internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
val parentDescriptor: DeclarationDescriptor, val parentDescriptor: DeclarationDescriptor,
@@ -484,7 +486,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
return IrCallImpl( return IrCallImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
type = newDescriptor.returnType!!, type = context.ir.translateErased(newDescriptor.returnType!!),
descriptor = newDescriptor, descriptor = newDescriptor,
typeArgumentsCount = expression.typeArgumentsCount, typeArgumentsCount = expression.typeArgumentsCount,
origin = expression.origin, origin = expression.origin,
@@ -497,19 +499,100 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
//---------------------------------------------------------------------// //---------------------------------------------------------------------//
override fun visitFunction(declaration: IrFunction): IrFunction = override fun visitSimpleFunction(declaration: IrSimpleFunction): IrFunction {
IrFunctionImpl( val descriptor = mapFunctionDeclaration(declaration.descriptor)
startOffset = declaration.startOffset, return IrFunctionImpl(
endOffset = declaration.endOffset, startOffset = declaration.startOffset,
origin = mapDeclarationOrigin(declaration.origin), endOffset = declaration.endOffset,
descriptor = mapFunctionDeclaration(declaration.descriptor), origin = mapDeclarationOrigin(declaration.origin),
body = declaration.body?.transform(this, null) descriptor = descriptor
).also { ).also {
it.returnType = context.ir.translateErased(descriptor.returnType!!)
it.body = declaration.body?.transform(this, null)
it.setOverrides(context.ir.symbols.symbolTable) 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 { private fun <T : IrFunction> T.transformDefaults(original: T): T {
for (originalValueParameter in original.descriptor.valueParameters) { for (originalValueParameter in original.descriptor.valueParameters) {
val valueParameter = descriptor.valueParameters[originalValueParameter.index] 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) { return when (operator) {
IrTypeOperator.CAST, IrTypeOperator.CAST,
IrTypeOperator.IMPLICIT_CAST, IrTypeOperator.IMPLICIT_CAST,
@@ -531,22 +614,24 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> type IrTypeOperator.IMPLICIT_INTEGER_COERCION -> type
IrTypeOperator.SAFE_CAST -> type.makeNullable() IrTypeOperator.SAFE_CAST -> type.makeNullable()
IrTypeOperator.INSTANCEOF, IrTypeOperator.INSTANCEOF,
IrTypeOperator.NOT_INSTANCEOF -> context.builtIns.booleanType IrTypeOperator.NOT_INSTANCEOF -> context.irBuiltIns.booleanType
} }
} }
//---------------------------------------------------------------------// //---------------------------------------------------------------------//
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall { override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall {
val typeOperand = substituteType(expression.typeOperand)!! val erasedTypeOperand = substituteAndEraseType(expression.typeOperand)!!
val returnType = getTypeOperatorReturnType(expression.operator, typeOperand) val typeOperand = substituteAndBreakType(expression.typeOperand)
val returnType = getTypeOperatorReturnType(expression.operator, erasedTypeOperand)
return IrTypeOperatorCallImpl( return IrTypeOperatorCallImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
type = returnType, type = returnType,
operator = expression.operator, operator = expression.operator,
typeOperand = typeOperand, 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( IrReturnImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
type = substituteType(expression.type)!!, type = substituteAndEraseType(expression.type)!!,
returnTargetDescriptor = mapReturnTarget(expression.returnTarget), returnTargetDescriptor = mapReturnTarget(expression.returnTarget),
value = expression.value.transform(this, null) value = expression.value.transform(this, null)
) )
@@ -577,7 +662,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
} else { } else {
IrBlockImpl( IrBlockImpl(
expression.startOffset, expression.endOffset, expression.startOffset, expression.endOffset,
substituteType(expression.type)!!, substituteAndEraseType(expression.type)!!,
mapStatementOrigin(expression.origin), mapStatementOrigin(expression.origin),
expression.statements.map { it.transform(this, null) } expression.statements.map { it.transform(this, null) }
) )
@@ -587,7 +672,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
override fun visitClassReference(expression: IrClassReference): IrClassReference { 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 newDescriptorType = substituteType(expression.descriptor.defaultType)!! // Substituted type of referenced class.
val classDescriptor = newDescriptorType.constructor.declarationDescriptor!! // Get ClassifierDescriptor of the referenced class. val classDescriptor = newDescriptorType.constructor.declarationDescriptor!! // Get ClassifierDescriptor of the referenced class.
return IrClassReferenceImpl( return IrClassReferenceImpl(
@@ -602,7 +687,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
override fun visitGetClass(expression: IrGetClass): IrGetClass { override fun visitGetClass(expression: IrGetClass): IrGetClass {
val type = substituteType(expression.type)!! val type = substituteAndEraseType(expression.type)!!
return IrGetClassImpl( return IrGetClassImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
@@ -616,6 +701,27 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop { override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
return 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 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) { private fun IrMemberAccessExpression.substituteTypeArguments(original: IrMemberAccessExpression) {
for (index in 0 until original.typeArgumentsCount) { for (index in 0 until original.typeArgumentsCount) {
val originalTypeArgument = original.getTypeArgument(index) val originalTypeArgument = original.getTypeArgument(index)
val newTypeArgument = substituteType(originalTypeArgument)!! val newTypeArgument = substituteAndBreakType(originalTypeArgument!!)
this.putTypeArgument(index, newTypeArgument) this.putTypeArgument(index, newTypeArgument)
} }
} }
@@ -649,7 +767,10 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
class SubstitutedDescriptor(val inlinedFunction: FunctionDescriptor, val descriptor: DeclarationDescriptor) 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() { : IrElementTransformerVoidWithContext() {
private val variableSubstituteMap = mutableMapOf<VariableDescriptor, VariableDescriptor>() private val variableSubstituteMap = mutableMapOf<VariableDescriptor, VariableDescriptor>()
@@ -710,6 +831,7 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<
endOffset = declaration.endOffset, endOffset = declaration.endOffset,
origin = declaration.origin, origin = declaration.origin,
descriptor = newDescriptor, descriptor = newDescriptor,
type = context.ir.translateErased(newDescriptor.type),
initializer = declaration.initializer initializer = declaration.initializer
) )
} }
@@ -725,6 +847,7 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<
return IrGetValueImpl( return IrGetValueImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
type = context.ir.translateErased(newDescriptor.type),
origin = expression.origin, origin = expression.origin,
symbol = createValueSymbol(newDescriptor) symbol = createValueSymbol(newDescriptor)
) )
@@ -743,7 +866,7 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<
return IrCallImpl( return IrCallImpl(
startOffset = oldExpression.startOffset, startOffset = oldExpression.startOffset,
endOffset = oldExpression.endOffset, endOffset = oldExpression.endOffset,
type = newDescriptor.returnType!!, type = context.ir.translateErased(newDescriptor.returnType!!),
symbol = createFunctionSymbol(newDescriptor), symbol = createFunctionSymbol(newDescriptor),
descriptor = newDescriptor, descriptor = newDescriptor,
typeArgumentsCount = oldExpression.typeArgumentsCount, 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 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.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock 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.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.ir.createArrayOfExpression
import org.jetbrains.kotlin.backend.konan.KonanBackendContext 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.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl 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.IrFile
import org.jetbrains.kotlin.ir.declarations.IrLocalDelegatedProperty import org.jetbrains.kotlin.ir.declarations.IrLocalDelegatedProperty
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl 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.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrLocalDelegatedPropertyReference import org.jetbrains.kotlin.ir.expressions.IrLocalDelegatedPropertyReference
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.util.addChild import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.functions import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -55,10 +52,10 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
private val reflectionTypes = context.reflectionTypes private val reflectionTypes = context.reflectionTypes
private var tempIndex = 0 private var tempIndex = 0
private fun getKPropertyImplConstructor(receiverTypes: List<KotlinType>, private fun getKPropertyImplConstructor(receiverTypes: List<IrType>,
returnType: KotlinType, returnType: IrType,
isLocal: Boolean, isLocal: Boolean,
isMutable: Boolean) : Pair<IrConstructorSymbol, Map<TypeParameterDescriptor, KotlinType>> { isMutable: Boolean) : Pair<IrConstructorSymbol, List<IrType>> {
val symbols = context.ir.symbols 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)) val arguments = (receiverTypes + listOf(returnType))
.mapIndexed { index, type -> typeParameters[index] to type }
.toMap()
return classSymbol.constructors.single() to arguments return classSymbol.constructors.single() to arguments
} }
@@ -102,17 +96,21 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
val kProperties = mutableMapOf<VariableDescriptorWithAccessors, Pair<IrExpression, Int>>() 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 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, val kPropertiesField = IrFieldImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION, DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
createKPropertiesFieldDescriptor(irFile.packageFragmentDescriptor, createKPropertiesFieldDescriptor(irFile.packageFragmentDescriptor,
context.builtIns.array.replace(kPropertyImplType) kPropertiesFieldType.toKotlinType()
) ),
kPropertiesFieldType
) )
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() { irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
@@ -148,11 +146,9 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
createKProperty(expression, this) to kProperties.size createKProperty(expression, this) to kProperties.size
} }
return irCall(arrayItemGetter, typeArguments = listOf(kPropertyImplType)).apply { return irCall(arrayItemGetter).apply {
dispatchReceiver = dispatchReceiver = irGetField(null, kPropertiesField)
IrGetFieldImpl(expression.startOffset, expression.endOffset, kPropertiesField.symbol) putValueArgument(0, irInt(field.second))
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, field.second))
} }
} }
} }
@@ -173,14 +169,16 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
else { // Cache KProperties with no arguments. else { // Cache KProperties with no arguments.
// TODO: what about `receiversCount == 1` case? // TODO: what about `receiversCount == 1` case?
val field = kProperties.getOrPut(propertyDescriptor) { 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 { return irCall(arrayItemGetter).apply {
dispatchReceiver = dispatchReceiver = irGetField(null, kPropertiesField)
IrGetFieldImpl(expression.startOffset, expression.endOffset, kPropertiesField.symbol) putValueArgument(0, irInt(field.second))
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, field.second))
} }
} }
} }
@@ -203,23 +201,23 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
val startOffset = expression.startOffset val startOffset = expression.startOffset
val endOffset = expression.endOffset val endOffset = expression.endOffset
return irBuilder.irBlock(expression) { return irBuilder.irBlock(expression) {
val receiverTypes = mutableListOf<KotlinType>() val receiverTypes = mutableListOf<IrType>()
val dispatchReceiver = expression.dispatchReceiver.let { val dispatchReceiver = expression.dispatchReceiver.let {
if (it == null) if (it == null)
null null
else else
irTemporary(value = it, nameHint = "\$dispatchReceiver${tempIndex++}").symbol irTemporary(value = it, nameHint = "\$dispatchReceiver${tempIndex++}")
} }
val extensionReceiver = expression.extensionReceiver.let { val extensionReceiver = expression.extensionReceiver.let {
if (it == null) if (it == null)
null null
else else
irTemporary(value = it, nameHint = "\$extensionReceiver${tempIndex++}").symbol irTemporary(value = it, nameHint = "\$extensionReceiver${tempIndex++}")
} }
val propertyDescriptor = expression.descriptor val propertyDescriptor = expression.descriptor
val returnType = expression.getter?.owner?.returnType ?: expression.field!!.owner.type
val returnType = propertyDescriptor.type val getterCallableReference = expression.getter?.owner?.let { getter ->
val getterCallableReference = propertyDescriptor.getter?.let { getter ->
getter.extensionReceiverParameter.let { getter.extensionReceiverParameter.let {
if (it != null && expression.extensionReceiver == null) if (it != null && expression.extensionReceiver == null)
receiverTypes.add(it.type) receiverTypes.add(it.type)
@@ -228,39 +226,37 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
if (it != null && expression.dispatchReceiver == null) if (it != null && expression.dispatchReceiver == null)
receiverTypes.add(it.type) receiverTypes.add(it.type)
} }
val getterKFunctionType = reflectionTypes.getKFunctionType( val getterKFunctionType = this@PropertyDelegationLowering.context.ir.symbols.getKFunctionType(
annotations = Annotations.EMPTY, returnType,
receiverType = receiverTypes.firstOrNull(), receiverTypes
parameterTypes = if (receiverTypes.size < 2) listOf() else listOf(receiverTypes[1]), )
returnType = returnType)
IrFunctionReferenceImpl( IrFunctionReferenceImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
type = getterKFunctionType, type = getterKFunctionType,
symbol = expression.getter!!, symbol = expression.getter!!,
descriptor = getter, descriptor = getter.descriptor,
typeArguments = null typeArgumentsCount = 0
).apply { ).apply {
this.dispatchReceiver = dispatchReceiver?.let { irGet(it) } this.dispatchReceiver = dispatchReceiver?.let { irGet(it) }
this.extensionReceiver = extensionReceiver?.let { irGet(it) } this.extensionReceiver = extensionReceiver?.let { irGet(it) }
} }
} }
val setterCallableReference = propertyDescriptor.setter?.let { val setterCallableReference = expression.setter?.owner?.let {
if (!isKMutablePropertyType(expression.type)) null if (!isKMutablePropertyType(expression.type.toKotlinType())) null
else { else {
val setterKFunctionType = reflectionTypes.getKFunctionType( val setterKFunctionType = this@PropertyDelegationLowering.context.ir.symbols.getKFunctionType(
annotations = Annotations.EMPTY, context.irBuiltIns.unitType,
receiverType = receiverTypes.firstOrNull(), receiverTypes + returnType
parameterTypes = if (receiverTypes.size < 2) listOf(returnType) else listOf(receiverTypes[1], returnType), )
returnType = context.builtIns.unitType)
IrFunctionReferenceImpl( IrFunctionReferenceImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
type = setterKFunctionType, type = setterKFunctionType,
symbol = expression.setter!!, symbol = expression.setter!!,
descriptor = it, descriptor = it.descriptor,
typeArguments = null typeArgumentsCount = 0
).apply { ).apply {
this.dispatchReceiver = dispatchReceiver?.let { irGet(it) } this.dispatchReceiver = dispatchReceiver?.let { irGet(it) }
this.extensionReceiver = extensionReceiver?.let { irGet(it) } this.extensionReceiver = extensionReceiver?.let { irGet(it) }
@@ -273,7 +269,7 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
returnType = returnType, returnType = returnType,
isLocal = false, isLocal = false,
isMutable = setterCallableReference != null) isMutable = setterCallableReference != null)
val initializer = irCall(symbol, constructorTypeArguments).apply { val initializer = irCall(symbol.owner, constructorTypeArguments).apply {
putValueArgument(0, irString(propertyDescriptor.name.asString())) putValueArgument(0, irString(propertyDescriptor.name.asString()))
if (getterCallableReference != null) if (getterCallableReference != null)
putValueArgument(1, getterCallableReference) putValueArgument(1, getterCallableReference)
@@ -285,16 +281,15 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
} }
private fun createLocalKProperty(propertyDescriptor: VariableDescriptorWithAccessors, private fun createLocalKProperty(propertyDescriptor: VariableDescriptorWithAccessors,
propertyType: IrType,
irBuilder: IrBuilderWithScope): IrExpression { irBuilder: IrBuilderWithScope): IrExpression {
irBuilder.run { irBuilder.run {
val returnType = propertyDescriptor.type
val (symbol, constructorTypeArguments) = getKPropertyImplConstructor( val (symbol, constructorTypeArguments) = getKPropertyImplConstructor(
receiverTypes = emptyList(), receiverTypes = emptyList(),
returnType = returnType, returnType = propertyType,
isLocal = true, isLocal = true,
isMutable = false) isMutable = false)
val initializer = irCall(symbol, constructorTypeArguments).apply { val initializer = irCall(symbol.owner, constructorTypeArguments).apply {
putValueArgument(0, irString(propertyDescriptor.name.asString())) putValueArgument(0, irString(propertyDescriptor.name.asString()))
} }
return initializer return initializer
@@ -316,10 +311,15 @@ internal class PropertyDelegationLowering(val context: KonanBackendContext) : Fi
private object DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION : private object DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION :
IrDeclarationOriginImpl("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, return PropertyDescriptorImpl.create(containingDeclaration, Annotations.EMPTY, Modality.FINAL, Visibilities.PRIVATE,
false, "KPROPERTIES".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE, 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.FileLoweringPass
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.runOnFilePostfix 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.Context
import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor 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.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlockBody 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.*
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.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement 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.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* 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.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.*
internal class EnumSyntheticFunctionsBuilder(val context: Context) { internal class EnumSyntheticFunctionsBuilder(val context: Context) {
fun buildValuesExpression(startOffset: Int, endOffset: Int, fun buildValuesExpression(startOffset: Int, endOffset: Int,
enumClassDescriptor: ClassDescriptor): IrExpression { enumClass: IrClass): IrExpression {
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor)
val typeParameterT = genericValuesDescriptor.typeParameters[0] val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClass)
val enumClassType = enumClassDescriptor.defaultType
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumClassType)))
val substitutedValueOf = genericValuesDescriptor.substitute(typeSubstitutor)!!
return IrCallImpl(startOffset, endOffset, return irCall(startOffset, endOffset, genericValuesSymbol.owner, listOf(enumClass.defaultType))
genericValuesSymbol, substitutedValueOf, mapOf(typeParameterT to enumClassType))
.apply { .apply {
val receiver = IrGetObjectValueImpl(startOffset, endOffset, val receiver = IrGetObjectValueImpl(startOffset, endOffset,
loweredEnum.implObject.defaultType, loweredEnum.implObject.symbol) loweredEnum.implObject.defaultType,
putValueArgument(0, IrGetFieldImpl(startOffset, endOffset, loweredEnum.valuesField.symbol, receiver)) loweredEnum.implObject.symbol)
putValueArgument(0, IrGetFieldImpl(
startOffset,
endOffset,
loweredEnum.valuesField.symbol,
loweredEnum.valuesField.type,
receiver
))
} }
} }
fun buildValueOfExpression(startOffset: Int, endOffset: Int, fun buildValueOfExpression(startOffset: Int, endOffset: Int,
enumClassDescriptor: ClassDescriptor, enumClass: IrClass,
value: IrExpression): IrExpression { value: IrExpression): IrExpression {
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor) val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClass)
val typeParameterT = genericValueOfDescriptor.typeParameters[0] return irCall(startOffset, endOffset, genericValueOfSymbol.owner, listOf(enumClass.defaultType))
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))
.apply { .apply {
putValueArgument(0, value) putValueArgument(0, value)
val receiver = IrGetObjectValueImpl(startOffset, endOffset, val receiver = IrGetObjectValueImpl(startOffset, endOffset,
loweredEnum.implObject.defaultType, loweredEnum.implObject.symbol) 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 genericValueOfSymbol = context.ir.symbols.valueOfForEnum
private val genericValueOfDescriptor = genericValueOfSymbol.descriptor
private val genericValuesSymbol = context.ir.symbols.valuesForEnum private val genericValuesSymbol = context.ir.symbols.valuesForEnum
private val genericValuesDescriptor = genericValuesSymbol.descriptor
} }
internal class EnumUsageLowering(val context: Context) internal class EnumUsageLowering(val context: Context)
@@ -105,16 +107,13 @@ internal class EnumUsageLowering(val context: Context)
} }
override fun visitGetEnumValue(expression: IrGetEnumValue): IrExpression { override fun visitGetEnumValue(expression: IrGetEnumValue): IrExpression {
val enumClassDescriptor = expression.descriptor.containingDeclaration as ClassDescriptor val entry = expression.symbol.owner
return loadEnumEntry(expression.startOffset, expression.endOffset, enumClassDescriptor, expression.descriptor.name) return loadEnumEntry(
} expression.startOffset,
expression.endOffset,
// TODO: remove as soon IR is fixed (there should no be any enum get with GET_OBJECT operation). entry.parentAsClass,
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression { entry.name
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)
} }
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
@@ -125,18 +124,20 @@ internal class EnumUsageLowering(val context: Context)
if (descriptor.original != enumValuesDescriptor && descriptor.original != enumValueOfDescriptor) if (descriptor.original != enumValuesDescriptor && descriptor.original != enumValueOfDescriptor)
return expression return expression
val genericT = descriptor.original.typeParameters[0] val irClassSymbol = expression.getTypeArgument(0)!!.classifierOrNull as? IrClassSymbol
val substitutedT = expression.getTypeArgument(genericT)!!
val classDescriptor = substitutedT.constructor.declarationDescriptor as? ClassDescriptor
?: return expression // Type parameter. ?: 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) { return if (descriptor.original == enumValuesDescriptor) {
enumSyntheticFunctionsBuilder.buildValuesExpression(expression.startOffset, expression.endOffset, classDescriptor) enumSyntheticFunctionsBuilder.buildValuesExpression(expression.startOffset, expression.endOffset, irClass)
} else { } else {
val value = expression.getValueArgument(0)!! 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 enumValuesSymbol = context.ir.symbols.enumValues
private val enumValuesDescriptor = enumValuesSymbol.descriptor private val enumValuesDescriptor = enumValuesSymbol.descriptor
private fun loadEnumEntry(startOffset: Int, endOffset: Int, enumClassDescriptor: ClassDescriptor, name: Name): IrExpression { private fun loadEnumEntry(startOffset: Int, endOffset: Int, enumClass: IrClass, name: Name): IrExpression {
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClassDescriptor) val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClass)
val ordinal = loweredEnum.entriesMap[name]!! val ordinal = loweredEnum.entriesMap[name]!!
return IrCallImpl(startOffset, endOffset, loweredEnum.itemGetterSymbol, loweredEnum.itemGetterDescriptor).apply { return irCall(startOffset, endOffset, loweredEnum.itemGetterSymbol.owner, emptyList()).apply {
dispatchReceiver = IrCallImpl(startOffset, endOffset, loweredEnum.valuesGetter.symbol) dispatchReceiver = IrCallImpl(startOffset, endOffset, loweredEnum.valuesGetter.returnType, loweredEnum.valuesGetter.symbol)
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, enumClassDescriptor.module.builtIns.intType, ordinal)) 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 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 loweredEnumConstructors = mutableMapOf<ClassConstructorDescriptor, IrConstructor>()
private val descriptorToIrConstructorWithDefaultArguments = mutableMapOf<ClassConstructorDescriptor, IrConstructor>() private val descriptorToIrConstructorWithDefaultArguments = mutableMapOf<ClassConstructorDescriptor, IrConstructor>()
private val defaultEnumEntryConstructors = mutableMapOf<ClassConstructorDescriptor, IrConstructor>() private val defaultEnumEntryConstructors = mutableMapOf<ClassConstructorDescriptor, IrConstructor>()
@@ -212,7 +213,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
blockBody.statements.transformFlat { blockBody.statements.transformFlat {
if (it is IrEnumConstructorCall) if (it is IrEnumConstructorCall)
listOf(it, IrInstanceInitializerCallImpl(declaration.startOffset, declaration.startOffset, listOf(it, IrInstanceInitializerCallImpl(declaration.startOffset, declaration.startOffset,
irClass.symbol)) irClass.symbol, context.irBuiltIns.unitType))
else null else null
} }
} }
@@ -245,17 +246,22 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val defaultClassDescriptor = ClassDescriptorImpl(descriptor, "DEFAULT".synthesizedName, Modality.FINAL, val defaultClassDescriptor = ClassDescriptorImpl(descriptor, "DEFAULT".synthesizedName, Modality.FINAL,
ClassKind.CLASS, listOf(descriptor.defaultType), SourceElement.NO_SOURCE, false, LockBasedStorageManager.NO_LOCKS) ClassKind.CLASS, listOf(descriptor.defaultType), SourceElement.NO_SOURCE, false, LockBasedStorageManager.NO_LOCKS)
val defaultClass = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, defaultClassDescriptor) val defaultClass = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, defaultClassDescriptor)
defaultClass.createParameterDeclarations()
val constructors = mutableSetOf<ClassConstructorDescriptor>() val constructors = mutableSetOf<ClassConstructorDescriptor>()
descriptor.constructors.forEach { descriptor.constructors.forEach {
val loweredEnumConstructorSymbol = loweredEnumConstructors[it]!!.symbol val loweredEnumIrConstructor = loweredEnumConstructors[it]!!
val loweredEnumConstructor = loweredEnumConstructorSymbol.descriptor val loweredEnumConstructor = loweredEnumIrConstructor.descriptor
val constructorDescriptor = defaultClassDescriptor.createSimpleDelegatingConstructorDescriptor(loweredEnumConstructor)
val constructor = defaultClass.addSimpleDelegatingConstructor( val constructor = defaultClass.addSimpleDelegatingConstructor(
loweredEnumConstructorSymbol, constructorDescriptor, loweredEnumIrConstructor,
DECLARATION_ORIGIN_ENUM) context.irBuiltIns,
DECLARATION_ORIGIN_ENUM
)
val constructorDescriptor = constructor.descriptor
constructors.add(constructorDescriptor) constructors.add(constructorDescriptor)
defaultEnumEntryConstructors.put(loweredEnumConstructor, constructor) defaultEnumEntryConstructors.put(loweredEnumConstructor, constructor)
@@ -273,8 +279,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val memberScope = stub<MemberScope>("enum default class") val memberScope = stub<MemberScope>("enum default class")
defaultClassDescriptor.initialize(memberScope, constructors, null) defaultClassDescriptor.initialize(memberScope, constructors, null)
defaultClass.createParameterDeclarations() defaultClass.setSuperSymbolsAndAddFakeOverrides(listOf(irClass.defaultType))
defaultClass.setSuperSymbolsAndAddFakeOverrides(listOf(irClass))
return defaultClass return defaultClass
} }
@@ -310,12 +315,6 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
++i ++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(createSyntheticValuesPropertyDeclaration(enumEntries))
implObject.addChild(createValuesPropertyInitializer(enumEntries)) implObject.addChild(createValuesPropertyInitializer(enumEntries))
@@ -329,17 +328,19 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val startOffset = irClass.startOffset val startOffset = irClass.startOffset
val endOffset = irClass.endOffset val endOffset = irClass.endOffset
val irValuesInitializer = context.createArrayOfExpression(irClass.descriptor.defaultType, val irValuesInitializer = context.createArrayOfExpression(irClass.defaultType,
enumEntries enumEntries
.sortedBy { it.descriptor.name } .sortedBy { it.descriptor.name }
.map { .map {
val enumEntryClass = ((it.initializerExpression!! as IrCall).descriptor as ConstructorDescriptor).constructedClass val entryConstructorCall = it.initializerExpression!! as IrCall
val typeParameterT = genericCreateUninitializedInstanceDescriptor.typeParameters[0] val entryConstructor = entryConstructorCall.symbol.owner as IrConstructor
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumEntryClass.defaultType))) val entryClass = entryConstructor.constructedClass
val substitutedCreateUninitializedInstance = genericCreateUninitializedInstanceDescriptor.substitute(typeSubstitutor)!!
IrCallImpl(startOffset, endOffset, irCall(startOffset, endOffset,
genericCreateUninitializedInstanceSymbol, substitutedCreateUninitializedInstance, mapOf(typeParameterT to enumEntryClass.defaultType) genericCreateUninitializedInstanceSymbol.owner,
listOf(entryClass.defaultType)
) )
}, startOffset, endOffset) }, startOffset, endOffset)
val irField = loweredEnum.valuesField.apply { val irField = loweredEnum.valuesField.apply {
initializer = IrExpressionBodyImpl(startOffset, endOffset, irValuesInitializer) initializer = IrExpressionBodyImpl(startOffset, endOffset, irValuesInitializer)
@@ -349,8 +350,20 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val receiver = IrGetObjectValueImpl(startOffset, endOffset, val receiver = IrGetObjectValueImpl(startOffset, endOffset,
loweredEnum.implObject.defaultType, loweredEnum.implObject.symbol) loweredEnum.implObject.defaultType, loweredEnum.implObject.symbol)
val value = IrGetFieldImpl(startOffset, endOffset, loweredEnum.valuesField.symbol, receiver) val value = IrGetFieldImpl(
val returnStatement = IrReturnImpl(startOffset, endOffset, loweredEnum.valuesGetter.symbol, value) 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)) getter.body = IrBlockBodyImpl(startOffset, endOffset, listOf(returnStatement))
return IrPropertyImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, 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 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 { private fun createValuesPropertyInitializer(enumEntries: List<IrEnumEntry>): IrAnonymousInitializerImpl {
val startOffset = irClass.startOffset 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 { return IrAnonymousInitializerImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, loweredEnum.implObject.descriptor).apply {
body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody(irClass) { 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 enumEntries
.sortedBy { it.descriptor.name } .sortedBy { it.descriptor.name }
.withIndex() .withIndex()
.forEach { .forEach {
val instance = irCall(arrayGetSymbol).apply { val instance = irCall(arrayGetSymbol).apply {
dispatchReceiver = irGet(instances.symbol) dispatchReceiver = irGet(instances)
putValueArgument(0, irInt(it.index)) putValueArgument(0, irInt(it.index))
} }
val initializer = it.value.initializerExpression!! as IrCall 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 { +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 { private fun createSyntheticValuesMethodBody(declaration: IrFunction): IrBody {
val startOffset = irClass.startOffset val startOffset = irClass.startOffset
val endOffset = irClass.endOffset val endOffset = irClass.endOffset
val valuesExpression = enumSyntheticFunctionsBuilder.buildValuesExpression(startOffset, endOffset, irClass.descriptor) val valuesExpression = enumSyntheticFunctionsBuilder.buildValuesExpression(startOffset, endOffset, irClass)
return IrBlockBodyImpl(startOffset, endOffset, return IrBlockBodyImpl(startOffset, endOffset).apply {
listOf(IrReturnImpl(startOffset, endOffset, declaration.symbol, valuesExpression)) statements += IrReturnImpl(
) startOffset,
endOffset,
context.irBuiltIns.nothingType,
declaration.symbol,
valuesExpression
)
}
} }
private fun createSyntheticValueOfMethodBody(declaration: IrFunction): IrBody { private fun createSyntheticValueOfMethodBody(declaration: IrFunction): IrBody {
val startOffset = irClass.startOffset val startOffset = irClass.startOffset
val endOffset = irClass.endOffset val endOffset = irClass.endOffset
val value = IrGetValueImpl(startOffset, endOffset, declaration.valueParameters[0].symbol) val parameter = declaration.valueParameters[0]
val valueOfExpression = enumSyntheticFunctionsBuilder.buildValueOfExpression(startOffset, endOffset, irClass.descriptor, value) val value = IrGetValueImpl(startOffset, endOffset, parameter.type, parameter.symbol)
val valueOfExpression = enumSyntheticFunctionsBuilder.buildValueOfExpression(startOffset, endOffset, irClass, value)
return IrBlockBodyImpl( return IrBlockBodyImpl(startOffset, endOffset).apply {
startOffset, endOffset, statements += IrReturnImpl(
listOf(IrReturnImpl(startOffset, endOffset, declaration.symbol, valueOfExpression)) startOffset,
) endOffset,
context.irBuiltIns.nothingType,
declaration.symbol,
valueOfExpression
)
}
} }
private fun lowerEnumConstructors(irClass: IrClass) { private fun lowerEnumConstructors(irClass: IrClass) {
@@ -423,18 +448,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
} }
private fun transformEnumConstructor(enumConstructor: IrConstructor): IrConstructor { private fun transformEnumConstructor(enumConstructor: IrConstructor): IrConstructor {
val constructorDescriptor = enumConstructor.descriptor val loweredEnumConstructor = lowerEnumConstructor(enumConstructor)
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()
enumConstructor.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach { enumConstructor.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach {
val body = enumConstructor.getDefault(it)!! val body = enumConstructor.getDefault(it)!!
@@ -443,54 +457,75 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val descriptor = expression.descriptor val descriptor = expression.descriptor
when (descriptor) { when (descriptor) {
is ValueParameterDescriptor -> { is ValueParameterDescriptor -> {
val parameter = loweredEnumConstructor.valueParameters[descriptor.loweredIndex()]
return IrGetValueImpl(expression.startOffset, return IrGetValueImpl(expression.startOffset,
expression.endOffset, expression.endOffset,
loweredEnumConstructor.valueParameters[descriptor.loweredIndex()].symbol) parameter.type,
parameter.symbol)
} }
} }
return expression return expression
} }
}) })
loweredEnumConstructor.putDefault(loweredConstructorDescriptor.valueParameters[it.loweredIndex()], body) loweredEnumConstructor.valueParameters[it.loweredIndex()].defaultValue = body
descriptorToIrConstructorWithDefaultArguments[loweredConstructorDescriptor] = loweredEnumConstructor descriptorToIrConstructorWithDefaultArguments[loweredEnumConstructor.descriptor] = loweredEnumConstructor
} }
return loweredEnumConstructor return loweredEnumConstructor
} }
private fun lowerEnumConstructor(constructorDescriptor: ClassConstructorDescriptor): ClassConstructorDescriptor { private fun lowerEnumConstructor(enumConstructor: IrConstructor): IrConstructorImpl {
val loweredConstructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized( val loweredConstructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
constructorDescriptor.containingDeclaration, enumConstructor.descriptor.containingDeclaration,
constructorDescriptor.annotations, enumConstructor.descriptor.annotations,
constructorDescriptor.isPrimary, enumConstructor.descriptor.isPrimary,
constructorDescriptor.source enumConstructor.descriptor.source
) )
val valueParameters = val valueParameters =
listOf( listOf(
loweredConstructorDescriptor.createValueParameter(0, "name", context.builtIns.stringType), loweredConstructorDescriptor.createValueParameter(
loweredConstructorDescriptor.createValueParameter(1, "ordinal", context.builtIns.intType) 0,
"name",
context.irBuiltIns.stringType,
enumConstructor.startOffset,
enumConstructor.endOffset
),
loweredConstructorDescriptor.createValueParameter(
1,
"ordinal",
context.irBuiltIns.intType,
enumConstructor.startOffset,
enumConstructor.endOffset
)
) + ) +
constructorDescriptor.valueParameters.map { enumConstructor.valueParameters.map {
lowerConstructorValueParameter(loweredConstructorDescriptor, it) 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 loweredConstructorDescriptor.initialize(
valueParameters.map { it.descriptor as ValueParameterDescriptor },
return loweredConstructorDescriptor Visibilities.PROTECTED
}
private fun lowerConstructorValueParameter(
loweredConstructorDescriptor: ClassConstructorDescriptor,
valueParameterDescriptor: ValueParameterDescriptor
): ValueParameterDescriptor {
val loweredValueParameterDescriptor = valueParameterDescriptor.copy(
loweredConstructorDescriptor,
valueParameterDescriptor.name,
valueParameterDescriptor.loweredIndex()
) )
loweredEnumConstructorParameters[valueParameterDescriptor] = loweredValueParameterDescriptor loweredConstructorDescriptor.returnType = enumConstructor.descriptor.returnType
return loweredValueParameterDescriptor 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() { private fun lowerEnumClassBody() {
@@ -505,7 +540,8 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val origin = enumConstructorCall.origin val origin = enumConstructorCall.origin
val result = IrDelegatingConstructorCallImpl(startOffset, endOffset, val result = IrDelegatingConstructorCallImpl(startOffset, endOffset,
enumConstructorCall.symbol, enumConstructorCall.descriptor) context.irBuiltIns.unitType,
enumConstructorCall.symbol, enumConstructorCall.descriptor, enumConstructorCall.typeArgumentsCount)
assert(result.descriptor.valueParameters.size == 2) { assert(result.descriptor.valueParameters.size == 2) {
"Enum(String, Int) constructor call expected:\n${result.dump()}" "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") throw AssertionError("No 'ordinal' parameter in enum constructor: $enumClassConstructor")
} }
result.putValueArgument(0, IrGetValueImpl(startOffset, endOffset, nameParameter.symbol, origin)) result.putValueArgument(0,
result.putValueArgument(1, IrGetValueImpl(startOffset, endOffset, ordinalParameter.symbol, origin)) IrGetValueImpl(startOffset, endOffset, nameParameter.type, nameParameter.symbol, origin)
)
result.putValueArgument(1,
IrGetValueImpl(startOffset, endOffset, ordinalParameter.type, ordinalParameter.symbol, origin)
)
return result 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") throw AssertionError("Constructor called in enum entry initializer should've been lowered: $descriptor")
} }
val result = IrDelegatingConstructorCallImpl(startOffset, endOffset, val result = IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.unitType,
loweredDelegatedConstructor.symbol, loweredDelegatedConstructor.descriptor) loweredDelegatedConstructor.symbol, loweredDelegatedConstructor.descriptor, 0)
val firstParameter = enumClassConstructor.valueParameters[0]
result.putValueArgument(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, result.putValueArgument(1,
IrGetValueImpl(startOffset, endOffset, enumClassConstructor.valueParameters[1].symbol)) IrGetValueImpl(startOffset, endOffset, secondParameter.type, secondParameter.symbol))
descriptor.valueParameters.forEach { valueParameter -> descriptor.valueParameters.forEach { valueParameter ->
result.putValueArgument(valueParameter.loweredIndex(), delegatingConstructorCall.getValueArgument(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) val result = createConstructorCall(startOffset, endOffset, loweredConstructor.symbol)
result.putValueArgument(0, IrConstImpl.string(startOffset, endOffset, context.builtIns.stringType, name)) result.putValueArgument(0,
result.putValueArgument(1, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, ordinal)) IrConstImpl.string(startOffset, endOffset, context.irBuiltIns.stringType, name))
result.putValueArgument(1,
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, ordinal))
descriptor.valueParameters.forEach { valueParameter -> descriptor.valueParameters.forEach { valueParameter ->
val i = valueParameter.index val i = valueParameter.index
@@ -584,14 +628,25 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
} }
private inner class InEnumEntryClassConstructor(enumEntry: ClassDescriptor) : InEnumEntry(enumEntry) { private inner class InEnumEntryClassConstructor(enumEntry: ClassDescriptor) : InEnumEntry(enumEntry) {
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol) override fun createConstructorCall(
= IrDelegatingConstructorCallImpl(startOffset, endOffset, loweredConstructor, loweredConstructor.descriptor) startOffset: Int,
endOffset: Int,
loweredConstructor: IrConstructorSymbol
) = IrDelegatingConstructorCallImpl(
startOffset,
endOffset,
context.irBuiltIns.unitType,
loweredConstructor,
loweredConstructor.descriptor,
0
)
} }
private inner class InEnumEntryInitializer(enumEntry: ClassDescriptor) : InEnumEntry(enumEntry) { private inner class InEnumEntryInitializer(enumEntry: ClassDescriptor) : InEnumEntry(enumEntry) {
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrCall { override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrCall {
return IrCallImpl(startOffset, endOffset, val irConstructorSymbol = defaultEnumEntryConstructors[loweredConstructor.descriptor]?.symbol
defaultEnumEntryConstructors[loweredConstructor.descriptor]?.symbol ?: loweredConstructor) ?: 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 loweredEnumConstructor = loweredEnumConstructors[expression.descriptor.containingDeclaration]!!
val loweredIrParameter = loweredEnumConstructor.valueParameters[loweredParameter.index] val loweredIrParameter = loweredEnumConstructor.valueParameters[loweredParameter.index]
assert(loweredIrParameter.descriptor == loweredParameter) assert(loweredIrParameter.descriptor == loweredParameter)
return IrGetValueImpl(expression.startOffset, expression.endOffset, return IrGetValueImpl(expression.startOffset, expression.endOffset, loweredIrParameter.type,
loweredIrParameter.symbol, expression.origin) loweredIrParameter.symbol, expression.origin)
} else { } else {
return expression return expression
@@ -685,9 +740,11 @@ private class ParameterMapper(val originalConstructor: IrConstructor) : IrElemen
val descriptor = expression.descriptor val descriptor = expression.descriptor
when (descriptor) { when (descriptor) {
is ValueParameterDescriptor -> { is ValueParameterDescriptor -> {
val parameter = originalConstructor.valueParameters[descriptor.index]
return IrGetValueImpl(expression.startOffset, return IrGetValueImpl(expression.startOffset,
expression.endOffset, expression.endOffset,
originalConstructor.valueParameters[descriptor.index].symbol) parameter.type,
parameter.symbol)
} }
} }
return expression 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.pop
import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.Context 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.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin 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.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl 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.getArguments
import org.jetbrains.kotlin.ir.util.getPropertyGetter import org.jetbrains.kotlin.ir.util.getPropertyGetter
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid 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 val subject = irBlock.statements[0] as IrVariable
// Subject should not be nullable because we will access the `ordinal` property. // Subject should not be nullable because we will access the `ordinal` property.
if (subject.type.isNullable()) { if (subject.type.containsNull()) {
return false return false
} }
// Check that subject is enum entry. // Check that subject is enum entry.
val enumClass = subject.type.constructor.declarationDescriptor as? ClassDescriptor val enumClass = subject.type.getClass()
?: return false ?: return false
return enumClass.kind == ClassKind.ENUM_CLASS return enumClass.kind == ClassKind.ENUM_CLASS
} }
@@ -83,14 +86,22 @@ internal class EnumWhenLowering(private val context: Context) : IrElementTransfo
private fun createEnumOrdinalVariable(enumVariable: IrVariable): IrVariable { private fun createEnumOrdinalVariable(enumVariable: IrVariable): IrVariable {
val ordinalPropertyGetter = context.ir.symbols.enum.getPropertyGetter("ordinal")!! val ordinalPropertyGetter = context.ir.symbols.enum.getPropertyGetter("ordinal")!!
val getOrdinal = IrCallImpl(enumVariable.startOffset, enumVariable.endOffset, ordinalPropertyGetter).apply { val getOrdinal = IrCallImpl(
dispatchReceiver = IrGetValueImpl(enumVariable.startOffset, enumVariable.endOffset, enumVariable.symbol) 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. // Create temporary variable for subject's ordinal.
val ordinalDescriptor = IrTemporaryVariableDescriptorImpl(enumVariable.descriptor.containingDeclaration, val ordinalDescriptor = IrTemporaryVariableDescriptorImpl(enumVariable.descriptor.containingDeclaration,
Name.identifier(enumVariable.name.asString() + "_ordinal"), context.builtIns.intType) Name.identifier(enumVariable.name.asString() + "_ordinal"), context.builtIns.intType)
return IrVariableImpl(enumVariable.startOffset, enumVariable.endOffset, 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 { 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 { 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. // 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 lhs = callArgs[0].second
val rhs = callArgs[1].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. // If there is nothing on stack then nothing we can do.
val (topmostSubject, topmostOrdinalProvider) = subjectWithOrdinalStack.peek() val (topmostSubject, topmostOrdinalProvider) = subjectWithOrdinalStack.peek()
?: return call ?: 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 entryOrdinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(rhs.descriptor)
val subjectOrdinal = topmostOrdinalProvider.value val subjectOrdinal = topmostOrdinalProvider.value
return IrCallImpl(call.startOffset, call.endOffset, areEqualByValue).apply { return IrCallImpl(call.startOffset, call.endOffset, areEqualByValue.owner.returnType, areEqualByValue).apply {
putValueArgument(0, IrGetValueImpl(lhs.startOffset, lhs.endOffset, subjectOrdinal.symbol)) putValueArgument(0,
putValueArgument(1, IrConstImpl.int(rhs.startOffset, rhs.endOffset, context.builtIns.intType, entryOrdinal)) IrGetValueImpl(lhs.startOffset, lhs.endOffset, subjectOrdinal.type, subjectOrdinal.symbol))
putValueArgument(1,
IrConstImpl.int(rhs.startOffset, rhs.endOffset, context.irBuiltIns.intType, entryOrdinal))
} }
} }
return call 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.common.FileLoweringPass
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.isExpectMember 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.MemberDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
@@ -79,20 +76,21 @@ internal class ExpectDeclarationsRemoving(val context: Context) : FileLoweringPa
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid() expression.transformChildrenVoid()
val newSymbol = remapExpectValueSymbol(expression.symbol) val newValue = remapExpectValue(expression.symbol)
?: return expression ?: return expression
return IrGetValueImpl( return IrGetValueImpl(
expression.startOffset, expression.startOffset,
expression.endOffset, expression.endOffset,
newSymbol, newValue.type,
newValue.symbol,
expression.origin expression.origin
) )
} }
}, data = null) }, data = null)
} }
private fun remapExpectValueSymbol(symbol: IrValueSymbol): IrValueParameterSymbol? { private fun remapExpectValue(symbol: IrValueSymbol): IrValueParameter? {
if (symbol !is IrValueParameterSymbol) { if (symbol !is IrValueParameterSymbol) {
return null return null
} }
@@ -120,6 +118,6 @@ internal class ExpectDeclarationsRemoving(val context: Context) : FileLoweringPa
} }
else -> error(parent) 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.IrReturnTargetSymbol
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl 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.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isNothing import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, IrElementTransformerVoidWithContext() { internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, IrElementTransformerVoidWithContext() {
private val symbols get() = context.ir.symbols
private interface HighLevelJump { private interface HighLevelJump {
fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression): IrExpression fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression): IrExpression
} }
private data class Return(val target: IrReturnTargetSymbol): HighLevelJump { private data class Return(val target: IrReturnTargetSymbol): HighLevelJump {
override fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression) 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 { private data class Break(val loop: IrLoop): HighLevelJump {
override fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression) 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( statements = listOf(
value, value,
IrBreakImpl(startOffset, endOffset, context.builtIns.nothingType, loop) IrBreakImpl(startOffset, endOffset, context.irBuiltIns.nothingType, loop)
)) ))
} }
private data class Continue(val loop: IrLoop): HighLevelJump { private data class Continue(val loop: IrLoop): HighLevelJump {
override fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression) 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( statements = listOf(
value, 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] val currentTryScope = tryScopes[index]
currentTryScope.jumps.getOrPut(jump) { currentTryScope.jumps.getOrPut(jump) {
val symbol = getIrReturnableBlockSymbol(jump.toString(), value.type) val type = value.type
val symbol = getIrReturnableBlockSymbol(jump.toString(), type)
with(currentTryScope) { with(currentTryScope) {
irBuilder.run { irBuilder.run {
val inlinedFinally = irInlineFinally(symbol, expression, finallyExpression) val inlinedFinally = irInlineFinally(symbol, type, expression, finallyExpression)
expression = performHighLevelJump( expression = performHighLevelJump(
tryScopes = tryScopes, tryScopes = tryScopes,
index = index + 1, index = index + 1,
@@ -201,7 +207,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
return IrReturnImpl( return IrReturnImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
type = context.builtIns.nothingType, type = context.irBuiltIns.nothingType,
returnTargetSymbol = it, returnTargetSymbol = it,
value = value) value = value)
} }
@@ -219,7 +225,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
val transformedTry = IrTryImpl( val transformedTry = IrTryImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
type = context.builtIns.nothingType type = context.irBuiltIns.nothingType
) )
val transformedFinallyExpression = finallyExpression.transform(transformer, null) val transformedFinallyExpression = finallyExpression.transform(transformer, null)
val parameter = IrTemporaryVariableDescriptorImpl( val parameter = IrTemporaryVariableDescriptorImpl(
@@ -228,24 +234,26 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
outType = context.builtIns.throwable.defaultType outType = context.builtIns.throwable.defaultType
) )
val catchParameter = IrVariableImpl( val catchParameter = IrVariableImpl(
startOffset, endOffset, IrDeclarationOrigin.CATCH_PARAMETER, parameter) startOffset, endOffset, IrDeclarationOrigin.CATCH_PARAMETER, parameter,
symbols.throwable.owner.defaultType)
val syntheticTry = IrTryImpl( val syntheticTry = IrTryImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
type = context.builtIns.nothingType, type = context.irBuiltIns.nothingType,
tryResult = transformedTry, tryResult = transformedTry,
catches = listOf( catches = listOf(
irCatch(catchParameter).apply { irCatch(catchParameter).apply {
result = irBlock { result = irBlock {
+finallyExpression.copy() +finallyExpression.copy()
+irThrow(irGet(catchParameter.symbol)) +irThrow(irGet(catchParameter))
} }
}), }),
finallyExpression = null finallyExpression = null
) )
using(TryScope(syntheticTry, transformedFinallyExpression, this)) { 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) val transformedResult = aTry.tryResult.transform(transformer, null)
transformedTry.tryResult = irReturn(fallThroughSymbol, transformedResult) transformedTry.tryResult = irReturn(fallThroughSymbol, transformedResult)
for (aCatch in aTry.catches) { for (aCatch in aTry.catches) {
@@ -253,28 +261,28 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
transformedCatch.result = irReturn(fallThroughSymbol, transformedCatch.result) transformedCatch.result = irReturn(fallThroughSymbol, transformedCatch.result)
transformedTry.catches.add(transformedCatch) 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, value: IrExpression,
finallyExpression: IrExpression): IrExpression { finallyExpression: IrExpression): IrExpression {
val returnType = symbol.descriptor.returnType!! val returnType = symbol.descriptor.returnType!!
return when { return when {
returnType.isUnit() || returnType.isNothing() -> irBlock(value, null, returnType) { returnType.isUnit() || returnType.isNothing() -> irBlock(value, null, type) {
+irReturnableBlock(symbol) { +irReturnableBlock(symbol, type) {
+value +value
} }
+finallyExpression.copy() +finallyExpression.copy()
} }
else -> irBlock(value, null, returnType) { else -> irBlock(value, null, type) {
val tmp = irTemporary(irReturnableBlock(symbol) { val tmp = irTemporary(irReturnableBlock(symbol, type) {
+irReturn(symbol, value) +irReturn(symbol, value)
}) })
+finallyExpression.copy() +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) initialize(null, null, emptyList(), emptyList(), returnType, Modality.ABSTRACT, Visibilities.PRIVATE)
} }
private fun getIrReturnableBlockSymbol(name: String, returnType: KotlinType): IrReturnableBlockSymbol = private fun getIrReturnableBlockSymbol(name: String, returnType: IrType): IrReturnableBlockSymbol =
IrReturnableBlockSymbolImpl(getFakeFunctionDescriptor(name, returnType)) IrReturnableBlockSymbolImpl(getFakeFunctionDescriptor(name, returnType.toKotlinType()))
private inline fun <reified T : IrElement> T.copy() = this.deepCopyWithVariables() private inline fun <reified T : IrElement> T.copy() = this.deepCopyWithVariables()
fun IrBuilderWithScope.irReturn(target: IrReturnTargetSymbol, value: IrExpression) = 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) = inline fun IrBuilderWithScope.irReturnableBlock(symbol: IrReturnableBlockSymbol, type: IrType, body: IrBlockBuilder.() -> Unit) =
IrReturnableBlockImpl(startOffset, endOffset, symbol.descriptor.returnType!!, symbol, null, IrReturnableBlockImpl(startOffset, endOffset, type, symbol, null,
IrBlockBuilder(context, scope, startOffset, endOffset, null, symbol.descriptor.returnType!!) IrBlockBuilder(context, scope, startOffset, endOffset, null, type)
.block(body).statements) .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.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irIfThen import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation 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.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol 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.ir.visitors.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -134,36 +138,40 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
//region Util methods ============================================================================================== //region Util methods ==============================================================================================
private fun IrExpression.castIfNecessary(progressionType: ProgressionType): IrExpression { private fun IrExpression.castIfNecessary(progressionType: ProgressionType): IrExpression {
val type = this.type.toKotlinType()
assert(type in progressionElementClassesTypes || type in progressionElementClassesNullableTypes) assert(type in progressionElementClassesTypes || type in progressionElementClassesNullableTypes)
return if (type == progressionType.elementType) { return if (type == progressionType.elementType) {
this this
} else { } 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 } .apply { dispatchReceiver = this@castIfNecessary }
} }
} }
private fun DeclarationIrBuilder.ensureNotNullable(expression: IrExpression): IrExpression { private fun DeclarationIrBuilder.ensureNotNullable(expression: IrExpression): IrExpression {
return if (expression.type.isMarkedNullable) { return if (expression.type.isSimpleTypeWithQuestionMark) {
irImplicitCast(expression, expression.type.makeNotNullable()) irImplicitCast(expression, expression.type.makeNotNull())
} else { } else {
expression expression
} }
} }
private fun IrExpression.unaryMinus(): IrExpression = private fun IrExpression.unaryMinus(): IrExpression {
IrCallImpl(startOffset, endOffset, symbols.getUnaryOperator(OperatorNameConventions.UNARY_MINUS, type)).apply { val unaryOperator = symbols.getUnaryOperator(OperatorNameConventions.UNARY_MINUS, type.toKotlinType())
dispatchReceiver = this@unaryMinus return IrCallImpl(startOffset, endOffset, unaryOperator.owner.returnType, unaryOperator).apply {
} dispatchReceiver = this@unaryMinus
}
}
private fun ProgressionInfo.defaultStep(startOffset: Int, endOffset: Int): IrExpression = private fun ProgressionInfo.defaultStep(startOffset: Int, endOffset: Int): IrExpression =
progressionType.elementType.let { type -> progressionType.elementType.let { type ->
val step = if (increasing) 1 else -1 val step = if (increasing) 1 else -1
when { when {
KotlinBuiltIns.isInt(type) || KotlinBuiltIns.isChar(type) -> 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) -> KotlinBuiltIns.isLong(type) ->
IrConstImpl.long(startOffset, endOffset, context.builtIns.longType, step.toLong()) IrConstImpl.long(startOffset, endOffset, context.irBuiltIns.longType, step.toLong())
else -> throw IllegalArgumentException() else -> throw IllegalArgumentException()
} }
} }
@@ -178,9 +186,9 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
// Used only by the assert. // Used only by the assert.
private fun stepHasRightType(step: IrExpression, progressionType: ProgressionType) = private fun stepHasRightType(step: IrExpression, progressionType: ProgressionType) =
((progressionType.isCharProgression() || progressionType.isIntProgression()) && ((progressionType.isCharProgression() || progressionType.isIntProgression()) &&
KotlinBuiltIns.isInt(step.type.makeNotNullable())) || KotlinBuiltIns.isInt(step.type.toKotlinType().makeNotNullable())) ||
(progressionType.isLongProgression() && (progressionType.isLongProgression() &&
KotlinBuiltIns.isLong(step.type.makeNotNullable())) KotlinBuiltIns.isLong(step.type.toKotlinType().makeNotNullable()))
private fun irCheckProgressionStep(progressionType: ProgressionType, private fun irCheckProgressionStep(progressionType: ProgressionType,
step: IrExpression): Pair<IrExpression, Boolean> { step: IrExpression): Pair<IrExpression, Boolean> {
@@ -193,25 +201,25 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
// so there is no need to cast it. // so there is no need to cast it.
assert(stepHasRightType(step, progressionType)) 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}") ?: 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) putValueArgument(0, step)
} to true } to true
} }
private fun irGetProgressionLast(progressionType: ProgressionType, private fun irGetProgressionLast(progressionType: ProgressionType,
first: IrVariableSymbol, first: IrVariable,
lastExpression: IrExpression, lastExpression: IrExpression,
step: IrVariableSymbol): IrExpression { step: IrVariable): IrExpression {
val symbol = symbols.getProgressionLast[progressionType.elementType] val symbol = symbols.getProgressionLast[progressionType.elementType]
?: throw IllegalArgumentException("Unknown progression element type: ${lastExpression.type}") ?: throw IllegalArgumentException("Unknown progression element type: ${lastExpression.type}")
val startOffset = lastExpression.startOffset val startOffset = lastExpression.startOffset
val endOffset = lastExpression.endOffset val endOffset = lastExpression.endOffset
return IrCallImpl(startOffset, lastExpression.endOffset, symbol).apply { return IrCallImpl(startOffset, lastExpression.endOffset, symbol.owner.returnType, symbol).apply {
putValueArgument(0, IrGetValueImpl(startOffset, endOffset, first)) putValueArgument(0, IrGetValueImpl(startOffset, endOffset, first.type, first.symbol))
putValueArgument(1, lastExpression.castIfNecessary(progressionType)) putValueArgument(1, lastExpression.castIfNecessary(progressionType))
putValueArgument(2, IrGetValueImpl(startOffset, endOffset, step)) putValueArgument(2, IrGetValueImpl(startOffset, endOffset, step.type, step.symbol))
} }
} }
//endregion //endregion
@@ -236,11 +244,11 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
/** Contains information about variables used in the loop. */ /** Contains information about variables used in the loop. */
private data class ForLoopInfo( private data class ForLoopInfo(
val progressionInfo: ProgressionInfo, val progressionInfo: ProgressionInfo,
val inductionVariable: IrVariableSymbol, val inductionVariable: IrVariable,
val bound: IrVariableSymbol, val bound: IrVariable,
val last: IrVariableSymbol, val last: IrVariable,
val step: IrVariableSymbol, val step: IrVariable,
var loopVariable: IrVariableSymbol? = null) var loopVariable: IrVariable? = null)
private inner class ProgressionInfoBuilder : IrElementVisitor<ProgressionInfo?, Nothing?> { 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 visitElement(element: IrElement, data: Nothing?): ProgressionInfo? = null
override fun visitCall(expression: IrCall, data: Nothing?): ProgressionInfo? { override fun visitCall(expression: IrCall, data: Nothing?): ProgressionInfo? {
val type = expression.type val type = expression.type.toKotlinType()
val progressionType = when { val progressionType = when {
type.isSubtypeOf(symbols.charProgression.descriptor.defaultType) -> CHAR_PROGRESSION type.isSubtypeOf(symbols.charProgression.descriptor.defaultType) -> CHAR_PROGRESSION
type.isSubtypeOf(symbols.intProgression.descriptor.defaultType) -> INT_PROGRESSION type.isSubtypeOf(symbols.intProgression.descriptor.defaultType) -> INT_PROGRESSION
@@ -362,15 +370,15 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
var lastExpression: IrExpression? = null var lastExpression: IrExpression? = null
if (!closed) { if (!closed) {
val decrementSymbol = symbols.getUnaryOperator(OperatorNameConventions.DEC, boundValue.descriptor.type) val decrementSymbol = symbols.getUnaryOperator(OperatorNameConventions.DEC, boundValue.descriptor.type)
lastExpression = irCall(decrementSymbol).apply { lastExpression = irCall(decrementSymbol.owner).apply {
dispatchReceiver = irGet(boundValue.symbol) dispatchReceiver = irGet(boundValue)
} }
} }
if (needLastCalculation) { if (needLastCalculation) {
lastExpression = irGetProgressionLast(progressionType, lastExpression = irGetProgressionLast(progressionType,
inductionVariable.symbol, inductionVariable,
lastExpression ?: irGet(boundValue.symbol), lastExpression ?: irGet(boundValue),
stepValue.symbol) stepValue)
} }
val lastValue = if (lastExpression != null) { val lastValue = if (lastExpression != null) {
scope.createTemporaryVariable(lastExpression, scope.createTemporaryVariable(lastExpression,
@@ -383,12 +391,12 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
} }
iteratorToLoopInfo[symbol] = ForLoopInfo(progressionInfo, iteratorToLoopInfo[symbol] = ForLoopInfo(progressionInfo,
inductionVariable.symbol, inductionVariable,
boundValue.symbol, boundValue,
lastValue.symbol, lastValue,
stepValue.symbol) 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.inductionVariable.descriptor.type,
forLoopInfo.step.descriptor.type forLoopInfo.step.descriptor.type
) )
forLoopInfo.loopVariable = variable.symbol forLoopInfo.loopVariable = variable
with(builder) { with(builder) {
variable.initializer = irGet(forLoopInfo.inductionVariable) variable.initializer = irGet(forLoopInfo.inductionVariable)
val increment = irSetVar(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, return IrCompositeImpl(variable.startOffset,
variable.endOffset, variable.endOffset,
context.irBuiltIns.unit, context.irBuiltIns.unitType,
IrStatementOrigin.FOR_LOOP_NEXT, IrStatementOrigin.FOR_LOOP_NEXT,
listOf(variable, increment)) listOf(variable, increment))
} }
@@ -427,16 +435,16 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
return irCall(context.irBuiltIns.greaterFunByOperandType[context.irBuiltIns.int]?.symbol!!).apply { return irCall(context.irBuiltIns.greaterFunByOperandType[context.irBuiltIns.int]?.symbol!!).apply {
val minConst = when { val minConst = when {
progressionType.isIntProgression() -> IrConstImpl progressionType.isIntProgression() -> IrConstImpl
.int(startOffset, endOffset, context.builtIns.intType, Int.MIN_VALUE) .int(startOffset, endOffset, context.irBuiltIns.intType, Int.MIN_VALUE)
progressionType.isCharProgression() -> IrConstImpl progressionType.isCharProgression() -> IrConstImpl
.char(startOffset, endOffset, context.builtIns.charType, 0.toChar()) .char(startOffset, endOffset, context.irBuiltIns.charType, 0.toChar())
progressionType.isLongProgression() -> IrConstImpl 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") else -> throw IllegalArgumentException("Unknown progression type")
} }
val compareToCall = irCall(symbols.getBinaryOperator(OperatorNameConventions.COMPARE_TO, val compareToCall = irCall(symbols.getBinaryOperator(OperatorNameConventions.COMPARE_TO,
forLoopInfo.bound.descriptor.type, forLoopInfo.bound.descriptor.type,
minConst.type)).apply { minConst.type.toKotlinType())).apply {
dispatchReceiver = irGet(forLoopInfo.bound) dispatchReceiver = irGet(forLoopInfo.bound)
putValueArgument(0, minConst) putValueArgument(0, minConst)
} }
@@ -458,7 +466,7 @@ private class ForLoopsTransformer(val context: Context) : IrElementTransformerVo
forLoopInfo.last.descriptor.type) forLoopInfo.last.descriptor.type)
val check: IrExpression = irCall(comparingBuiltIn!!).apply { 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)) 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.IrReturnableBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl 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.getArguments
import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -66,7 +67,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
fun inline(irModule: IrModuleFragment): IrElement { fun inline(irModule: IrModuleFragment): IrElement {
val transformedModule = irModule.accept(this, null) 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 return transformedModule
} }
@@ -157,8 +158,8 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
irBuilder.run { irBuilder.run {
val constructorDescriptor = delegatingConstructorCall.descriptor.original val constructorDescriptor = delegatingConstructorCall.descriptor.original
val constructorCall = irCall(delegatingConstructorCall.symbol, val constructorCall = irCall(delegatingConstructorCall.symbol, callee.type,
constructorDescriptor.typeParameters.associate { it to delegatingConstructorCall.getTypeArgument(it)!! }).apply { constructorDescriptor.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply {
constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) } constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) }
} }
val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter
@@ -167,12 +168,12 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this" nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this"
) )
statements[0] = newThis statements[0] = newThis
substituteMap[oldThis] = irGet(newThis.symbol) substituteMap[oldThis] = irGet(newThis)
statements.add(irReturn(irGet(newThis.symbol))) 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 sourceFileName = context.ir.originalModuleIndex.declarationToFile[caller.descriptor.original]?:""
val inlineFunctionBody = IrReturnableBlockImpl( // Create new IR element to replace "call". val inlineFunctionBody = IrReturnableBlockImpl( // Create new IR element to replace "call".
startOffset = startOffset, startOffset = startOffset,
@@ -235,6 +236,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val immediateCall = IrCallImpl( val immediateCall = IrCallImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
type = expression.type,
symbol = functionArgument.symbol, symbol = functionArgument.symbol,
descriptor = functionArgument.descriptor).apply { descriptor = functionArgument.descriptor).apply {
functionParameters.forEach { functionParameters.forEach {
@@ -290,7 +292,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val substitutionContext = mutableMapOf<TypeConstructor, TypeProjection>() val substitutionContext = mutableMapOf<TypeConstructor, TypeProjection>()
for (index in 0 until irCall.typeArgumentsCount) { for (index in 0 until irCall.typeArgumentsCount) {
val typeArgument = irCall.getTypeArgument(index) ?: continue val typeArgument = irCall.getTypeArgument(index) ?: continue
substitutionContext[typeParameters[index].typeConstructor] = TypeProjectionImpl(typeArgument) substitutionContext[typeParameters[index].typeConstructor] = TypeProjectionImpl(typeArgument.toKotlinType())
} }
return TypeSubstitutor.create(substitutionContext) return TypeSubstitutor.create(substitutionContext)
} }
@@ -359,8 +361,9 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
} }
val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>() val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>()
functionDescriptor.valueParameters.forEach { parameterDescriptor -> // Iterate value parameter descriptors. irFunction.valueParameters.forEach { parameter -> // Iterate value parameters.
val argument = valueArguments[parameterDescriptor.index] // Get appropriate argument from call site. val parameterDescriptor = parameter.descriptor as ValueParameterDescriptor
val argument = valueArguments[parameterDescriptor.index] // Get appropriate argument from call site.
when { when {
argument != null -> { // Argument is good enough. argument != null -> { // Argument is good enough.
parameterToArgument += ParameterToArgument( // Associate current parameter with the argument. parameterToArgument += ParameterToArgument( // Associate current parameter with the argument.
@@ -381,8 +384,8 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val emptyArray = IrVarargImpl( val emptyArray = IrVarargImpl(
startOffset = irCall.startOffset, startOffset = irCall.startOffset,
endOffset = irCall.endOffset, endOffset = irCall.endOffset,
type = parameterDescriptor.type, type = parameter.type,
varargElementType = parameterDescriptor.varargElementType!! varargElementType = parameter.varargElementType!!
) )
parameterToArgument += ParameterToArgument( parameterToArgument += ParameterToArgument(
parameterDescriptor = parameterDescriptor, parameterDescriptor = parameterDescriptor,
@@ -432,7 +435,8 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
val getVal = IrGetValueImpl( // Create new expression, representing access the new variable. val getVal = IrGetValueImpl( // Create new expression, representing access the new variable.
startOffset = currentScope.irElement.startOffset, startOffset = currentScope.irElement.startOffset,
endOffset = currentScope.irElement.endOffset, 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. 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.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.util.addChild 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.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -64,7 +64,7 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement { override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement {
initializers.add(IrBlockImpl(declaration.startOffset, declaration.endOffset, 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 return declaration
} }
@@ -72,11 +72,16 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
val initializer = declaration.initializer ?: return declaration val initializer = declaration.initializer ?: return declaration
val startOffset = initializer.startOffset val startOffset = initializer.startOffset
val endOffset = initializer.endOffset 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( listOf(
IrSetFieldImpl(startOffset, endOffset, declaration.symbol, IrSetFieldImpl(startOffset, endOffset, declaration.symbol,
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol), IrGetValueImpl(
initializer.expression, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER)))) startOffset, endOffset,
irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol
),
initializer.expression,
context.irBuiltIns.unitType,
STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER))))
declaration.initializer = null declaration.initializer = null
return declaration return declaration
} }
@@ -109,9 +114,13 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
val startOffset = irClass.startOffset val startOffset = irClass.startOffset
val endOffset = irClass.endOffset val endOffset = irClass.endOffset
val initializer = IrFunctionImpl(startOffset, endOffset, DECLARATION_ORIGIN_ANONYMOUS_INITIALIZER, 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 { initializers.forEach {
it.transformChildrenVoid(object : IrElementTransformerVoid() { it.transformChildrenVoid(object : IrElementTransformerVoid() {
@@ -120,6 +129,7 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
return IrGetValueImpl( return IrGetValueImpl(
expression.startOffset, expression.startOffset,
expression.endOffset, expression.endOffset,
initializer.dispatchReceiverParameter!!.type,
initializer.dispatchReceiverParameter!!.symbol initializer.dispatchReceiverParameter!!.symbol
) )
} else { } else {
@@ -129,7 +139,7 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
}) })
} }
irClass.addChild(initializer) irClass.declarations.add(initializer)
return initializer.symbol return initializer.symbol
} }
@@ -156,8 +166,13 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
} else { } else {
val startOffset = it.startOffset val startOffset = it.startOffset
val endOffset = it.endOffset val endOffset = it.endOffset
listOf(IrCallImpl(startOffset, endOffset, initializerMethodSymbol).apply { listOf(IrCallImpl(startOffset, endOffset,
dispatchReceiver = IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol) 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.addChild
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
internal class InnerClassLowering(val context: Context) : ClassLoweringPass { internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
@@ -57,7 +56,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
} }
private fun createOuterThisField() { private fun createOuterThisField() {
val field = context.specialDeclarationsFactory.getOuterThisField(classDescriptor) val field = context.specialDeclarationsFactory.getOuterThisField(irClass)
outerThisFieldSymbol = field.symbol outerThisFieldSymbol = field.symbol
irClass.addChild(field) irClass.addChild(field)
} }
@@ -78,12 +77,15 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
?: throw AssertionError("Unexpected constructor body: ${irConstructor.body}") ?: throw AssertionError("Unexpected constructor body: ${irConstructor.body}")
val startOffset = irConstructor.startOffset val startOffset = irConstructor.startOffset
val endOffset = irConstructor.endOffset val endOffset = irConstructor.endOffset
val thisReceiver = irClass.thisReceiver!!
val outerReceiver = irConstructor.dispatchReceiverParameter!!
blockBody.statements.add( blockBody.statements.add(
0, 0,
IrSetFieldImpl( IrSetFieldImpl(
startOffset, endOffset, outerThisFieldSymbol, startOffset, endOffset, outerThisFieldSymbol,
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol), IrGetValueImpl(startOffset, endOffset, thisReceiver.type, thisReceiver.symbol),
IrGetValueImpl(startOffset, endOffset, irConstructor.dispatchReceiverParameter!!.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 val origin = expression.origin
var irThis: IrExpression var irThis: IrExpression
var innerClass: ClassDescriptor var innerClass: IrClass
if (constructorSymbol == null || constructorSymbol.descriptor.constructedClass != classDescriptor) { if (constructorSymbol == null || constructorSymbol.descriptor.constructedClass != classDescriptor) {
innerClass = classDescriptor innerClass = irClass
val currentIrFunction = currentFunction!!.scope.scopeOwnerSymbol.owner as IrFunction val currentIrFunction = currentFunction!!.scope.scopeOwnerSymbol.owner as IrFunction
val currentFunctionReceiver = currentIrFunction.dispatchReceiverParameter val currentFunctionReceiver = currentIrFunction.dispatchReceiverParameter
val thisSymbol = if (currentFunctionReceiver?.descriptor == irClass.thisReceiver!!.descriptor) { val thisParameter = if (currentFunctionReceiver?.descriptor == irClass.thisReceiver!!.descriptor) {
currentFunctionReceiver currentFunctionReceiver
} else { } else {
irClass.thisReceiver!! irClass.thisReceiver!!
}.symbol }
irThis = IrGetValueImpl(startOffset, endOffset, thisSymbol, origin) irThis = IrGetValueImpl(startOffset, endOffset, thisParameter.type, thisParameter.symbol, origin)
} else { } else {
// For constructor we have outer class as dispatchReceiverParameter. // 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") throw AssertionError("No containing class for inner class $classDescriptor")
irThis = IrGetValueImpl(startOffset, endOffset, val thisParameter = constructorSymbol.owner.dispatchReceiverParameter!!
constructorSymbol.owner.dispatchReceiverParameter!!.symbol, origin) irThis = IrGetValueImpl(startOffset, endOffset, thisParameter.type, thisParameter.symbol, origin)
} }
while (innerClass != implicitThisClass) { while (innerClass.descriptor != implicitThisClass) {
if (!innerClass.isInner) { if (!innerClass.isInner) {
// Captured 'this' unrelated to inner classes nesting hierarchy, leave it as is - // Captured 'this' unrelated to inner classes nesting hierarchy, leave it as is -
// should be transformed by closures conversion. // should be transformed by closures conversion.
@@ -137,11 +139,16 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
} }
val outerThisField = context.specialDeclarationsFactory.getOuterThisField(innerClass) 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 val outer = innerClass.parent
innerClass = outer as? ClassDescriptor ?: innerClass = outer as? IrClass ?:
throw AssertionError("Unexpected containing declaration for inner class $innerClass: $outer") throw AssertionError("Unexpected containing declaration for inner class ${innerClass.descriptor}: $outer")
} }
return irThis return irThis
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.backend.konan.lower package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass 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.lower.*
import org.jetbrains.kotlin.backend.common.peek import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.backend.common.pop 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.allOverriddenDescriptors
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructors import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
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.descriptors.* 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.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl 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.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl 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.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName 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.constants.StringValue
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny 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 { 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 { private fun IrBuilderWithScope.getObjCClass(classSymbol: IrClassSymbol): IrExpression {
val classDescriptor = classSymbol.descriptor val classDescriptor = classSymbol.descriptor
assert(!classDescriptor.isObjCMetaClass()) assert(!classDescriptor.isObjCMetaClass())
return irCall(symbols.interopGetObjCClass, listOf(classDescriptor.defaultType)) return irCall(symbols.interopGetObjCClass, symbols.nativePtrType, listOf(classSymbol.typeWithStarProjections))
} }
private val outerClasses = mutableListOf<IrClass>() private val outerClasses = mutableListOf<IrClass>()
@@ -131,7 +129,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
val superClass = irClass.getSuperClassNotAny()!! val superClass = irClass.getSuperClassNotAny()!!
val superConstructors = superClass.constructors.filter { val superConstructors = superClass.constructors.filter {
constructor.overridesConstructor(it) constructor.overridesConstructor(it)
} }.toList()
val superConstructor = superConstructors.singleOrNull() ?: run { val superConstructor = superConstructors.singleOrNull() ?: run {
val annotation = context.interopBuiltIns.objCOverrideInit.name val annotation = context.interopBuiltIns.objCOverrideInit.name
@@ -179,38 +177,42 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
initMethod.name, initMethod.name,
CallableMemberDescriptor.Kind.DECLARATION, CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE SourceElement.NO_SOURCE
).apply { )
val valueParameters = initMethod.valueParameters.map {
ValueParameterDescriptorImpl( val valueParameters = initMethod.valueParameters.map {
this, val descriptor = ValueParameterDescriptorImpl(
null, resultDescriptor,
it.index,
Annotations.EMPTY,
it.name,
it.type,
false,
false,
false,
it.varargElementType,
SourceElement.NO_SOURCE
)
}
initialize(
null, null,
irClass.descriptor.thisAsReceiverParameter, it.index,
emptyList<TypeParameterDescriptor>(), Annotations.EMPTY,
valueParameters, it.name,
irClass.defaultType, it.descriptor.type,
Modality.OPEN, false,
Visibilities.PUBLIC 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( return IrFunctionImpl(
constructor.startOffset, constructor.endOffset, OVERRIDING_INITIALIZER_BY_CONSTRUCTOR, constructor.startOffset, constructor.endOffset, OVERRIDING_INITIALIZER_BY_CONSTRUCTOR,
resultDescriptor resultDescriptor
).also { result -> ).also { result ->
result.createParameterDeclarations() result.returnType = irClass.defaultType
result.parent = irClass
result.createDispatchReceiverParameter()
result.valueParameters += valueParameters
result.overriddenSymbols.add(initMethod.symbol) result.overriddenSymbols.add(initMethod.symbol)
result.descriptor.overriddenDescriptors = listOf(initMethod.descriptor) 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) { result.body = context.createIrBuilder(result.symbol).irBlockBody(result) {
+irReturn( +irReturn(
irCall(symbols.interopObjCObjectInitBy, listOf(irClass.defaultType)).apply { irCall(symbols.interopObjCObjectInitBy, listOf(irClass.defaultType)).apply {
extensionReceiver = irGet(result.dispatchReceiverParameter!!.symbol) extensionReceiver = irGet(result.dispatchReceiverParameter!!)
putValueArgument(0, irCall(constructor.symbol).also { putValueArgument(0, irCall(constructor).also {
result.valueParameters.forEach { parameter -> 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") IrDeclarationOriginImpl("OVERRIDING_INITIALIZER_BY_CONSTRUCTOR")
private fun IrConstructor.overridesConstructor(other: IrConstructor): Boolean { private fun IrConstructor.overridesConstructor(other: IrConstructor): Boolean {
return this.valueParameters.size == other.valueParameters.size && return this.descriptor.valueParameters.size == other.descriptor.valueParameters.size &&
this.valueParameters.all { this.descriptor.valueParameters.all {
val otherParameter = other.valueParameters[it.index] val otherParameter = other.descriptor.valueParameters[it.index]
it.name == otherParameter.name && it.type == otherParameter.type 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()) { 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", "Only 'Unit' is supported here",
currentFile, function currentFile, function
) )
@@ -303,7 +305,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
private fun getMethodSignatureEncoding(function: IrFunction): String { private fun getMethodSignatureEncoding(function: IrFunction): String {
assert(function.extensionReceiverParameter == null) assert(function.extensionReceiverParameter == null)
assert(function.valueParameters.all { it.type.isObjCObjectType() }) 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. // Note: these values are valid for x86_64 and arm64.
return when (function.valueParameters.size) { return when (function.valueParameters.size) {
@@ -319,10 +321,10 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
private fun generateFunctionImp(selector: String, function: IrFunction): IrSimpleFunction { private fun generateFunctionImp(selector: String, function: IrFunction): IrSimpleFunction {
val signatureEncoding = getMethodSignatureEncoding(function) val signatureEncoding = getMethodSignatureEncoding(function)
val returnType = function.descriptor.returnType!! val returnType = function.returnType
assert(returnType.isUnit()) assert(returnType.isUnit())
val nativePtrType = context.builtIns.nativePtr.defaultType val nativePtrType = context.ir.symbols.nativePtrType
val parameterTypes = mutableListOf(nativePtrType) // id self val parameterTypes = mutableListOf(nativePtrType) // id self
@@ -353,7 +355,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
index, index,
Annotations.EMPTY, Annotations.EMPTY,
Name.identifier("p$index"), Name.identifier("p$index"),
it, it.toKotlinType(),
false, false,
false, false,
false, false,
@@ -366,7 +368,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
null, null, null, null,
emptyList(), emptyList(),
valueParameters, valueParameters,
returnType, function.descriptor.returnType,
Modality.FINAL, Modality.FINAL,
Visibilities.PRIVATE Visibilities.PRIVATE
) )
@@ -375,20 +377,33 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
function.startOffset, function.endOffset, function.startOffset, function.endOffset,
IrDeclarationOrigin.DEFINED, IrDeclarationOrigin.DEFINED,
newDescriptor 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) val builder = context.createIrBuilder(newFunction.symbol)
newFunction.body = builder.irBlockBody(newFunction) { newFunction.body = builder.irBlockBody(newFunction) {
+irCall(function.symbol).apply { +irCall(function).apply {
dispatchReceiver = interpretObjCPointer( dispatchReceiver = interpretObjCPointer(
irGet(newFunction.valueParameters[0].symbol), irGet(newFunction.valueParameters[0]),
function.dispatchReceiverParameter!!.type function.dispatchReceiverParameter!!.type
) )
function.valueParameters.forEachIndexed { index, parameter -> function.valueParameters.forEachIndexed { index, parameter ->
putValueArgument(index, putValueArgument(index,
interpretObjCPointer( interpretObjCPointer(
irGet(newFunction.valueParameters[index + 2].symbol), irGet(newFunction.valueParameters[index + 2]),
parameter.type parameter.type
) )
) )
@@ -399,8 +414,8 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
return newFunction return newFunction
} }
private fun IrBuilderWithScope.interpretObjCPointer(expression: IrExpression, type: KotlinType): IrExpression { private fun IrBuilderWithScope.interpretObjCPointer(expression: IrExpression, type: IrType): IrExpression {
val callee: IrFunctionSymbol = if (TypeUtils.isNullableType(type)) { val callee: IrFunctionSymbol = if (type.containsNull()) {
symbols.interopInterpretObjCPointerOrNull symbols.interopInterpretObjCPointerOrNull
} else { } else {
symbols.interopInterpretObjCPointer symbols.interopInterpretObjCPointer
@@ -534,7 +549,7 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
val initCall = builder.genLoweredObjCMethodCall( val initCall = builder.genLoweredObjCMethodCall(
initMethodInfo, initMethodInfo,
superQualifier = symbolTable.referenceClass(expression.descriptor.constructedClass), 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)!! } arguments = initMethod.valueParameters.map { expression.getValueArgument(it)!! }
) )
@@ -544,10 +559,17 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
return builder.irBlock(expression) { return builder.irBlock(expression) {
// Required for the IR to be valid, will be ignored in codegen: // 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 { +irCall(symbols.interopObjCObjectSuperInitCheck).apply {
extensionReceiver = irGet(constructedClass.thisReceiver!!.symbol) extensionReceiver = irGet(constructedClass.thisReceiver!!)
putValueArgument(0, initCall) putValueArgument(0, initCall)
} }
} }
@@ -560,10 +582,10 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
receiver: IrExpression, arguments: List<IrExpression>): IrExpression { receiver: IrExpression, arguments: List<IrExpression>): IrExpression {
val superClass = superQualifier?.let { getObjCClass(it) } ?: val superClass = superQualifier?.let { getObjCClass(it) } ?:
irCall(symbols.getNativeNullPtr) irCall(symbols.getNativeNullPtr, symbols.nativePtrType)
val bridge = symbolTable.referenceSimpleFunction(info.bridge) val bridge = symbolTable.referenceSimpleFunction(info.bridge)
return irCall(bridge).apply { return irCall(bridge, symbolTable.translateErased(info.bridge.returnType!!)).apply {
putValueArgument(0, superClass) putValueArgument(0, superClass)
putValueArgument(1, receiver) putValueArgument(1, receiver)
@@ -646,18 +668,16 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
return when (descriptor) { return when (descriptor) {
context.interopBuiltIns.typeOf -> { context.interopBuiltIns.typeOf -> {
val typeArgument = expression.getSingleTypeArgument() val typeArgument = expression.getSingleTypeArgument()
val classDescriptor = TypeUtils.getClassDescriptor(typeArgument) val classSymbol = typeArgument.classifierOrNull as? IrClassSymbol
if (classDescriptor == null) { if (classSymbol == null) {
expression expression
} else { } else {
val companionObjectDescriptor = classDescriptor.companionObjectDescriptor ?: val classDescriptor = classSymbol.descriptor
val companionObject = classDescriptor.companionObjectDescriptor ?:
error("native variable class $classDescriptor must have the companion object") error("native variable class $classDescriptor must have the companion object")
IrGetObjectValueImpl( builder.at(expression).irGetObject(symbolTable.referenceClass(companionObject))
expression.startOffset, expression.endOffset, companionObjectDescriptor.defaultType,
symbolTable.referenceClass(companionObjectDescriptor)
)
} }
} }
else -> expression else -> expression
@@ -674,14 +694,14 @@ internal class InteropLoweringPart1(val context: Context) : IrBuildingTransforme
val initCall = genLoweredObjCMethodCall( val initCall = genLoweredObjCMethodCall(
initMethodInfo, initMethodInfo,
superQualifier = null, superQualifier = null,
receiver = irGet(allocated.symbol), receiver = irGet(allocated),
arguments = arguments arguments = arguments
) )
+IrTryImpl(startOffset, endOffset, initCall.type).apply { +IrTryImpl(startOffset, endOffset, initCall.type).apply {
tryResult = initCall tryResult = initCall
finallyExpression = irCall(symbols.interopObjCRelease).apply { 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 targetSymbol = irCallableReference.symbol
val target = targetSymbol.descriptor val target = targetSymbol.owner
val signatureTypes = target.allParameters.map { it.type } + target.returnType!! val signatureTypes = target.allParameters.map { it.type } + target.returnType
signatureTypes.forEachIndexed { index, type -> signatureTypes.forEachIndexed { index, type ->
type.ensureSupportedInCallbacks( type.ensureSupportedInCallbacks(
@@ -781,9 +801,10 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
} }
descriptor.typeParameters.forEachIndexed { index, typeParameterDescriptor -> descriptor.typeParameters.forEachIndexed { index, typeParameterDescriptor ->
val typeArgument = expression.getTypeArgument(typeParameterDescriptor)!! val typeArgument = expression.getTypeArgument(typeParameterDescriptor)!!.toKotlinType()
val signatureType = signatureTypes[index] val signatureType = signatureTypes[index].toKotlinType()
if (typeArgument != signatureType) { if (typeArgument.constructor != signatureType.constructor ||
typeArgument.isMarkedNullable != signatureType.isMarkedNullable) {
context.reportCompilationError( context.reportCompilationError(
"C function signature element mismatch: expected '$signatureType', got '$typeArgument'", "C function signature element mismatch: expected '$signatureType', got '$typeArgument'",
irFile, expression irFile, expression
@@ -794,8 +815,8 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
IrFunctionReferenceImpl( IrFunctionReferenceImpl(
builder.startOffset, builder.endOffset, builder.startOffset, builder.endOffset,
expression.type, expression.type,
targetSymbol, target, targetSymbol, target.descriptor,
typeArguments = null) typeArgumentsCount = 0)
} }
interop.scheduleFunction -> { interop.scheduleFunction -> {
@@ -812,9 +833,9 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
val target = targetSymbol.descriptor val target = targetSymbol.descriptor
val jobPointer = IrFunctionReferenceImpl( val jobPointer = IrFunctionReferenceImpl(
builder.startOffset, builder.endOffset, builder.startOffset, builder.endOffset,
interop.cPointer.defaultType, symbols.scheduleImpl.owner.valueParameters[3].type,
targetSymbol, target, targetSymbol, target,
typeArguments = null) typeArgumentsCount = 0)
builder.irCall(symbols.scheduleImpl).apply { builder.irCall(symbols.scheduleImpl).apply {
putValueArgument(0, expression.dispatchReceiver) putValueArgument(0, expression.dispatchReceiver)
@@ -827,33 +848,36 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
interop.signExtend, interop.narrow -> { interop.signExtend, interop.narrow -> {
val integerTypePredicates = arrayOf( val integerTypePredicates = arrayOf(
KotlinBuiltIns::isByte, KotlinBuiltIns::isShort, KotlinBuiltIns::isInt, KotlinBuiltIns::isLong IrType::isByte, IrType::isShort, IrType::isInt, IrType::isLong
) )
val receiver = expression.extensionReceiver!! val receiver = expression.extensionReceiver!!
val typeOperand = expression.getSingleTypeArgument() val typeOperand = expression.getSingleTypeArgument()
val kotlinTypeOperand = typeOperand.toKotlinType()
val receiverTypeIndex = integerTypePredicates.indexOfFirst { it(receiver.type) } val receiverTypeIndex = integerTypePredicates.indexOfFirst { it(receiver.type) }
val typeOperandIndex = integerTypePredicates.indexOfFirst { it(typeOperand) } val typeOperandIndex = integerTypePredicates.indexOfFirst { it(typeOperand) }
val receiverKotlinType = receiver.type.toKotlinType()
if (receiverTypeIndex == -1) { 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) irFile, receiver)
} }
if (typeOperandIndex == -1) { 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) irFile, expression)
} }
when (descriptor) { when (descriptor) {
interop.signExtend -> if (receiverTypeIndex > typeOperandIndex) { 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) irFile, expression)
} }
interop.narrow -> if (receiverTypeIndex < typeOperandIndex) { interop.narrow -> if (receiverTypeIndex < typeOperandIndex) {
context.reportCompilationError("unable to narrow ${receiver.type} to $typeOperand", context.reportCompilationError("unable to narrow $receiverKotlinType to $kotlinTypeOperand",
irFile, expression) irFile, expression)
} }
@@ -863,8 +887,12 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
val receiverClass = symbols.integerClasses.single { val receiverClass = symbols.integerClasses.single {
receiver.type.isSubtypeOf(it.owner.defaultType) receiver.type.isSubtypeOf(it.owner.defaultType)
} }
val targetClass = symbols.integerClasses.single {
typeOperand.isSubtypeOf(it.owner.defaultType)
}
val conversionSymbol = receiverClass.functions.single { 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 { builder.irCall(conversionSymbol).apply {
@@ -880,16 +908,16 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
returnType.checkCTypeNullability(::reportError) returnType.checkCTypeNullability(::reportError)
val invokeImpl = symbols.interopInvokeImpls[TypeUtils.getClassDescriptor(returnType)] ?: val invokeImpl = symbols.interopInvokeImpls[returnType.getClass()?.descriptor] ?:
context.reportCompilationError( 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 irFile, expression
) )
builder.irCall(invokeImpl).apply { builder.irCall(invokeImpl).apply {
putValueArgument(0, expression.extensionReceiver) putValueArgument(0, expression.extensionReceiver)
val varargParameter = invokeImpl.descriptor.valueParameters[1] val varargParameter = invokeImpl.owner.valueParameters[1]
val varargArgument = IrVarargImpl( val varargArgument = IrVarargImpl(
startOffset, endOffset, varargParameter.type, varargParameter.varargElementType!! startOffset, endOffset, varargParameter.type, varargParameter.varargElementType!!
).apply { ).apply {
@@ -897,7 +925,7 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
this.addElement(expression.getValueArgument(it)!!) 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) this.checkCTypeNullability(reportError)
if (isReturnType && KotlinBuiltIns.isUnit(this)) { if (isReturnType && this.isUnit()) {
return return
} }
if (KotlinBuiltIns.isPrimitiveType(this)) { if (this.isPrimitiveType()) {
return return
} }
if (TypeUtils.getClassDescriptor(this) == interop.cPointer) { if (this.getClass()?.descriptor == interop.cPointer) {
return 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) { private fun IrType.checkCTypeNullability(reportError: (String) -> Nothing) {
if (KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType(this) && this.isMarkedNullable) { if (this.isNullablePrimitiveType()) {
reportError("Type $this must not be nullable when used in C function signature") reportError("Type ${this.toKotlinType()} must not be nullable when used in C function signature")
} }
if (TypeUtils.getClassDescriptor(this) == interop.cPointer && !this.isMarkedNullable) { if (this.getClass() == interop.cPointer && !this.isSimpleTypeWithQuestionMark) {
reportError("Type $this must be nullable when used in C function signature") 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() val typeParameter = descriptor.original.typeParameters.single()
return getTypeArgument(typeParameter)!! return getTypeArgument(typeParameter)!!
} }
private fun IrBuilder.irFloat(value: Float) = 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) = 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) 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.common.lower.*
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor 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.IrStatement
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.*
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.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl 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.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.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.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
@@ -59,6 +59,21 @@ internal class LateinitLowering(
private val isInitializedGetterDescriptor = isInitializedPropertyDescriptor.getter!! private val isInitializedGetterDescriptor = isInitializedPropertyDescriptor.getter!!
override fun lower(irFile: IrFile) { 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) { irFile.transformChildrenVoid(object : IrBuildingTransformer(context) {
override fun visitVariable(declaration: IrVariable): IrStatement { override fun visitVariable(declaration: IrVariable): IrStatement {
@@ -85,10 +100,10 @@ internal class LateinitLowering(
return irBlock(expression) { return irBlock(expression) {
// TODO: do data flow analysis to check if value is proved to be not-null. // TODO: do data flow analysis to check if value is proved to be not-null.
+irIfThen( +irIfThen(
irEqualsNull(irGet(symbol)), irEqualsNull(irGet(expression.type, symbol)),
throwUninitializedPropertyAccessException(symbol) throwUninitializedPropertyAccessException(symbol)
) )
+irGet(symbol) +irGet(expression.type, symbol)
} }
} }
} }
@@ -101,19 +116,13 @@ internal class LateinitLowering(
val propertyReference = expression.extensionReceiver!! as IrPropertyReference val propertyReference = expression.extensionReceiver!! as IrPropertyReference
assert(propertyReference.extensionReceiver == null, { "'lateinit' modifier is not allowed on extension properties" }) 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 propertyDescriptor = propertyReference.descriptor.resolveFakeOverride().original
val type = propertyDescriptor.type val type = propertyDescriptor.type
assert(!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" }) assert(!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" })
builder.at(expression).run { builder.at(expression).run {
@Suppress("DEPRECATION") val field = lateinitPropertyToField[propertyDescriptor]!!
val fieldValue = IrGetFieldImpl( val fieldValue = irGetField(propertyReference.dispatchReceiver, field)
expression.startOffset,
expression.endOffset,
propertyDescriptor,
propertyReference.dispatchReceiver
)
return irNotEquals(fieldValue, irNull()) return irNotEquals(fieldValue, irNull())
} }
} }
@@ -125,7 +134,7 @@ internal class LateinitLowering(
return declaration return declaration
val backingField = declaration.backingField!! 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" }) assert(backingField.initializer == null, { "'lateinit' modifier is not allowed for properties with initializer" })
val irBuilder = context.createIrBuilder(backingField.symbol, declaration.startOffset, declaration.endOffset) val irBuilder = context.createIrBuilder(backingField.symbol, declaration.startOffset, declaration.endOffset)
@@ -136,20 +145,20 @@ internal class LateinitLowering(
return declaration return declaration
} }
private fun transformGetter(backingFieldSymbol: IrFieldSymbol, getter: IrFunction) { private fun transformGetter(backingField: IrField, getter: IrFunction) {
val type = backingFieldSymbol.descriptor.type val type = backingField.descriptor.type
assert(!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" }) assert(!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" })
val irBuilder = context.createIrBuilder(getter.symbol, getter.startOffset, getter.endOffset) val irBuilder = context.createIrBuilder(getter.symbol, getter.startOffset, getter.endOffset)
irBuilder.run { irBuilder.run {
getter.body = irBlockBody { getter.body = irBlockBody {
val resultVar = irTemporary( val resultVar = irTemporary(
irGetField(getter.dispatchReceiverParameter?.let { irGet(it.symbol) }, backingFieldSymbol) irGetField(getter.dispatchReceiverParameter?.let { irGet(it) }, backingField)
) )
+irIfThenElse( +irIfThenElse(
context.builtIns.nothingType, context.irBuiltIns.nothingType,
irNotEquals(irGet(resultVar.symbol), irNull()), irNotEquals(irGet(resultVar), irNull()),
irReturn(irGet(resultVar.symbol)), irReturn(irGet(resultVar)),
throwUninitializedPropertyAccessException(backingFieldSymbol) throwUninitializedPropertyAccessException(backingField.symbol)
) )
} }
} }
@@ -158,14 +167,14 @@ internal class LateinitLowering(
} }
private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(backingFieldSymbol: IrSymbol) = private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(backingFieldSymbol: IrSymbol) =
irCall(throwErrorFunction).apply { irCall(throwErrorFunction, context.irBuiltIns.nothingType).apply {
if (generateParameterNameInAssertion) { if (generateParameterNameInAssertion) {
putValueArgument( putValueArgument(
0, 0,
IrConstImpl.string( IrConstImpl.string(
startOffset, startOffset,
endOffset, endOffset,
context.builtIns.stringType, context.irBuiltIns.stringType,
backingFieldSymbol.descriptor.name.asString() 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.IrBuildingTransformer
import org.jetbrains.kotlin.backend.common.lower.at import org.jetbrains.kotlin.backend.common.lower.at
import org.jetbrains.kotlin.backend.konan.Context 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.backend.konan.reportCompilationError
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
/** /**
@@ -43,7 +46,7 @@ internal class PostInlineLowering(val context: Context) : FileLoweringPass {
expression.transformChildrenVoid() expression.transformChildrenVoid()
builder.at(expression) builder.at(expression)
val typeArgument = expression.descriptor.defaultType val typeArgument = expression.symbol.typeWithStarProjections
return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply { return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply {
putValueArgument(0, builder.irCall(symbols.getClassTypeInfo, listOf(typeArgument))) putValueArgument(0, builder.irCall(symbols.getClassTypeInfo, listOf(typeArgument)))
@@ -54,7 +57,7 @@ internal class PostInlineLowering(val context: Context) : FileLoweringPass {
expression.transformChildrenVoid() expression.transformChildrenVoid()
builder.at(expression) builder.at(expression)
val typeArgument = expression.type.arguments.single().type val typeArgument = expression.argument.type
return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply { return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply {
val typeInfo = builder.irCall(symbols.getObjectTypeInfo).apply { val typeInfo = builder.irCall(symbols.getObjectTypeInfo).apply {
putValueArgument(0, expression.argument) putValueArgument(0, expression.argument)
@@ -95,7 +98,7 @@ internal class PostInlineLowering(val context: Context) : FileLoweringPass {
} }
expression.putValueArgument(0, IrConstImpl<String>( expression.putValueArgument(0, IrConstImpl<String>(
expression.startOffset, expression.endOffset, expression.startOffset, expression.endOffset,
context.ir.symbols.immutableBinaryBlob.descriptor.defaultType, context.ir.symbols.immutableBinaryBlob.typeWithoutArguments,
IrConstKind.String, builder.toString())) 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.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl 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.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.typeUtil.isUnit
/** /**
* This pass runs before inlining and performs the following additional transformations over some operations: * 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 package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.* 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.getFunction
import org.jetbrains.kotlin.backend.common.descriptors.replace
import org.jetbrains.kotlin.backend.common.ir.createOverriddenDescriptor import org.jetbrains.kotlin.backend.common.ir.createOverriddenDescriptor
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.Context 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.IrSuspendableExpressionImpl
import org.jetbrains.kotlin.backend.konan.ir.IrSuspensionPoint import org.jetbrains.kotlin.backend.konan.ir.IrSuspensionPoint
import org.jetbrains.kotlin.backend.konan.ir.IrSuspensionPointImpl 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.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl 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.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl import org.jetbrains.kotlin.ir.declarations.impl.*
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.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* 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.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl 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.util.*
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager 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 { 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 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 val returnIfSuspendedDescriptor = context.getInternalFunctions("returnIfSuspended").single()
private fun removeReturnIfSuspendedCallAndSimplifyDelegatingCall(irFunction: IrFunction, delegatingCall: IrCall) { private fun removeReturnIfSuspendedCallAndSimplifyDelegatingCall(irFunction: IrFunction, delegatingCall: IrCall) {
@@ -245,7 +240,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
putValueArgument(index, irGet(argument)) putValueArgument(index, irGet(argument))
} }
putValueArgument(functionParameters.size, putValueArgument(functionParameters.size,
irCall(getContinuationSymbol, listOf(descriptor.returnType!!))) irCall(getContinuation, listOf(irFunction.returnType)))
} }
putValueArgument(0, irGetObject(symbols.unit)) // value putValueArgument(0, irGetObject(symbols.unit)) // value
putValueArgument(1, irNull()) // exception 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 coroutinesScope = context.irModule!!.descriptor.getPackage(COROUTINES_FQ_NAME).memberScope
private val kotlinPackageScope = context.irModule!!.descriptor.getPackage(KOTLIN_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 inner class CoroutineBuilder(val irFunction: IrFunction, val functionReference: IrFunctionReference?) {
private val functionParameters = irFunction.descriptor.explicitParameters private val functionParameters = irFunction.explicitParameters
private val boundFunctionParameters = functionReference?.getArguments()?.map { it.first } private val boundFunctionParameters = functionReference?.getArgumentsWithIr()?.map { it.first }
private val unboundFunctionParameters = boundFunctionParameters?.let { functionParameters - it } private val unboundFunctionParameters = boundFunctionParameters?.let { functionParameters - it }
private var tempIndex = 0 private var tempIndex = 0
private var suspensionPointIdIndex = 0 private var suspensionPointIdIndex = 0
private lateinit var suspendResult: IrVariableSymbol private lateinit var suspendResult: IrVariable
private lateinit var dataArgument: IrValueParameterSymbol private lateinit var dataArgument: IrValueParameter
private lateinit var exceptionArgument: IrValueParameterSymbol private lateinit var exceptionArgument: IrValueParameter
private lateinit var coroutineClassDescriptor: ClassDescriptorImpl private lateinit var coroutineClassDescriptor: ClassDescriptorImpl
private lateinit var coroutineClass: IrClassImpl private lateinit var coroutineClass: IrClassImpl
private lateinit var coroutineClassThis: IrValueParameterSymbol private lateinit var coroutineClassThis: IrValueParameter
private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrFieldSymbol> private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrField>
private val coroutineImplSymbol = symbols.coroutineImpl private val coroutineImplSymbol = symbols.coroutineImpl
private val coroutineImplConstructorSymbol = coroutineImplSymbol.constructors.single() private val coroutineImplConstructorSymbol = coroutineImplSymbol.constructors.single()
private val coroutineImplClassDescriptor = coroutineImplSymbol.descriptor private val coroutineImplClassDescriptor = coroutineImplSymbol.descriptor
private val create1FunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope private val create1Function = coroutineImplSymbol.owner.simpleFunctions()
.getContributedFunctions(Name.identifier("create"), NoLookupLocation.FROM_BACKEND) .single { it.name.asString() == "create" && it.valueParameters.size == 1 }
.single { it.valueParameters.size == 1 } private val create1CompletionParameter = create1Function.valueParameters[0]
private val create1CompletionParameter = create1FunctionDescriptor.valueParameters[0]
private val coroutineImplLabelGetterSymbol = coroutineImplSymbol.getPropertyGetter("label")!! private val coroutineImplLabelGetterSymbol = coroutineImplSymbol.getPropertyGetter("label")!!
private val coroutineImplLabelSetterSymbol = coroutineImplSymbol.getPropertySetter("label")!! private val coroutineImplLabelSetterSymbol = coroutineImplSymbol.getPropertySetter("label")!!
fun build(): BuiltCoroutine { fun build(): BuiltCoroutine {
val superTypes = mutableListOf<KotlinType>(coroutineImplClassDescriptor.defaultType) val superTypes = mutableListOf<IrType>(coroutineImplSymbol.owner.defaultType)
val superClasses = mutableListOf<IrClass>(coroutineImplSymbol.owner) var suspendFunctionClass: IrClass? = null
var suspendFunctionClassDescriptor: ClassDescriptor? = null var functionClass: IrClass? = null
var functionClassDescriptor: ClassDescriptor? = null var suspendFunctionClassTypeArguments: List<IrType>? = null
var suspendFunctionClassTypeArguments: List<KotlinType>? = null var functionClassTypeArguments: List<IrType>? = null
var functionClassTypeArguments: List<KotlinType>? = null
if (unboundFunctionParameters != null) { if (unboundFunctionParameters != null) {
// Suspend lambda inherits SuspendFunction. // Suspend lambda inherits SuspendFunction.
val numberOfParameters = unboundFunctionParameters.size val numberOfParameters = unboundFunctionParameters.size
suspendFunctionClassDescriptor = kotlinPackageScope.getContributedClassifier( suspendFunctionClass = context.ir.symbols.suspendFunctions[numberOfParameters].owner
Name.identifier("SuspendFunction$numberOfParameters"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
val unboundParameterTypes = unboundFunctionParameters.map { it.type } val unboundParameterTypes = unboundFunctionParameters.map { it.type }
suspendFunctionClassTypeArguments = unboundParameterTypes + irFunction.descriptor.returnType!! suspendFunctionClassTypeArguments = unboundParameterTypes + irFunction.returnType
superTypes += suspendFunctionClassDescriptor.defaultType.replace(suspendFunctionClassTypeArguments) superTypes += suspendFunctionClass.typeWith(suspendFunctionClassTypeArguments)
superClasses += context.ir.symbols.suspendFunctions[numberOfParameters].owner
functionClassDescriptor = kotlinPackageScope.getContributedClassifier( functionClass = context.ir.symbols.functions[numberOfParameters + 1].owner
Name.identifier("Function${numberOfParameters + 1}"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor val continuationType = continuationClassSymbol.typeWith(irFunction.returnType)
val continuationType = continuationClassDescriptor.defaultType.replace(listOf(irFunction.descriptor.returnType!!)) functionClassTypeArguments = unboundParameterTypes + continuationType + context.irBuiltIns.anyNType
functionClassTypeArguments = unboundParameterTypes + continuationType + context.builtIns.nullableAnyType superTypes += functionClass.typeWith(functionClassTypeArguments)
superTypes += functionClassDescriptor.defaultType.replace(functionClassTypeArguments)
superClasses += context.ir.symbols.functions[numberOfParameters + 1].owner
} }
coroutineClassDescriptor = ClassDescriptorImpl( coroutineClassDescriptor = ClassDescriptorImpl(
@@ -328,11 +314,13 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
/* name = */ "${irFunction.descriptor.name}\$${coroutineId++}".synthesizedName, /* name = */ "${irFunction.descriptor.name}\$${coroutineId++}".synthesizedName,
/* modality = */ Modality.FINAL, /* modality = */ Modality.FINAL,
/* kind = */ ClassKind.CLASS, /* kind = */ ClassKind.CLASS,
/* superTypes = */ superTypes, /* superTypes = */ superTypes.map { it.toKotlinType() },
/* source = */ SourceElement.NO_SOURCE, /* source = */ SourceElement.NO_SOURCE,
/* isExternal = */ false, /* isExternal = */ false,
/* storageManager = */ LockBasedStorageManager.NO_LOCKS /* storageManager = */ LockBasedStorageManager.NO_LOCKS
) ).also {
it.initialize(stub("coroutine class"), stub("coroutine class constructors"), null)
}
coroutineClass = IrClassImpl( coroutineClass = IrClassImpl(
startOffset = irFunction.startOffset, startOffset = irFunction.startOffset,
endOffset = irFunction.endOffset, endOffset = irFunction.endOffset,
@@ -340,17 +328,19 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
descriptor = coroutineClassDescriptor descriptor = coroutineClassDescriptor
) )
coroutineClass.parent = irFunction.parent coroutineClass.parent = irFunction.parent
coroutineClass.createParameterDeclarations()
coroutineClassThis = coroutineClass.thisReceiver!!
val overriddenMap = mutableMapOf<CallableMemberDescriptor, CallableMemberDescriptor>() val overriddenMap = mutableMapOf<CallableMemberDescriptor, CallableMemberDescriptor>()
val constructors = mutableSetOf<ClassConstructorDescriptor>()
val coroutineConstructorBuilder = createConstructorBuilder() val coroutineConstructorBuilder = createConstructorBuilder()
constructors.add(coroutineConstructorBuilder.symbol.descriptor) coroutineConstructorBuilder.initialize()
val doResumeFunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope val doResumeFunction = coroutineImplSymbol.owner.simpleFunctions()
.getContributedFunctions(Name.identifier("doResume"), NoLookupLocation.FROM_BACKEND).single() .single { it.name.asString() == "doResume" }
val doResumeMethodBuilder = createDoResumeMethodBuilder(doResumeFunctionDescriptor) val doResumeMethodBuilder = createDoResumeMethodBuilder(doResumeFunction, coroutineClass)
overriddenMap += doResumeFunctionDescriptor to doResumeMethodBuilder.symbol.descriptor doResumeMethodBuilder.initialize()
overriddenMap += doResumeFunction.descriptor to doResumeMethodBuilder.symbol.descriptor
var coroutineFactoryConstructorBuilder: SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>? = null var coroutineFactoryConstructorBuilder: SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>? = null
var createMethodBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>? = null var createMethodBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>? = null
@@ -358,7 +348,6 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
if (functionReference != null) { if (functionReference != null) {
// Suspend lambda - create factory methods. // Suspend lambda - create factory methods.
coroutineFactoryConstructorBuilder = createFactoryConstructorBuilder(boundFunctionParameters!!) coroutineFactoryConstructorBuilder = createFactoryConstructorBuilder(boundFunctionParameters!!)
constructors.add(coroutineFactoryConstructorBuilder.symbol.descriptor)
val createFunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope val createFunctionDescriptor = coroutineImplClassDescriptor.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("create"), NoLookupLocation.FROM_BACKEND) .getContributedFunctions(Name.identifier("create"), NoLookupLocation.FROM_BACKEND)
@@ -366,27 +355,24 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
createMethodBuilder = createCreateMethodBuilder( createMethodBuilder = createCreateMethodBuilder(
unboundArgs = unboundFunctionParameters!!, unboundArgs = unboundFunctionParameters!!,
superFunctionDescriptor = createFunctionDescriptor, superFunctionDescriptor = createFunctionDescriptor,
coroutineConstructorSymbol = coroutineConstructorBuilder.symbol) coroutineConstructor = coroutineConstructorBuilder.ir,
coroutineClass = coroutineClass)
createMethodBuilder.initialize()
if (createFunctionDescriptor != null) if (createFunctionDescriptor != null)
overriddenMap += createFunctionDescriptor to createMethodBuilder.symbol.descriptor overriddenMap += createFunctionDescriptor to createMethodBuilder.symbol.descriptor
val invokeFunctionDescriptor = functionClassDescriptor!!.getFunction("invoke", functionClassTypeArguments!!) val invokeFunctionDescriptor = functionClass!!.descriptor
val suspendInvokeFunctionDescriptor = suspendFunctionClassDescriptor!!.getFunction("invoke", suspendFunctionClassTypeArguments!!) .getFunction("invoke", functionClassTypeArguments!!.map { it.toKotlinType() })
val suspendInvokeFunctionDescriptor = suspendFunctionClass!!.descriptor
.getFunction("invoke", suspendFunctionClassTypeArguments!!.map { it.toKotlinType() })
invokeMethodBuilder = createInvokeMethodBuilder( invokeMethodBuilder = createInvokeMethodBuilder(
suspendFunctionInvokeFunctionDescriptor = suspendInvokeFunctionDescriptor, suspendFunctionInvokeFunctionDescriptor = suspendInvokeFunctionDescriptor,
functionInvokeFunctionDescriptor = invokeFunctionDescriptor, functionInvokeFunctionDescriptor = invokeFunctionDescriptor,
createFunctionSymbol = createMethodBuilder.symbol, createFunction = createMethodBuilder.ir,
doResumeFunctionSymbol = doResumeMethodBuilder.symbol) 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) coroutineClass.addChild(coroutineConstructorBuilder.ir)
coroutineFactoryConstructorBuilder?.let { coroutineFactoryConstructorBuilder?.let {
@@ -395,7 +381,6 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
} }
createMethodBuilder?.let { createMethodBuilder?.let {
it.initialize()
coroutineClass.addChild(it.ir) coroutineClass.addChild(it.ir)
} }
@@ -404,10 +389,9 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
coroutineClass.addChild(it.ir) coroutineClass.addChild(it.ir)
} }
doResumeMethodBuilder.initialize()
coroutineClass.addChild(doResumeMethodBuilder.ir) coroutineClass.addChild(doResumeMethodBuilder.ir)
coroutineClass.setSuperSymbolsAndAddFakeOverrides(superClasses) coroutineClass.setSuperSymbolsAndAddFakeOverrides(superTypes)
return BuiltCoroutine( return BuiltCoroutine(
coroutineClass = coroutineClass, coroutineClass = coroutineClass,
@@ -428,21 +412,30 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
) )
) )
private lateinit var constructorParameters: List<IrValueParameter>
override fun doInitialize() { override fun doInitialize() {
val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
val constructorParameters = ( constructorParameters = (
functionParameters functionParameters
+ coroutineImplConstructorSymbol.descriptor.valueParameters[0] // completion. + coroutineImplConstructorSymbol.owner.valueParameters[0] // completion.
).mapIndexed { index, parameter -> parameter.copyAsValueParameter(descriptor, index) } ).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 descriptor.returnType = coroutineClassDescriptor.defaultType
} }
override fun buildIr(): IrConstructor { override fun buildIr(): IrConstructor {
// Save all arguments to fields. // Save all arguments to fields.
argumentToPropertiesMap = functionParameters.associate { argumentToPropertiesMap = functionParameters.associate {
it to buildPropertyWithBackingField(it.name, it.type, false) it.descriptor to addField(it.name, it.type, false)
} }
val startOffset = irFunction.startOffset val startOffset = irFunction.startOffset
@@ -453,25 +446,32 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
origin = DECLARATION_ORIGIN_COROUTINE_IMPL, origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
symbol = symbol).apply { symbol = symbol).apply {
createParameterDeclarations() returnType = coroutineClass.defaultType
this.valueParameters += constructorParameters
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody { body = irBuilder.irBlockBody {
val completionParameter = valueParameters.last() val completionParameter = valueParameters.last()
+IrDelegatingConstructorCallImpl(startOffset, endOffset, +IrDelegatingConstructorCallImpl(startOffset, endOffset,
context.irBuiltIns.unitType,
coroutineImplConstructorSymbol, coroutineImplConstructorSymbol.descriptor).apply { 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 -> 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>() { = object : SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() {
override fun buildSymbol() = IrConstructorSymbolImpl( override fun buildSymbol() = IrConstructorSymbolImpl(
@@ -483,12 +483,18 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
) )
) )
lateinit var constructorParameters: List<IrValueParameter>
override fun doInitialize() { override fun doInitialize() {
val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
val constructorParameters = boundParams.mapIndexed { index, parameter -> constructorParameters = boundParams.mapIndexed { index, parameter ->
parameter.copyAsValueParameter(descriptor, index) 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 descriptor.returnType = coroutineClassDescriptor.defaultType
} }
@@ -501,27 +507,32 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
origin = DECLARATION_ORIGIN_COROUTINE_IMPL, origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
symbol = symbol).apply { symbol = symbol).apply {
createParameterDeclarations() returnType = coroutineClass.defaultType
this.valueParameters += constructorParameters
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody { body = irBuilder.irBlockBody {
+IrDelegatingConstructorCallImpl(startOffset, endOffset, +IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.unitType,
coroutineImplConstructorSymbol, coroutineImplConstructorSymbol.descriptor).apply { coroutineImplConstructorSymbol, coroutineImplConstructorSymbol.descriptor).apply {
putValueArgument(0, irNull()) // Completion. putValueArgument(0, irNull()) // Completion.
} }
+IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol) +IrInstanceInitializerCallImpl(startOffset, endOffset, coroutineClass.symbol,
context.irBuiltIns.unitType)
// Save all arguments to fields. // Save all arguments to fields.
boundParams.forEachIndexed { index, parameter -> 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?, superFunctionDescriptor: FunctionDescriptor?,
coroutineConstructorSymbol: IrConstructorSymbol) coroutineConstructor: IrConstructor,
coroutineClass: IrClass)
= object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() { = object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildSymbol() = IrSimpleFunctionSymbolImpl( override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
@@ -534,19 +545,21 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
) )
) )
lateinit var parameters: List<IrValueParameter>
override fun doInitialize() { override fun doInitialize() {
val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl
val valueParameters = ( parameters = (
unboundArgs + create1CompletionParameter unboundArgs + create1CompletionParameter
).mapIndexed { index, parameter -> ).mapIndexed { index, parameter ->
parameter.copyAsValueParameter(descriptor, index) parameter.copy(parameter.descriptor.copyAsValueParameter(descriptor, index))
} }
descriptor.initialize( descriptor.initialize(
/* receiverParameterType = */ null, /* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ coroutineClassDescriptor.thisAsReceiverParameter, /* dispatchReceiverParameter = */ coroutineClassDescriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(), /* typeParameters = */ emptyList(),
/* unsubstitutedValueParameters = */ valueParameters, /* unsubstitutedValueParameters = */ parameters.map { it.descriptor as ValueParameterDescriptor },
/* unsubstitutedReturnType = */ coroutineClassDescriptor.defaultType, /* unsubstitutedReturnType = */ coroutineClassDescriptor.defaultType,
/* modality = */ Modality.FINAL, /* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE).apply { /* visibility = */ Visibilities.PRIVATE).apply {
@@ -566,25 +579,29 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
origin = DECLARATION_ORIGIN_COROUTINE_IMPL, origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
symbol = symbol).apply { 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) val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody(startOffset, endOffset) { body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn( +irReturn(
irCall(coroutineConstructorSymbol).apply { irCall(coroutineConstructor).apply {
var unboundIndex = 0 var unboundIndex = 0
val unboundArgsSet = unboundArgs.toSet() val unboundArgsSet = unboundArgs.toSet()
functionParameters.map { functionParameters.map {
if (unboundArgsSet.contains(it)) if (unboundArgsSet.contains(it))
irGet(valueParameters[unboundIndex++].symbol) irGet(valueParameters[unboundIndex++])
else else
irGetField(irGet(thisReceiver), argumentToPropertiesMap[it]!!) irGetField(irGet(thisReceiver), argumentToPropertiesMap[it.descriptor]!!)
}.forEachIndexed { index, argument -> }.forEachIndexed { index, argument ->
putValueArgument(index, argument) putValueArgument(index, argument)
} }
putValueArgument(functionParameters.size, irGet(valueParameters[unboundIndex].symbol)) putValueArgument(functionParameters.size, irGet(valueParameters[unboundIndex]))
assert(unboundIndex == valueParameters.size - 1, assert(unboundIndex == valueParameters.size - 1,
{ "Not all arguments of <create> are used" }) { "Not all arguments of <create> are used" })
}) })
@@ -595,8 +612,9 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
private fun createInvokeMethodBuilder(suspendFunctionInvokeFunctionDescriptor: FunctionDescriptor, private fun createInvokeMethodBuilder(suspendFunctionInvokeFunctionDescriptor: FunctionDescriptor,
functionInvokeFunctionDescriptor: FunctionDescriptor, functionInvokeFunctionDescriptor: FunctionDescriptor,
createFunctionSymbol: IrFunctionSymbol, createFunction: IrFunction,
doResumeFunctionSymbol: IrFunctionSymbol) doResumeFunction: IrFunction,
coroutineClass: IrClass)
= object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() { = object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildSymbol() = IrSimpleFunctionSymbolImpl( override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
@@ -609,18 +627,20 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
) )
) )
lateinit var parameters: List<IrValueParameter>
override fun doInitialize() { override fun doInitialize() {
val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl 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. // Skip completion - invoke() already has it implicitly as a suspend function.
.take(createFunctionSymbol.descriptor.valueParameters.size - 1) .take(createFunction.valueParameters.size - 1)
.map { it.copyAsValueParameter(descriptor, it.index) } .map { it.copy(it.descriptor.copyAsValueParameter(descriptor, it.index)) }
descriptor.initialize( descriptor.initialize(
/* receiverParameterType = */ null, /* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ coroutineClassDescriptor.thisAsReceiverParameter, /* dispatchReceiverParameter = */ coroutineClassDescriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(), /* typeParameters = */ emptyList(),
/* unsubstitutedValueParameters = */ valueParameters, /* unsubstitutedValueParameters = */ parameters.map { it.descriptor as ValueParameterDescriptor },
/* unsubstitutedReturnType = */ irFunction.descriptor.returnType, /* unsubstitutedReturnType = */ irFunction.descriptor.returnType,
/* modality = */ Modality.FINAL, /* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE).apply { /* visibility = */ Visibilities.PRIVATE).apply {
@@ -639,21 +659,25 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
origin = DECLARATION_ORIGIN_COROUTINE_IMPL, origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
symbol = symbol).apply { 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) val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
body = irBuilder.irBlockBody(startOffset, endOffset) { body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn( +irReturn(
irCall(doResumeFunctionSymbol).apply { irCall(doResumeFunction).apply {
dispatchReceiver = irCall(createFunctionSymbol).apply { dispatchReceiver = irCall(createFunction).apply {
dispatchReceiver = irGet(thisReceiver) dispatchReceiver = irGet(thisReceiver)
valueParameters.forEachIndexed { index, parameter -> valueParameters.forEachIndexed { index, parameter ->
putValueArgument(index, irGet(parameter.symbol)) putValueArgument(index, irGet(parameter))
} }
putValueArgument(valueParameters.size, putValueArgument(valueParameters.size,
irCall(getContinuationSymbol, listOf(symbol.descriptor.returnType!!))) irCall(getContinuation, listOf(returnType)))
} }
putValueArgument(0, irGetObject(symbols.unit)) // value putValueArgument(0, irGetObject(symbols.unit)) // value
putValueArgument(1, irNull()) // exception 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 { private fun addField(name: Name, type: IrType, isMutable: Boolean): IrField = createField(
val propertyBuilder = context.createPropertyWithBackingFieldBuilder( irFunction.startOffset,
startOffset = irFunction.startOffset, irFunction.endOffset,
endOffset = irFunction.endOffset, type,
origin = DECLARATION_ORIGIN_COROUTINE_IMPL, name,
owner = coroutineClassDescriptor, isMutable,
name = name, DECLARATION_ORIGIN_COROUTINE_IMPL,
type = type, coroutineClassDescriptor
isMutable = isMutable).apply { ).also {
initialize() coroutineClass.addChild(it)
}
coroutineClass.addChild(propertyBuilder.ir)
return propertyBuilder.symbol
} }
private fun createDoResumeMethodBuilder(doResumeFunctionDescriptor: FunctionDescriptor) private fun createDoResumeMethodBuilder(doResumeFunction: IrFunction, coroutineClass: IrClass)
= object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() { = object: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
override fun buildSymbol() = IrSimpleFunctionSymbolImpl( override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
doResumeFunctionDescriptor.createOverriddenDescriptor(coroutineClassDescriptor) doResumeFunction.descriptor.createOverriddenDescriptor(coroutineClassDescriptor)
) )
override fun doInitialize() { } override fun doInitialize() { }
@@ -699,58 +719,76 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
origin = DECLARATION_ORIGIN_COROUTINE_IMPL, origin = DECLARATION_ORIGIN_COROUTINE_IMPL,
symbol = symbol).apply { 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 dataArgument = function.valueParameters[0]
exceptionArgument = function.valueParameters[1].symbol exceptionArgument = function.valueParameters[1]
suspendResult = IrVariableSymbolImpl(
IrTemporaryVariableDescriptorImpl( val label = coroutineImplSymbol.owner.declarations.filterIsInstance<IrProperty>()
containingDeclaration = irFunction.descriptor, .single { it.name.asString() == "label" }
name = "suspendResult".synthesizedName,
outType = context.builtIns.nullableAnyType,
isMutable = true)
)
val label = coroutineImplClassDescriptor.unsubstitutedMemberScope
.getContributedVariables(Name.identifier("label"), NoLookupLocation.FROM_BACKEND).single()
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
function.body = irBuilder.irBlockBody(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. // 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 liveLocals = computeLivenessAtSuspensionPoints(originalBody)
val immutableLiveLocals = liveLocals.values.flatten().filterNot { it.descriptor.isVar }.toSet() val immutableLiveLocals = liveLocals.values.flatten().filterNot { it.descriptor.isVar }.toSet()
val localsMap = immutableLiveLocals.associate { val localsMap = immutableLiveLocals.associate {
// TODO: Remove .descriptor as soon as all symbols are bound. // TODO: Remove .descriptor as soon as all symbols are bound.
it.descriptor to IrVariableSymbolImpl( val symbol = IrVariableSymbolImpl(
IrTemporaryVariableDescriptorImpl( IrTemporaryVariableDescriptorImpl(
containingDeclaration = irFunction.descriptor, containingDeclaration = irFunction.descriptor,
name = it.descriptor.name, name = it.descriptor.name,
outType = it.descriptor.type, outType = it.descriptor.type,
isMutable = true) 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()) if (localsMap.isNotEmpty())
transformVariables(originalBody, localsMap) // Make variables mutable in order to save/restore them. 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. // TODO: optimize by using the same property for different locals.
liveLocals.values.forEach { scope -> liveLocals.values.forEach { scope ->
scope.forEach { scope.forEach {
localToPropertyMap.getOrPut(it) { localToPropertyMap.getOrPut(it.symbol) {
buildPropertyWithBackingField(it.descriptor.name, it.descriptor.type, true) addField(it.descriptor.name, it.type, true)
} }
} }
} }
originalBody.transformChildrenVoid(object : IrElementTransformerVoid() { originalBody.transformChildrenVoid(object : IrElementTransformerVoid() {
private val thisReceiver = function.dispatchReceiverParameter!!.symbol private val thisReceiver = function.dispatchReceiverParameter!!
// Replace returns to refer to the new function. // Replace returns to refer to the new function.
override fun visitReturn(expression: IrReturn): IrExpression { override fun visitReturn(expression: IrReturn): IrExpression {
@@ -783,23 +821,24 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
when (expression.symbol) { when (expression.symbol) {
saveStateSymbol -> { saveState.symbol -> {
val scope = liveLocals[suspensionPoint]!! val scope = liveLocals[suspensionPoint]!!
return irBlock(expression) { return irBlock(expression) {
scope.forEach { 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 { +irCall(coroutineImplLabelSetterSymbol).apply {
dispatchReceiver = irGet(thisReceiver) dispatchReceiver = irGet(thisReceiver)
putValueArgument(0, irGet(suspensionPoint.suspensionPointIdParameter.symbol)) putValueArgument(0, irGet(suspensionPoint.suspensionPointIdParameter))
} }
} }
} }
restoreStateSymbol -> { restoreState.symbol -> {
val scope = liveLocals[suspensionPoint]!! val scope = liveLocals[suspensionPoint]!!
return irBlock(expression) { return irBlock(expression) {
scope.forEach { 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 val statements = (originalBody as IrBlockBody).statements
+irVar(suspendResult, null) +suspendResult
+IrSuspendableExpressionImpl( +IrSuspendableExpressionImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
type = context.builtIns.unitType, type = context.irBuiltIns.unitType,
suspensionPointId = irCall(coroutineImplLabelGetterSymbol).apply { suspensionPointId = irCall(coroutineImplLabelGetterSymbol).apply {
dispatchReceiver = irGet(function.dispatchReceiverParameter!!.symbol) dispatchReceiver = irGet(function.dispatchReceiverParameter!!)
}, },
result = irBlock(startOffset, endOffset) { result = irBlock(startOffset, endOffset) {
+irThrowIfNotNull(exceptionArgument) // Coroutine might start with an exception. +irThrowIfNotNull(exceptionArgument) // Coroutine might start with an exception.
statements.forEach { +it } statements.forEach { +it }
}) })
if (irFunction.descriptor.returnType!!.isUnit()) if (irFunction.returnType.isUnit())
+irReturn(irGetObject(symbols.unit)) // Insert explicit return for Unit functions. +irReturn(irGetObject(symbols.unit)) // Insert explicit return for Unit functions.
} }
return function return function
} }
} }
private fun transformVariables(element: IrElement, variablesMap: Map<VariableDescriptor, IrVariableSymbol>) { private fun transformVariables(element: IrElement, variablesMap: Map<VariableDescriptor, IrVariable>) {
element.transformChildrenVoid(object: IrElementTransformerVoid() { element.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
@@ -843,7 +882,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
return IrGetValueImpl( return IrGetValueImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
symbol = newVariable, type = newVariable.type,
symbol = newVariable.symbol,
origin = expression.origin) origin = expression.origin)
} }
@@ -856,7 +896,8 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
return IrSetVariableImpl( return IrSetVariableImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
symbol = newVariable, type = context.irBuiltIns.unitType,
symbol = newVariable.symbol,
value = expression.value, value = expression.value,
origin = expression.origin) origin = expression.origin)
} }
@@ -867,21 +908,17 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val newVariable = variablesMap[declaration.symbol.descriptor] val newVariable = variablesMap[declaration.symbol.descriptor]
?: return declaration ?: return declaration
return IrVariableImpl( newVariable.initializer = declaration.initializer
startOffset = declaration.startOffset,
endOffset = declaration.endOffset, return newVariable
origin = declaration.origin,
symbol = newVariable).apply {
initializer = declaration.initializer
}
} }
}) })
} }
private fun computeLivenessAtSuspensionPoints(body: IrBody): Map<IrSuspensionPoint, List<IrVariableSymbol>> { private fun computeLivenessAtSuspensionPoints(body: IrBody): Map<IrSuspensionPoint, List<IrVariable>> {
// TODO: data flow analysis. // TODO: data flow analysis.
// Just save all visible for now. // Just save all visible for now.
val result = mutableMapOf<IrSuspensionPoint, List<IrVariableSymbol>>() val result = mutableMapOf<IrSuspensionPoint, List<IrVariable>>()
body.acceptChildrenVoid(object: VariablesScopeTracker() { body.acceptChildrenVoid(object: VariablesScopeTracker() {
override fun visitExpression(expression: IrExpression) { override fun visitExpression(expression: IrExpression) {
@@ -894,7 +931,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
suspensionPoint.result.acceptChildrenVoid(this) suspensionPoint.result.acceptChildrenVoid(this)
suspensionPoint.resumeResult.acceptChildrenVoid(this) suspensionPoint.resumeResult.acceptChildrenVoid(this)
val visibleVariables = mutableListOf<IrVariableSymbol>() val visibleVariables = mutableListOf<IrVariable>()
scopeStack.forEach { visibleVariables += it } scopeStack.forEach { visibleVariables += it }
result.put(suspensionPoint, visibleVariables) 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. // 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( SimpleFunctionDescriptorImpl.create(
irFunction.descriptor, irFunction.descriptor,
Annotations.EMPTY, Annotations.EMPTY,
@@ -912,10 +949,11 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
CallableMemberDescriptor.Kind.SYNTHESIZED, CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE).apply { SourceElement.NO_SOURCE).apply {
initialize(null, null, emptyList(), emptyList(), context.builtIns.unitType, Modality.ABSTRACT, Visibilities.PRIVATE) 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( SimpleFunctionDescriptorImpl.create(
irFunction.descriptor, irFunction.descriptor,
Annotations.EMPTY, Annotations.EMPTY,
@@ -923,10 +961,11 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
CallableMemberDescriptor.Kind.SYNTHESIZED, CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE).apply { SourceElement.NO_SOURCE).apply {
initialize(null, null, emptyList(), emptyList(), context.builtIns.unitType, Modality.ABSTRACT, Visibilities.PRIVATE) 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. // TODO: optimize - it has square complexity.
override fun visitSetField(expression: IrSetField): IrExpression { override fun visitSetField(expression: IrSetField): IrExpression {
@@ -983,13 +1022,9 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
newChildren[index] = transformedChild newChildren[index] = transformedChild
else { else {
// Save to temporary in order to save execution order. // Save to temporary in order to save execution order.
val tmp = IrVariableSymbolImpl( val tmp = irVar(transformedChild)
IrTemporaryVariableDescriptorImpl(
containingDeclaration = irFunction.descriptor, tempStatements += tmp
name = "tmp${tempIndex++}".synthesizedName,
outType = transformedChild.type)
)
tempStatements += irVar(tmp, transformedChild)
newChildren[index] = irGet(tmp) newChildren[index] = irGet(tmp)
} }
} }
@@ -1001,7 +1036,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
calledSaveState = true calledSaveState = true
val firstArgument = newChildren[2]!! val firstArgument = newChildren[2]!!
newChildren[2] = irBlock(firstArgument) { newChildren[2] = irBlock(firstArgument) {
+irCall(saveStateSymbol) +irCall(saveState)
+firstArgument +firstArgument
} }
suspendCall = newChildren[2] suspendCall = newChildren[2]
@@ -1014,17 +1049,12 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
newChildren[numberOfChildren - 1] = newChildren[numberOfChildren - 1] =
irBlock(lastChild) { irBlock(lastChild) {
if (lastChild.isPure()) { if (lastChild.isPure()) {
+irCall(saveStateSymbol) +irCall(saveState)
+lastChild +lastChild
} else { } else {
val tmp = IrVariableSymbolImpl( val tmp = irVar(lastChild)
IrTemporaryVariableDescriptorImpl( +tmp
containingDeclaration = irFunction.descriptor, +irCall(saveState)
name = "tmp${tempIndex++}".synthesizedName,
outType = lastChild.type)
)
+irVar(tmp, lastChild)
+irCall(saveStateSymbol)
+irGet(tmp) +irGet(tmp)
} }
} }
@@ -1053,27 +1083,27 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
val suspensionPointIdParameter = IrTemporaryVariableDescriptorImpl( val suspensionPointIdParameter = IrTemporaryVariableDescriptorImpl(
containingDeclaration = irFunction.descriptor, containingDeclaration = irFunction.descriptor,
name = "suspensionPointId${suspensionPointIdIndex++}".synthesizedName, name = "suspensionPointId${suspensionPointIdIndex++}".synthesizedName,
outType = suspensionPointIdType) outType = suspensionPointIdType.toKotlinType())
val suspensionPoint = IrSuspensionPointImpl( val suspensionPoint = IrSuspensionPointImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
type = context.builtIns.nullableAnyType, type = context.irBuiltIns.anyNType,
suspensionPointIdParameter = irVar(suspensionPointIdParameter, null), suspensionPointIdParameter = irVar(suspensionPointIdParameter, suspensionPointIdType),
result = irBlock(startOffset, endOffset) { result = irBlock(startOffset, endOffset) {
if (!calledSaveState) if (!calledSaveState)
+irCall(saveStateSymbol) +irCall(saveState)
+irSetVar(suspendResult, suspendCall) +irSetVar(suspendResult.symbol, suspendCall)
+irReturnIfSuspended(suspendResult) +irReturnIfSuspended(suspendResult)
+irGet(suspendResult) +irGet(suspendResult)
}, },
resumeResult = irBlock(startOffset, endOffset) { resumeResult = irBlock(startOffset, endOffset) {
+irCall(restoreStateSymbol) +irCall(restoreState)
+irThrowIfNotNull(exceptionArgument) +irThrowIfNotNull(exceptionArgument)
+irGet(dataArgument) +irGet(dataArgument)
}) })
val expressionResult = when { val expressionResult = when {
suspendCall.type.isUnit() -> irImplicitCoercionToUnit(suspensionPoint) suspendCall.type.isUnit() -> irImplicitCoercionToUnit(suspensionPoint)
else -> irCast(suspensionPoint, suspendCall.type, suspendCall.type) else -> irAs(suspensionPoint, suspendCall.type)
} }
return irBlock(expression) { return irBlock(expression) {
tempStatements.forEach { +it } tempStatements.forEach { +it }
@@ -1132,27 +1162,31 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
get() = this is IrCall && this.descriptor.original == returnIfSuspendedDescriptor 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?) = private fun IrBuilderWithScope.irVar(descriptor: VariableDescriptor, type: IrType) =
IrVariableImpl(startOffset, endOffset, DECLARATION_ORIGIN_COROUTINE_IMPL, descriptor, initializer) IrVariableImpl(startOffset, endOffset, DECLARATION_ORIGIN_COROUTINE_IMPL, descriptor, type)
private fun IrBuilderWithScope.irVar(symbol: IrVariableSymbol, initializer: IrExpression?) = private fun IrBuilderWithScope.irReturnIfSuspended(value: IrValueDeclaration) =
IrVariableImpl(startOffset, endOffset, DECLARATION_ORIGIN_COROUTINE_IMPL, symbol).apply {
this.initializer = initializer
}
private fun IrBuilderWithScope.irReturnIfSuspended(value: IrValueSymbol) =
irIfThen(irEqeqeq(irGet(value), irCall(symbols.coroutineSuspendedGetter)), irIfThen(irEqeqeq(irGet(value), irCall(symbols.coroutineSuspendedGetter)),
irReturn(irGet(value))) irReturn(irGet(value)))
private fun IrBuilderWithScope.irThrowIfNotNull(exception: IrValueSymbol) = private fun IrBuilderWithScope.irThrowIfNotNull(exception: IrValueDeclaration) =
irIfThen(irNot(irEqeqeq(irGet(exception), irNull())), 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 { private open class VariablesScopeTracker: IrElementVisitorVoid {
protected val scopeStack = mutableListOf<MutableSet<IrVariableSymbol>>(mutableSetOf()) protected val scopeStack = mutableListOf<MutableSet<IrVariable>>(mutableSetOf())
override fun visitElement(element: IrElement) { override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this) element.acceptChildrenVoid(this)
@@ -1174,7 +1208,7 @@ internal class SuspendFunctionsLowering(val context: Context): DeclarationContai
override fun visitVariable(declaration: IrVariable) { override fun visitVariable(declaration: IrVariable) {
super.visitVariable(declaration) 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.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName 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.backend.konan.reportCompilationError
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.isFunctionType 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.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* 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.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl 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.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.* 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.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl 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.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -98,50 +99,50 @@ internal class TestProcessor (val context: KonanBackendContext) {
add(TestFunction(function, kind)) add(TestFunction(function, kind))
private fun <T: IrElement> IrStatementsBuilder<T>.generateFunctionRegistration( private fun <T: IrElement> IrStatementsBuilder<T>.generateFunctionRegistration(
receiver: IrValueSymbol, receiver: IrValueDeclaration,
registerTestCase: IrFunctionSymbol, registerTestCase: IrFunctionSymbol,
registerFunction: IrFunctionSymbol, registerFunction: IrFunctionSymbol,
functions: Collection<TestFunction>) { functions: Collection<TestFunction>) {
functions.forEach { functions.forEach {
if (it.kind == FunctionKind.TEST) { if (it.kind == FunctionKind.TEST) {
// Call registerTestCase(name: String, testFunction: () -> Unit) method. // Call registerTestCase(name: String, testFunction: () -> Unit) method.
+irCall(registerTestCase).apply { +irCall(registerTestCase, registerTestCase.descriptor.returnType!!.toErasedIrType()).apply {
dispatchReceiver = irGet(receiver) dispatchReceiver = irGet(receiver)
putValueArgument(0, IrConstImpl.string( putValueArgument(0, IrConstImpl.string(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
context.builtIns.stringType, context.irBuiltIns.stringType,
it.function.descriptor.name.identifier) it.function.descriptor.name.identifier)
) )
putValueArgument(1, IrFunctionReferenceImpl( putValueArgument(1, IrFunctionReferenceImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
descriptor.valueParameters[1].type, descriptor.valueParameters[1].type.toErasedIrType(),
it.function, it.function,
it.function.descriptor, emptyMap())) it.function.descriptor, 0))
putValueArgument(2, IrConstImpl.boolean( putValueArgument(2, IrConstImpl.boolean(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
context.builtIns.booleanType, context.irBuiltIns.booleanType,
it.ignored it.ignored
)) ))
} }
} else { } else {
// Call registerFunction(kind: TestFunctionKind, () -> Unit) method. // Call registerFunction(kind: TestFunctionKind, () -> Unit) method.
+irCall(registerFunction).apply { +irCall(registerFunction, registerFunction.descriptor.returnType!!.toErasedIrType()).apply {
dispatchReceiver = irGet(receiver) dispatchReceiver = irGet(receiver)
val testKindEntry = it.kind.runtimeKind val testKindEntry = it.kind.runtimeKind
putValueArgument(0, IrGetEnumValueImpl( putValueArgument(0, IrGetEnumValueImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
testKindEntry.descriptor.defaultType, symbols.testFunctionKind.typeWithoutArguments,
testKindEntry) testKindEntry)
) )
putValueArgument(1, IrFunctionReferenceImpl(UNDEFINED_OFFSET, putValueArgument(1, IrFunctionReferenceImpl(UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
descriptor.valueParameters[1].type, descriptor.valueParameters[1].type.toErasedIrType(),
it.function, 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 //region Symbol and IR builders
/** Base class for getters (createInstance and getCompanion). */ /** 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 testSuite: IrClassSymbol,
val getterName: Name) val getterName: Name)
: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrFunction>() { : SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrFunction>() {
@@ -300,7 +301,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
/* dispatchReceiverParameter = */ testSuite.descriptor.thisAsReceiverParameter, /* dispatchReceiverParameter = */ testSuite.descriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(), /* typeParameters = */ emptyList(),
/* unsubstitutedValueParameters = */ emptyList(), /* unsubstitutedValueParameters = */ emptyList(),
/* returnType = */ returnType, /* returnType = */ returnType.toKotlinType(),
/* modality = */ Modality.FINAL, /* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PROTECTED /* visibility = */ Visibilities.PROTECTED
).apply { ).apply {
@@ -324,18 +325,21 @@ internal class TestProcessor (val context: KonanBackendContext) {
* returning a reference to an object represented by `[objectSymbol]`. * returning a reference to an object represented by `[objectSymbol]`.
*/ */
private inner class ObjectGetterBuilder(val objectSymbol: IrClassSymbol, testSuite: IrClassSymbol, getterName: Name) 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( override fun buildIr(): IrFunction = IrFunctionImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
TEST_SUITE_GENERATED_MEMBER, TEST_SUITE_GENERATED_MEMBER,
symbol).apply { symbol).apply {
this.returnType = this@ObjectGetterBuilder.returnType
val builder = context.createIrBuilder(symbol) val builder = context.createIrBuilder(symbol)
createParameterDeclarations() createParameterDeclarations(context.ir.symbols.symbolTable)
body = builder.irBlockBody { body = builder.irBlockBody {
+irReturn(IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, +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]. * returning a new instance of class referenced by [classSymbol].
*/ */
private inner class InstanceGetterBuilder(val classSymbol: IrClassSymbol, testSuite: IrClassSymbol, getterName: Name) 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( override fun buildIr() = IrFunctionImpl(
startOffset = UNDEFINED_OFFSET, startOffset = UNDEFINED_OFFSET,
endOffset = UNDEFINED_OFFSET, endOffset = UNDEFINED_OFFSET,
origin = TEST_SUITE_GENERATED_MEMBER, origin = TEST_SUITE_GENERATED_MEMBER,
symbol = symbol).apply { symbol = symbol).apply {
this.returnType = this@InstanceGetterBuilder.returnType
val builder = context.createIrBuilder(symbol) val builder = context.createIrBuilder(symbol)
createParameterDeclarations() createParameterDeclarations(context.ir.symbols.symbolTable)
body = builder.irBlockBody { body = builder.irBlockBody {
val constructor = classSymbol.constructors.single { it.descriptor.valueParameters.isEmpty() } val constructor = classSymbol.owner.constructors.single { it.valueParameters.isEmpty() }
+irReturn(irCall(constructor)) +irReturn(irCall(constructor))
} }
} }
@@ -385,15 +392,18 @@ internal class TestProcessor (val context: KonanBackendContext) {
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
TEST_SUITE_GENERATED_MEMBER, TEST_SUITE_GENERATED_MEMBER,
symbol).apply { 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 && it.valueParameters.size == 3 &&
KotlinBuiltIns.isString(it.valueParameters[0].type) && // name: String KotlinBuiltIns.isString(it.valueParameters[0].type) && // name: String
it.valueParameters[1].type.isFunctionType && // function: testClassType.() -> Unit it.valueParameters[1].type.isFunctionType && // function: testClassType.() -> Unit
KotlinBuiltIns.isBoolean(it.valueParameters[2].type) // ignored: Boolean 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.size == 2 &&
it.valueParameters[0].type == symbols.testFunctionKind.descriptor.defaultType && // kind: TestFunctionKind it.valueParameters[0].type == symbols.testFunctionKind.descriptor.defaultType && // kind: TestFunctionKind
it.valueParameters[1].type.isFunctionType // function: () -> Unit it.valueParameters[1].type.isFunctionType // function: () -> Unit
@@ -404,26 +414,28 @@ internal class TestProcessor (val context: KonanBackendContext) {
+IrDelegatingConstructorCallImpl( +IrDelegatingConstructorCallImpl(
startOffset = UNDEFINED_OFFSET, startOffset = UNDEFINED_OFFSET,
endOffset = UNDEFINED_OFFSET, endOffset = UNDEFINED_OFFSET,
type = context.irBuiltIns.unitType,
symbol = symbols.symbolTable.referenceConstructor(superConstructor), symbol = symbols.symbolTable.referenceConstructor(superConstructor),
descriptor = superConstructor, descriptor = superConstructor,
typeArgumentsCount = 2 typeArgumentsCount = 2
).apply { ).apply {
copyTypeArgumentsFrom(mapOf(superConstructor.typeParameters[0] to testClassType, putTypeArgument(0, testClassType.toErasedIrType())
superConstructor.typeParameters[1] to testCompanionType)) putTypeArgument(1, testCompanionType.toErasedIrType())
putValueArgument(0, IrConstImpl.string( putValueArgument(0, IrConstImpl.string(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
context.builtIns.stringType, context.irBuiltIns.stringType,
suiteName) suiteName)
) )
putValueArgument(1, IrConstImpl.boolean( putValueArgument(1, IrConstImpl.boolean(
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
context.builtIns.booleanType, context.irBuiltIns.booleanType,
ignored ignored
)) ))
} }
generateFunctionRegistration(testSuite.owner.thisReceiver!!.symbol, generateFunctionRegistration(testSuite.owner.thisReceiver!!,
registerTestCase, registerFunction, functions) 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) * 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. * 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,
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
TEST_SUITE_CLASS, TEST_SUITE_CLASS,
symbol).apply { symbol.descriptor).apply {
createParameterDeclarations() createParameterDeclarations()
addMember(constructorBuilder.ir) addMember(constructorBuilder.ir)
addMember(instanceGetterBuilder.ir) addMember(instanceGetterBuilder.ir)
companionGetterBuilder?.let { addMember(it.ir) } companionGetterBuilder?.let { addMember(it.ir) }
addFakeOverrides() addFakeOverrides(symbols.symbolTable)
setSuperSymbols(context.ir.symbols.symbolTable) setSuperSymbols(symbols.symbolTable)
} }
override fun doInitialize() { override fun doInitialize() {
@@ -526,7 +540,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
companionGetterBuilder?.initialize() companionGetterBuilder?.initialize()
} }
override fun buildSymbol() = IrClassSymbolImpl( override fun buildSymbol() = symbols.symbolTable.referenceClass(
ClassDescriptorImpl( ClassDescriptorImpl(
/* containingDeclaration = */ containingDeclaration, /* containingDeclaration = */ containingDeclaration,
/* name = */ suiteClassName, /* name = */ suiteClassName,
@@ -549,8 +563,9 @@ internal class TestProcessor (val context: KonanBackendContext) {
testClass.functions)) { testClass.functions)) {
initialize() initialize()
irFile.addChild(ir) irFile.addChild(ir)
val irConstructor = ir.constructors.single()
irFile.addTopLevelInitializer( 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 { irFile.addTopLevelInitializer(builder.irBlock {
val constructorCall = irCall(symbols.topLevelSuiteConstructor).apply { val constructorCall = irCall(symbols.topLevelSuiteConstructor).apply {
putValueArgument(0, IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET, putValueArgument(0, IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET,
context.builtIns.stringType, suiteName)) context.irBuiltIns.stringType, suiteName))
} }
val testSuiteVal = irTemporary(constructorCall, "topLevelTestSuite") val testSuiteVal = irTemporary(constructorCall, "topLevelTestSuite")
generateFunctionRegistration(testSuiteVal.symbol, generateFunctionRegistration(testSuiteVal,
symbols.topLevelSuiteRegisterTestCase, symbols.topLevelSuiteRegisterTestCase,
symbols.topLevelSuiteRegisterFunction, symbols.topLevelSuiteRegisterFunction,
functions) 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.at
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor 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.IrStatement
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall 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.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.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils 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. * This lowering pass lowers some [IrTypeOperatorCall]s.
@@ -60,22 +65,24 @@ private class TypeOperatorTransformer(val context: CommonBackendContext, val fun
return declaration return declaration
} }
private fun KotlinType.erasure(): KotlinType { private fun IrType.erasure(): IrType {
val descriptor = this.constructor.declarationDescriptor if (this !is IrSimpleType) return this
return when (descriptor) {
is ClassDescriptor -> this
is TypeParameterDescriptor -> {
val upperBound = descriptor.upperBounds.singleOrNull() ?:
TODO("$descriptor : ${descriptor.upperBounds}")
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?` // `T?`
upperBound.erasure().makeNullable() upperBound.erasure().makeNullable()
} else { } else {
upperBound.erasure() 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) builder.at(expression)
val typeOperand = expression.typeOperand.erasure() 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. // TODO: consider the case when expression type is wrong e.g. due to generics-related unchecked casts.
return when { return when {
expression.argument.type.isSubtypeOf(typeOperand) -> expression.argument expression.argument.type.isSubtypeOf(typeOperand) -> expression.argument
expression.argument.type.isNullable() -> { expression.argument.type.containsNull() -> {
with (builder) { with (builder) {
irLetS(expression.argument) { argument -> irLetS(expression.argument) { argument ->
irIfThenElse( irIfThenElse(
type = expression.type, type = expression.type,
condition = irEqeqeq(irGet(argument), irNull()), condition = irEqeqeq(irGet(argument.owner), irNull()),
thenPart = if (typeOperand.isMarkedNullable) thenPart = if (typeOperand.isSimpleTypeWithQuestionMark)
irNull() irNull()
else 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 typeOperand == expression.typeOperand -> expression
@@ -124,8 +131,8 @@ private class TypeOperatorTransformer(val context: CommonBackendContext, val fun
return builder.irBlock(expression) { return builder.irBlock(expression) {
+irLetS(expression.argument) { variable -> +irLetS(expression.argument) { variable ->
irIfThenElse(expression.type, irIfThenElse(expression.type,
condition = irIs(irGet(variable), typeOperand), condition = irIs(irGet(variable.owner), typeOperand),
thenPart = irImplicitCast(irGet(variable), typeOperand), thenPart = irImplicitCast(irGet(variable.owner), typeOperand),
elsePart = irNull()) 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.functionName
import org.jetbrains.kotlin.backend.konan.llvm.localHash import org.jetbrains.kotlin.backend.konan.llvm.localHash
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET 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.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* 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.getArguments
import org.jetbrains.kotlin.ir.util.simpleFunctions import org.jetbrains.kotlin.ir.util.simpleFunctions
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlin.util.OperatorNameConventions 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. * Some primitive types can be null and some can't. Those that can't must be replaced with the corresponding box.
* Int -> Int * Int -> Int
@@ -61,29 +60,29 @@ private fun getClassWithBoxingIncluded(type: KotlinType, ir: KonanIr): ClassDesc
* CPointer -> CPointer * CPointer -> CPointer
* CPointer? -> CPointer * CPointer? -> CPointer
*/ */
return if (type.correspondingValueType == null && type.makeNotNullable().correspondingValueType != null) return if (type.correspondingValueType == null && type.makeNotNull().correspondingValueType != null)
ir.getClass(ir.symbols.getTypeConversion(type.makeNotNullable(), type)!!.descriptor.returnType!!)!! ir.symbols.getTypeConversion(type.makeNotNull(), type)!!.owner.returnType.getClass()!!
else 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) val irClass = getClassWithBoxingIncluded(type, ir)
if (irClass != null) { if (irClass != null) {
erasure += irClass erasure += irClass
} else { } else {
val descriptor = type.constructor.declarationDescriptor val classifier = type.classifierOrFail
if (descriptor is TypeParameterDescriptor) { if (classifier is IrTypeParameterSymbol) {
descriptor.upperBounds.forEach { classifier.owner.superTypes.forEach {
computeErasure(it, ir, erasure) computeErasure(it, ir, erasure)
} }
} else { } 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>() val result = mutableListOf<ClassDescriptor>()
computeErasure(this, context.ir, result) computeErasure(this, context.ir, result)
return result return result
@@ -163,7 +162,7 @@ private class ExpressionValuesExtractor(val context: Context,
forEachValue( forEachValue(
expression = (expression.statements.last() as? IrExpression) expression = (expression.statements.last() as? IrExpression)
?: IrGetObjectValueImpl(expression.startOffset, expression.endOffset, ?: IrGetObjectValueImpl(expression.startOffset, expression.endOffset,
context.builtIns.unitType, context.ir.symbols.unit), context.irBuiltIns.unitType, context.ir.symbols.unit),
block = block block = block
) )
} }
@@ -187,7 +186,8 @@ private class ExpressionValuesExtractor(val context: Context,
else { // Propagate cast to sub-values. else { // Propagate cast to sub-values.
forEachValue(expression.argument) { value -> forEachValue(expression.argument) { value ->
with(expression) { 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) { override fun visitConstructor(declaration: IrConstructor) {
val body = declaration.body 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" "Non-annotation class constructor has empty body"
} }
DEBUG_OUTPUT(0) { DEBUG_OUTPUT(0) {
@@ -280,7 +280,8 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
println("Analysing global field ${declaration.descriptor}") println("Analysing global field ${declaration.descriptor}")
println("IR: ${ir2stringWhole(declaration)}") 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) { if (expression is IrCall && expression.symbol == scheduleImplSymbol) {
// Producer and job of scheduleImpl are called externally, we need to reflect this somehow. // Producer and job of scheduleImpl are called externally, we need to reflect this somehow.
val producerInvocation = IrCallImpl(expression.startOffset, expression.endOffset, val producerInvocation = IrCallImpl(expression.startOffset, expression.endOffset,
scheduleImplProducerInvoke.returnType,
scheduleImplProducerInvoke.symbol, scheduleImplProducerInvoke.descriptor) scheduleImplProducerInvoke.symbol, scheduleImplProducerInvoke.descriptor)
producerInvocation.dispatchReceiver = expression.getValueArgument(2) producerInvocation.dispatchReceiver = expression.getValueArgument(2)
val jobFunctionReference = expression.getValueArgument(3) as? IrFunctionReference val jobFunctionReference = expression.getValueArgument(3) as? IrFunctionReference
?: error("A function reference expected") ?: error("A function reference expected")
val jobInvocation = IrCallImpl(expression.startOffset, expression.endOffset, val jobInvocation = IrCallImpl(expression.startOffset, expression.endOffset,
jobFunctionReference.symbol.owner.returnType,
jobFunctionReference.symbol, jobFunctionReference.descriptor) jobFunctionReference.symbol, jobFunctionReference.descriptor)
jobInvocation.putValueArgument(0, producerInvocation) 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 .filterIsInstance<IrSimpleFunction>().single { it.name.asString() == "doResume" }.symbol
private val getContinuationSymbol = context.ir.symbols.getContinuation private val getContinuationSymbol = context.ir.symbols.getContinuation
private val continuationType = getContinuationSymbol.owner.returnType
private val arrayGetSymbol = context.ir.symbols.arrayGet private val arrayGetSymbol = context.ir.symbols.arrayGet
private val arraySetSymbol = context.ir.symbols.arraySet 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 owner = callee.containingDeclaration as ClassDescriptor
val actualReceiverType = value.dispatchReceiver!!.type val actualReceiverType = value.dispatchReceiver!!.type
val receiverType = val receiverType =
if (actualReceiverType.constructor.declarationDescriptor is TypeParameterDescriptor if (actualReceiverType.classifierOrNull is IrTypeParameterSymbol
|| !callee.isReal /* Could be a bridge. */) || !callee.isReal /* Could be a bridge. */)
symbolTable.mapClass(owner) symbolTable.mapClass(owner)
else { else {
val actualClassAtCallsite = actualReceiverType.constructor.declarationDescriptor as org.jetbrains.kotlin.descriptors.ClassDescriptor val actualClassAtCallsite =
assert (DescriptorUtils.isSubclass(actualClassAtCallsite, owner.descriptor)) { actualReceiverType.classifierOrFail.descriptor
"Expected an inheritor of ${owner.descriptor}, but was $actualClassAtCallsite" 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) { if (owner.isInterface) {
val calleeHash = callee.functionName.localHash.value val calleeHash = callee.functionName.localHash.value
@@ -681,8 +691,9 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
} }
is IrDelegatingConstructorCall -> { is IrDelegatingConstructorCall -> {
val thiz = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, val thisReceiver = (descriptor as ConstructorDescriptor).constructedClass.thisReceiver!!
(descriptor as ConstructorDescriptor).constructedClass.thisReceiver!!.symbol) val thiz = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, thisReceiver.type,
thisReceiver.symbol)
val arguments = listOf(thiz) + value.getArguments().map { it.second } val arguments = listOf(thiz) + value.getArguments().map { it.second }
DataFlowIR.Node.StaticCall( DataFlowIR.Node.StaticCall(
symbolTable.mapFunction(value.symbol.owner), 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.IrCall
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrGetField 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.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature 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.name.Name
import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.IntValue 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 { internal object DataFlowIR {
@@ -468,7 +468,7 @@ internal object DataFlowIR {
private val pointsToOnWhomDescriptor = pointsToAnnotationDescriptor.unsubstitutedPrimaryConstructor!!.valueParameters.single() private val pointsToOnWhomDescriptor = pointsToAnnotationDescriptor.unsubstitutedPrimaryConstructor!!.valueParameters.single()
private val getContinuationSymbol = context.ir.symbols.getContinuation private val getContinuationSymbol = context.ir.symbols.getContinuation
private val continuationType = getContinuationSymbol.descriptor.returnType!! private val continuationType = getContinuationSymbol.owner.returnType
var privateTypeIndex = 0 var privateTypeIndex = 0
var privateFunIndex = 0 var privateFunIndex = 0
@@ -524,7 +524,7 @@ internal object DataFlowIR {
classMap[descriptor] = type classMap[descriptor] = type
type.superTypes += descriptor.defaultType.immediateSupertypes().map { mapType(it) } type.superTypes += descriptor.superTypes.map { mapType(it) }
if (!isAbstract) { if (!isAbstract) {
val vtableBuilder = context.getVtableBuilder(descriptor) val vtableBuilder = context.getVtableBuilder(descriptor)
type.vtable += vtableBuilder.vtableEntries.map { mapFunction(it.getImplementation(context)!!) } 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 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. // TODO: use from LlvmDeclarations.
private fun getFqName(descriptor: DeclarationDescriptor): FqName = private fun getFqName(descriptor: DeclarationDescriptor): FqName =
@@ -605,7 +605,7 @@ internal object DataFlowIR {
.map { mapClass(choosePrimary(it.erasure(context))) } .map { mapClass(choosePrimary(it.erasure(context))) }
.toTypedArray() .toTypedArray()
symbol.returnType = mapType(if (descriptor.isSuspend) symbol.returnType = mapType(if (descriptor.isSuspend)
context.builtIns.anyType context.irBuiltIns.anyType
else else
descriptor.returnType) 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.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.ir.IrPrivateClassReferenceImpl import org.jetbrains.kotlin.backend.konan.ir.IrPrivateClassReferenceImpl
import org.jetbrains.kotlin.backend.konan.ir.IrPrivateFunctionCallImpl import org.jetbrains.kotlin.backend.konan.ir.IrPrivateFunctionCallImpl
import org.jetbrains.kotlin.backend.konan.lower.nullConst import org.jetbrains.kotlin.backend.konan.irasdescriptors.getErasedTypeClass
import org.jetbrains.kotlin.backend.konan.objcexport.getErasedTypeClass
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement 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.IrExpression
import org.jetbrains.kotlin.ir.expressions.getValueArgument import org.jetbrains.kotlin.ir.expressions.getValueArgument
import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl 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.expressions.impl.IrWhenImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol 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.addArguments
import org.jetbrains.kotlin.ir.util.getArguments 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.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.types.KotlinType
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@@ -1009,7 +1008,7 @@ internal object Devirtualization {
class PossiblyCoercedValue(val value: IrVariable, val coercion: IrFunctionSymbol?) { class PossiblyCoercedValue(val value: IrVariable, val coercion: IrFunctionSymbol?) {
fun getFullValue(irBuilder: IrBuilderWithScope) = irBuilder.run { 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 val coercion = expression as IrCall
PossiblyCoercedValue( PossiblyCoercedValue(
irTemporary(irImplicitCast(coercion.getArguments().single().second, irTemporary(irImplicitCast(coercion.getArguments().single().second,
coercion.descriptor.explicitParameters.single().type)) coercion.symbol.owner.explicitParameters.single().type))
, coercion.symbol) , coercion.symbol)
} }
@@ -1041,12 +1040,12 @@ internal object Devirtualization {
val coercion = context.ir.symbols.getTypeConversion(type.correspondingValueType, targetType.correspondingValueType) val coercion = context.ir.symbols.getTypeConversion(type.correspondingValueType, targetType.correspondingValueType)
?: return possiblyCoercedValue.getFullValue(this) ?: return possiblyCoercedValue.getFullValue(this)
if (prevCoercion == null) if (prevCoercion == null)
return irCoerce(irGet(value.symbol), coercion) return irCoerce(irGet(value), coercion)
assertCoercionsMatch(coercion, prevCoercion) 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) = devirtualizedCallee: DataFlowIR.FunctionSymbol.Declared) =
IrPrivateFunctionCallImpl( IrPrivateFunctionCallImpl(
startOffset = startOffset, startOffset = startOffset,
@@ -1062,7 +1061,7 @@ internal object Devirtualization {
virtualCallee = callee virtualCallee = callee
) )
fun IrBuilderWithScope.irDevirtualizedCall(callee: IrCall, actualType: KotlinType, fun IrBuilderWithScope.irDevirtualizedCall(callee: IrCall, actualType: IrType,
actualCallee: DataFlowIR.FunctionSymbol.Declared, actualCallee: DataFlowIR.FunctionSymbol.Declared,
receiver: IrVariable, receiver: IrVariable,
extensionReceiver: PossiblyCoercedValue?, extensionReceiver: PossiblyCoercedValue?,
@@ -1070,7 +1069,7 @@ internal object Devirtualization {
actualCallee.bridgeTarget.let { actualCallee.bridgeTarget.let {
if (it == null) if (it == null)
irDevirtualizedCall(callee, actualType, actualCallee).apply { irDevirtualizedCall(callee, actualType, actualCallee).apply {
this.dispatchReceiver = irGet(receiver.symbol) this.dispatchReceiver = irGet(receiver)
this.extensionReceiver = extensionReceiver?.getFullValue(this@irDevirtualizedCall) this.extensionReceiver = extensionReceiver?.getFullValue(this@irDevirtualizedCall)
callee.descriptor.valueParameters.forEach { callee.descriptor.valueParameters.forEach {
putValueArgument(it.index, parameters[it]!!.getFullValue(this@irDevirtualizedCall)) putValueArgument(it.index, parameters[it]!!.getFullValue(this@irDevirtualizedCall))
@@ -1079,7 +1078,7 @@ internal object Devirtualization {
else { else {
val bridgeTarget = it.resolved() as DataFlowIR.FunctionSymbol.Declared val bridgeTarget = it.resolved() as DataFlowIR.FunctionSymbol.Declared
val callResult = irDevirtualizedCall(callee, actualType, bridgeTarget).apply { val callResult = irDevirtualizedCall(callee, actualType, bridgeTarget).apply {
this.dispatchReceiver = irGet(receiver.symbol) this.dispatchReceiver = irGet(receiver)
this.extensionReceiver = extensionReceiver?.let { this.extensionReceiver = extensionReceiver?.let {
irCoerceIfNeeded( irCoerceIfNeeded(
type = actualCallee.parameterTypes[1].resolved(), type = actualCallee.parameterTypes[1].resolved(),
@@ -1140,21 +1139,22 @@ internal object Devirtualization {
val startOffset = expression.startOffset val startOffset = expression.startOffset
val endOffset = expression.endOffset val endOffset = expression.endOffset
val type = if (descriptor.isSuspend) val type = if (descriptor.isSuspend)
context.builtIns.nullableAnyType context.irBuiltIns.anyNType
else descriptor.original.returnType!! else expression.symbol.owner.returnType
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, startOffset, endOffset)
irBuilder.run { irBuilder.run {
val dispatchReceiver = expression.dispatchReceiver!! val dispatchReceiver = expression.dispatchReceiver!!
return when { return when {
possibleCallees.isEmpty() -> irBlock(expression) { possibleCallees.isEmpty() -> irBlock(expression) {
+irCall(context.ir.symbols.throwInvalidReceiverTypeException).apply { val throwExpr = irCall(context.ir.symbols.throwInvalidReceiverTypeException.owner).apply {
putValueArgument(0, irCall(context.ir.symbols.kClassImplConstructor, listOf(dispatchReceiver.type)).apply { putValueArgument(0, irCall(context.ir.symbols.kClassImplConstructor.owner, listOf(dispatchReceiver.type)).apply {
putValueArgument(0, irCall(context.ir.symbols.getObjectTypeInfo).apply { putValueArgument(0, irCall(context.ir.symbols.getObjectTypeInfo.owner).apply {
putValueArgument(0, dispatchReceiver) 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. optimize && possibleCallees.size == 1 -> { // Monomorphic callsite.
@@ -1176,7 +1176,7 @@ internal object Devirtualization {
it to irSplitCoercion(expression.getValueArgument(it)!!) it to irSplitCoercion(expression.getValueArgument(it)!!)
} }
val typeInfo = irTemporary(irCall(context.ir.symbols.getObjectTypeInfo).apply { val typeInfo = irTemporary(irCall(context.ir.symbols.getObjectTypeInfo).apply {
putValueArgument(0, irGet(receiver.symbol)) putValueArgument(0, irGet(receiver))
}) })
val branches = mutableListOf<IrBranchImpl>() val branches = mutableListOf<IrBranchImpl>()
@@ -1186,8 +1186,8 @@ internal object Devirtualization {
val expectedTypeInfo = IrPrivateClassReferenceImpl( val expectedTypeInfo = IrPrivateClassReferenceImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
type = nativePtrType, type = context.ir.symbols.nativePtrType,
symbol = IrClassSymbolImpl(dispatchReceiver.type.getErasedTypeClass()), symbol = dispatchReceiver.type.getErasedTypeClass(),
classType = receiver.type, classType = receiver.type,
moduleDescriptor = actualReceiverType.module!!.descriptor, moduleDescriptor = actualReceiverType.module!!.descriptor,
totalClasses = actualReceiverType.module.numberOfClasses, totalClasses = actualReceiverType.module.numberOfClasses,
@@ -1198,7 +1198,7 @@ internal object Devirtualization {
irTrue() // Don't check last type in optimize mode. irTrue() // Don't check last type in optimize mode.
else else
irCall(nativePtrEqualityOperatorSymbol).apply { irCall(nativePtrEqualityOperatorSymbol).apply {
putValueArgument(0, irGet(typeInfo.symbol)) putValueArgument(0, irGet(typeInfo))
putValueArgument(1, expectedTypeInfo) putValueArgument(1, expectedTypeInfo)
} }
IrBranchImpl( IrBranchImpl(
@@ -1218,7 +1218,7 @@ internal object Devirtualization {
irCall(context.ir.symbols.kClassImplConstructor, irCall(context.ir.symbols.kClassImplConstructor,
listOf(dispatchReceiver.type) listOf(dispatchReceiver.type)
).apply { ).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.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.* import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.util.addFakeOverrides import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.createParameterDeclarations import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.setOverrides import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.setSuperSymbols import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.serialization.KonanDescriptorSerializer import org.jetbrains.kotlin.serialization.KonanDescriptorSerializer
import org.jetbrains.kotlin.metadata.KonanIr import org.jetbrains.kotlin.metadata.KonanIr
import org.jetbrains.kotlin.metadata.KonanIr.IrConst.ValueCase.* import org.jetbrains.kotlin.metadata.KonanIr.IrConst.ValueCase.*
@@ -82,6 +82,8 @@ internal class IrSerializer(val context: Context,
return irDescriptorSerializer.serializeKotlinType(type) return irDescriptorSerializer.serializeKotlinType(type)
} }
private fun serializeKotlinType(type: IrType) = serializeKotlinType(type.toKotlinType())
private fun serializeDescriptor(descriptor: DeclarationDescriptor): KonanIr.KotlinDescriptor { private fun serializeDescriptor(descriptor: DeclarationDescriptor): KonanIr.KotlinDescriptor {
context.log{"### serializeDescriptor $descriptor"} context.log{"### serializeDescriptor $descriptor"}
@@ -719,12 +721,12 @@ internal class IrDeserializer(val context: Context,
private fun deserializeDescriptor(proto: KonanIr.KotlinDescriptor) private fun deserializeDescriptor(proto: KonanIr.KotlinDescriptor)
= descriptorDeserializer.deserializeDescriptor(proto) = descriptorDeserializer.deserializeDescriptor(proto)
private fun deserializeTypeArguments(proto: KonanIr.TypeArguments): List<KotlinType> { private fun deserializeTypeArguments(proto: KonanIr.TypeArguments): List<IrType> {
context.log{"### deserializeTypeArguments"} context.log{"### deserializeTypeArguments"}
val result = mutableListOf<KotlinType>() val result = mutableListOf<IrType>()
proto.typeArgumentList.forEach { type -> proto.typeArgumentList.forEach { type ->
val kotlinType = deserializeKotlinType(type) val kotlinType = deserializeKotlinType(type)
result.add(kotlinType) result.add(kotlinType.brokenIr)
context.log{"$kotlinType"} context.log{"$kotlinType"}
} }
return result return result
@@ -782,6 +784,9 @@ internal class IrDeserializer(val context: Context,
return element 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 { private fun deserializeBlock(proto: KonanIr.IrBlock, start: Int, end: Int, type: KotlinType): IrBlock {
val statements = mutableListOf<IrStatement>() val statements = mutableListOf<IrStatement>()
val statementProtos = proto.statementList val statementProtos = proto.statementList
@@ -791,7 +796,7 @@ internal class IrDeserializer(val context: Context,
val isLambdaOrigin = if (proto.isLambdaOrigin) IrStatementOrigin.LAMBDA else null 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) { 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 val descriptor = deserializeDescriptor(proto.classDescriptor) as ClassifierDescriptor
/** TODO: [createClassifierSymbolForClassReference] is internal function */ /** TODO: [createClassifierSymbolForClassReference] is internal function */
@Suppress("DEPRECATION") @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 { 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) { val call: IrCall = when (proto.kind) {
KonanIr.IrCall.Primitive.NOT_PRIMITIVE -> KonanIr.IrCall.Primitive.NOT_PRIMITIVE ->
// TODO: implement the last three args here. // 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 -> KonanIr.IrCall.Primitive.NULLARY ->
IrNullaryPrimitiveImpl(start, end, null, createFunctionSymbol(descriptor)) IrNullaryPrimitiveImpl(start, end, type.ir, null, createFunctionSymbol(descriptor))
KonanIr.IrCall.Primitive.UNARY -> KonanIr.IrCall.Primitive.UNARY ->
IrUnaryPrimitiveImpl(start, end, null, createFunctionSymbol(descriptor)) IrUnaryPrimitiveImpl(start, end, type.ir, null, createFunctionSymbol(descriptor))
KonanIr.IrCall.Primitive.BINARY -> KonanIr.IrCall.Primitive.BINARY ->
IrBinaryPrimitiveImpl(start, end, null, createFunctionSymbol(descriptor)) IrBinaryPrimitiveImpl(start, end, type.ir, null, createFunctionSymbol(descriptor))
else -> TODO("Unexpected primitive IrCall.") else -> TODO("Unexpected primitive IrCall.")
} }
deserializeMemberAccessCommon(call, proto.memberAccess) deserializeMemberAccessCommon(call, proto.memberAccess)
@@ -850,7 +855,7 @@ internal class IrDeserializer(val context: Context,
val descriptor = deserializeDescriptor(proto.descriptor) as CallableDescriptor val descriptor = deserializeDescriptor(proto.descriptor) as CallableDescriptor
val callable = when (descriptor) { 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() else -> TODO()
} }
@@ -866,12 +871,12 @@ internal class IrDeserializer(val context: Context,
statementProtos.forEach { statementProtos.forEach {
statements.add(deserializeStatement(it) as IrStatement) 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 { private fun deserializeDelegatingConstructorCall(proto: KonanIr.IrDelegatingConstructorCall, start: Int, end: Int): IrDelegatingConstructorCall {
val descriptor = deserializeDescriptor(proto.descriptor) as ClassConstructorDescriptor 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) deserializeMemberAccessCommon(call, proto.memberAccess)
return call 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 { private fun deserializeGetClass(proto: KonanIr.IrGetClass, start: Int, end: Int, type: KotlinType): IrGetClass {
val argument = deserializeExpression(proto.argument) 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 { private fun deserializeGetField(proto: KonanIr.IrGetField, start: Int, end: Int): IrGetField {
@@ -892,39 +897,39 @@ internal class IrDeserializer(val context: Context,
deserializeExpression(access.receiver) deserializeExpression(access.receiver)
} else null } 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 { private fun deserializeGetValue(proto: KonanIr.IrGetValue, start: Int, end: Int): IrGetValue {
val descriptor = deserializeDescriptor(proto.descriptor) as ValueDescriptor val descriptor = deserializeDescriptor(proto.descriptor) as ValueDescriptor
// TODO: origin! // 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 { private fun deserializeGetEnumValue(proto: KonanIr.IrGetEnumValue, start: Int, end: Int): IrGetEnumValue {
val type = deserializeKotlinType(proto.type) val type = deserializeKotlinType(proto.type)
val descriptor = deserializeDescriptor(proto.descriptor) as ClassDescriptor 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 { private fun deserializeGetObject(proto: KonanIr.IrGetObject, start: Int, end: Int, type: KotlinType): IrGetObjectValue {
val descriptor = deserializeDescriptor(proto.descriptor) as ClassDescriptor 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 { private fun deserializeInstanceInitializerCall(proto: KonanIr.IrInstanceInitializerCall, start: Int, end: Int): IrInstanceInitializerCall {
val descriptor = deserializeDescriptor(proto.descriptor) as ClassDescriptor 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 { private fun deserializeReturn(proto: KonanIr.IrReturn, start: Int, end: Int, type: KotlinType): IrReturn {
val descriptor = val descriptor =
deserializeDescriptor(proto.returnTarget) as FunctionDescriptor deserializeDescriptor(proto.returnTarget) as FunctionDescriptor
val value = deserializeExpression(proto.value) 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 { private fun deserializeSetField(proto: KonanIr.IrSetField, start: Int, end: Int): IrSetField {
@@ -938,13 +943,13 @@ internal class IrDeserializer(val context: Context,
} else null } else null
val value = deserializeExpression(proto.value) 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 { private fun deserializeSetVariable(proto: KonanIr.IrSetVariable, start: Int, end: Int): IrSetVariable {
val descriptor = deserializeDescriptor(proto.descriptor) as VariableDescriptor val descriptor = deserializeDescriptor(proto.descriptor) as VariableDescriptor
val value = deserializeExpression(proto.value) 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 { private fun deserializeSpreadElement(proto: KonanIr.IrSpreadElement): IrSpreadElement {
@@ -959,11 +964,11 @@ internal class IrDeserializer(val context: Context,
argumentProtos.forEach { argumentProtos.forEach {
arguments.add(deserializeExpression(it)) 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 { 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 { 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 = val finallyExpression =
if (proto.hasFinally()) deserializeExpression(proto.getFinally()) else null 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 { 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 { private fun deserializeTypeOp(proto: KonanIr.IrTypeOp, start: Int, end: Int, type: KotlinType) : IrTypeOperatorCall {
val operator = deserializeTypeOperator(proto.operator) val operator = deserializeTypeOperator(proto.operator)
val operand = deserializeKotlinType(proto.operand) val operand = deserializeKotlinType(proto.operand).brokenIr
val argument = deserializeExpression(proto.argument) 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 { 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 { proto.elementList.forEach {
elements.add(deserializeVarargElement(it)) 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 { private fun deserializeVarargElement(element: KonanIr.IrVarargElement): IrVarargElement {
@@ -1033,7 +1041,7 @@ internal class IrDeserializer(val context: Context,
} }
// TODO: provide some origin! // 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 { 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 { private fun deserializeDoWhile(proto: KonanIr.IrDoWhile, start: Int, end: Int, type: KotlinType): IrDoWhileLoop {
// we create the loop before deserializing the body, so that // we create the loop before deserializing the body, so that
// IrBreak statements have something to put into 'loop' field. // 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) deserializeLoop(proto.loop, loop)
return 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 { private fun deserializeWhile(proto: KonanIr.IrWhile, start: Int, end: Int, type: KotlinType): IrWhileLoop {
// we create the loop before deserializing the body, so that // we create the loop before deserializing the body, so that
// IrBreak statements have something to put into 'loop' field. // 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) deserializeLoop(proto.loop, loop)
return loop return loop
} }
@@ -1071,7 +1079,7 @@ internal class IrDeserializer(val context: Context,
val label = if(proto.hasLabel()) proto.label else null val label = if(proto.hasLabel()) proto.label else null
val loopId = proto.loopId val loopId = proto.loopId
val loop = loopIndex[loopId]!! val loop = loopIndex[loopId]!!
val irBreak = IrBreakImpl(start, end, type, loop) val irBreak = IrBreakImpl(start, end, type.ir, loop)
irBreak.label = label irBreak.label = label
return irBreak return irBreak
@@ -1081,7 +1089,7 @@ internal class IrDeserializer(val context: Context,
val label = if(proto.hasLabel()) proto.label else null val label = if(proto.hasLabel()) proto.label else null
val loopId = proto.loopId val loopId = proto.loopId
val loop = loopIndex[loopId]!! val loop = loopIndex[loopId]!!
val irContinue = IrContinueImpl(start, end, type, loop) val irContinue = IrContinueImpl(start, end, type.ir, loop)
irContinue.label = label irContinue.label = label
return irContinue 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 = private fun deserializeConst(proto: KonanIr.IrConst, start: Int, end: Int, type: KotlinType): IrExpression =
when(proto.valueCase) { when(proto.valueCase) {
NULL NULL
-> IrConstImpl.constNull(start, end, type) -> IrConstImpl.constNull(start, end, type.ir)
BOOLEAN BOOLEAN
-> IrConstImpl.boolean(start, end, type, proto.boolean) -> IrConstImpl.boolean(start, end, type.ir, proto.boolean)
BYTE BYTE
-> IrConstImpl.byte(start, end, type, proto.byte.toByte()) -> IrConstImpl.byte(start, end, type.ir, proto.byte.toByte())
SHORT SHORT
-> IrConstImpl.short(start, end, type, proto.short.toShort()) -> IrConstImpl.short(start, end, type.ir, proto.short.toShort())
INT INT
-> IrConstImpl.int(start, end, type, proto.int) -> IrConstImpl.int(start, end, type.ir, proto.int)
LONG LONG
-> IrConstImpl.long(start, end, type, proto.long) -> IrConstImpl.long(start, end, type.ir, proto.long)
STRING STRING
-> IrConstImpl.string(start, end, type, proto.string) -> IrConstImpl.string(start, end, type.ir, proto.string)
FLOAT FLOAT
-> IrConstImpl.float(start, end, type, proto.float) -> IrConstImpl.float(start, end, type.ir, proto.float)
DOUBLE DOUBLE
-> IrConstImpl.double(start, end, type, proto.double) -> IrConstImpl.double(start, end, type.ir, proto.double)
else -> { else -> {
TODO("Not all const types have been implemented") 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) val clazz = IrClassImpl(start, end, origin, descriptor, members)
clazz.createParameterDeclarations() val symbolTable = context.ir.symbols.symbolTable
clazz.addFakeOverrides() clazz.createParameterDeclarations(symbolTable)
clazz.setSuperSymbols(context.ir.symbols.symbolTable) clazz.addFakeOverrides(symbolTable)
clazz.setSuperSymbols(symbolTable)
return clazz return clazz
@@ -1203,10 +1212,12 @@ internal class IrDeserializer(val context: Context,
start: Int, end: Int, origin: IrDeclarationOrigin): IrFunction { start: Int, end: Int, origin: IrDeclarationOrigin): IrFunction {
val body = deserializeStatement(proto.body) val body = deserializeStatement(proto.body)
val function = IrFunctionImpl(start, end, origin, val function = IrFunctionImpl(start, end, origin, descriptor)
descriptor, body as IrBody)
function.createParameterDeclarations() function.returnType = descriptor.returnType!!.ir
function.body = body as IrBody
function.createParameterDeclarations(context.ir.symbols.symbolTable)
function.setOverrides(context.ir.symbols.symbolTable) function.setOverrides(context.ir.symbols.symbolTable)
proto.defaultArgumentList.forEach { proto.defaultArgumentList.forEach {
@@ -1226,7 +1237,7 @@ internal class IrDeserializer(val context: Context,
deserializeExpression(proto.initializer) deserializeExpression(proto.initializer)
} else null } 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, 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.pop
import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.Context 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.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement 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.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
@Deprecated("") @Deprecated("")
@@ -47,11 +50,15 @@ internal fun IrModuleFragment.replaceUnboundSymbols(context: Context) {
val symbolTable = context.ir.symbols.symbolTable val symbolTable = context.ir.symbols.symbolTable
this.transformChildrenVoid(IrUnboundSymbolReplacer(symbolTable, collector.descriptorToSymbol)) this.transformChildrenVoid(IrUnboundSymbolReplacer(symbolTable, collector.descriptorToSymbol, context))
// Generate missing external stubs: // Generate missing external stubs:
@Suppress("DEPRECATION") @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: // Merge duplicated module and package declarations:
this.acceptVoid(object : IrElementVisitorVoid { this.acceptVoid(object : IrElementVisitorVoid {
@@ -111,7 +118,8 @@ private class DeclarationSymbolCollector : IrElementVisitorVoid {
private class IrUnboundSymbolReplacer( private class IrUnboundSymbolReplacer(
val symbolTable: SymbolTable, val symbolTable: SymbolTable,
val descriptorToSymbol: Map<DeclarationDescriptor, IrSymbol> val descriptorToSymbol: Map<DeclarationDescriptor, IrSymbol>,
val context: Context
) : IrElementTransformerVoid() { ) : IrElementTransformerVoid() {
private val localDescriptorToSymbol = mutableMapOf<DeclarationDescriptor, MutableList<IrSymbol>>() private val localDescriptorToSymbol = mutableMapOf<DeclarationDescriptor, MutableList<IrSymbol>>()
@@ -163,7 +171,7 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
return with(expression) { 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) expression.transformChildrenVoid(this)
return with(expression) { 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) expression.transformChildrenVoid(this)
return with(expression) { return with(expression) {
IrClassReferenceImpl(startOffset, endOffset, type, symbol, symbol.descriptor.defaultType) IrClassReferenceImpl(startOffset, endOffset, type, symbol, symbol.typeWithStarProjections)
} }
} }
override fun visitClass(declaration: IrClass): IrStatement { 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) { withLocal(declaration.thisReceiver?.symbol) {
return super.visitClass(declaration) return super.visitClass(declaration)
} }
@@ -229,7 +231,7 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
return with(expression) { 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) expression.transformChildrenVoid(this)
return with(expression) { 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 { override fun visitCall(expression: IrCall): IrExpression {
expression.replaceTypeArguments()
val symbol = expression.symbol.replace(SymbolTable::referenceFunction) ?: expression.symbol val symbol = expression.symbol.replace(SymbolTable::referenceFunction) ?: expression.symbol
val superQualifierSymbol = expression.superQualifierSymbol?.replaceOrSame(SymbolTable::referenceClass) val superQualifierSymbol = expression.superQualifierSymbol?.replaceOrSame(SymbolTable::referenceClass)
@@ -259,17 +263,21 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid() expression.transformChildrenVoid()
return with(expression) { return with(expression) {
IrCallImpl(startOffset, endOffset, symbol, descriptor, IrCallImpl(startOffset, endOffset, type, symbol, descriptor,
getTypeArgumentsMap(), typeArgumentsCount,
origin, superQualifierSymbol).also { origin, superQualifierSymbol).also {
it.copyArgumentsFrom(this) it.copyArgumentsFrom(this)
it.copyTypeArgumentsFrom(this)
} }
} }
} }
private fun IrMemberAccessExpression.getTypeArgumentsMap() = private fun IrMemberAccessExpression.replaceTypeArguments() {
descriptor.original.typeParameters.associate { it to getTypeArgumentOrDefault(it) } repeat(typeArgumentsCount) {
putTypeArgument(it, getTypeArgument(it)?.toKotlinType()?.let { context.ir.translateErased(it) })
}
}
private fun IrMemberAccessExpressionBase.copyArgumentsFrom(original: IrMemberAccessExpression) { private fun IrMemberAccessExpressionBase.copyArgumentsFrom(original: IrMemberAccessExpression) {
dispatchReceiver = original.dispatchReceiver dispatchReceiver = original.dispatchReceiver
@@ -284,37 +292,45 @@ private class IrUnboundSymbolReplacer(
return super.visitEnumConstructorCall(expression) return super.visitEnumConstructorCall(expression)
return with(expression) { return with(expression) {
IrEnumConstructorCallImpl(startOffset, endOffset, symbol, null).also { IrEnumConstructorCallImpl(startOffset, endOffset, expression.type, symbol, 0).also {
it.copyArgumentsFrom(this) it.copyArgumentsFrom(this)
} }
} }
} }
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.replaceTypeArguments()
val symbol = expression.symbol.replace(SymbolTable::referenceConstructor) ?: val symbol = expression.symbol.replace(SymbolTable::referenceConstructor) ?:
return super.visitDelegatingConstructorCall(expression) return super.visitDelegatingConstructorCall(expression)
expression.transformChildrenVoid() expression.transformChildrenVoid()
return with(expression) { return with(expression) {
IrDelegatingConstructorCallImpl(startOffset, endOffset, symbol, descriptor, getTypeArgumentsMap()).also { IrDelegatingConstructorCallImpl(startOffset, endOffset, type, symbol, descriptor, typeArgumentsCount).also {
it.copyArgumentsFrom(this) it.copyArgumentsFrom(this)
it.copyTypeArgumentsFrom(this)
} }
} }
} }
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression { override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
expression.replaceTypeArguments()
val symbol = expression.symbol.replace(SymbolTable::referenceFunction) ?: val symbol = expression.symbol.replace(SymbolTable::referenceFunction) ?:
return super.visitFunctionReference(expression) return super.visitFunctionReference(expression)
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
return with(expression) { return with(expression) {
IrFunctionReferenceImpl(startOffset, endOffset, type, symbol, descriptor, getTypeArgumentsMap()).also { IrFunctionReferenceImpl(startOffset, endOffset, type, symbol, descriptor, 0).also {
it.copyArgumentsFrom(this) it.copyArgumentsFrom(this)
it.copyTypeArgumentsFrom(this)
} }
} }
} }
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression { override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
expression.replaceTypeArguments()
val field = expression.field?.replaceOrSame(SymbolTable::referenceField) val field = expression.field?.replaceOrSame(SymbolTable::referenceField)
val getter = expression.getter?.replace(SymbolTable::referenceFunction) ?: expression.getter val getter = expression.getter?.replace(SymbolTable::referenceFunction) ?: expression.getter
val setter = expression.setter?.replace(SymbolTable::referenceFunction) ?: expression.setter val setter = expression.setter?.replace(SymbolTable::referenceFunction) ?: expression.setter
@@ -325,13 +341,14 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
return with(expression) { return with(expression) {
IrPropertyReferenceImpl(startOffset, endOffset, type, descriptor, IrPropertyReferenceImpl(startOffset, endOffset, type, descriptor, 0,
field, field,
getter, getter,
setter, setter,
getTypeArgumentsMap(), origin).also { origin).also {
it.copyArgumentsFrom(this) it.copyArgumentsFrom(this)
it.copyTypeArgumentsFrom(this)
} }
} }
} }
@@ -413,7 +430,19 @@ private class IrUnboundSymbolReplacer(
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
return with(expression) { 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 package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.backend.common.CommonBackendContext 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.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.KonanCompilationException import org.jetbrains.kotlin.backend.konan.KonanCompilationException
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName 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.*
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.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl 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.IrElement
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl 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.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingStrategy import org.jetbrains.kotlin.resolve.OverridingStrategy
import org.jetbrains.kotlin.resolve.OverridingUtil import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
import java.lang.reflect.Proxy import java.lang.reflect.Proxy
//TODO: delete file on next kotlin dependency update //TODO: delete file on next kotlin dependency update
@@ -63,25 +77,20 @@ internal fun IrFile.addTopLevelInitializer(expression: IrExpression) {
) )
val builtIns = fieldDescriptor.builtIns 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) fieldDescriptor.initialize(null, null)
val irField = IrFieldImpl( val irField = IrFieldImpl(
expression.startOffset, expression.endOffset, expression.startOffset, expression.endOffset,
IrDeclarationOrigin.DEFINED, fieldDescriptor IrDeclarationOrigin.DEFINED, fieldDescriptor, expression.type
) )
val initializer = IrTypeOperatorCallImpl( irField.initializer = IrExpressionBodyImpl(expression.startOffset, expression.endOffset, expression)
expression.startOffset, expression.endOffset, builtIns.unitType,
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, builtIns.unitType, expression
)
irField.initializer = IrExpressionBodyImpl(expression.startOffset, expression.endOffset, initializer)
this.addChild(irField) this.addChild(irField)
} }
fun IrClass.addFakeOverrides() { fun IrClass.addFakeOverrides(symbolTable: SymbolTable) {
val startOffset = this.startOffset val startOffset = this.startOffset
val endOffset = this.endOffset val endOffset = this.endOffset
@@ -90,17 +99,23 @@ fun IrClass.addFakeOverrides() {
.filterIsInstance<CallableMemberDescriptor>() .filterIsInstance<CallableMemberDescriptor>()
.filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE } .filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
.forEach { .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, startOffset, endOffset,
IrDeclarationOrigin.FAKE_OVERRIDE, this IrDeclarationOrigin.FAKE_OVERRIDE, this
).apply { ).apply {
createParameterDeclarations() returnType = symbolTable.translateErased(this@createFunction.returnType!!)
createParameterDeclarations(symbolTable)
} }
return when (descriptor) { 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( fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl(
innerStartOffset(this), innerEndOffset(this), innerStartOffset(this), innerEndOffset(this),
IrDeclarationOrigin.DEFINED, IrDeclarationOrigin.DEFINED,
this this, symbolTable.translateErased(this.type),
(this as? ValueParameterDescriptor)?.varargElementType?.let { symbolTable.translateErased(it) }
).also { ).also {
it.parent = this@createParameterDeclarations it.parent = this@createParameterDeclarations
} }
@@ -138,18 +155,84 @@ fun IrFunction.createParameterDeclarations() {
it it
).also { typeParameter -> ).also { typeParameter ->
typeParameter.parent = this 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) { fun IrSimpleFunction.setOverrides(symbolTable: SymbolTable) {
assert(this.overriddenSymbols.isEmpty()) assert(this.overriddenSymbols.isEmpty())
this.descriptor.overriddenDescriptors.mapTo(this.overriddenSymbols) { this.descriptor.overriddenDescriptors.mapTo(this.overriddenSymbols) {
symbolTable.referenceSimpleFunction(it.original) symbolTable.referenceSimpleFunction(it.original)
} }
this.typeParameters.forEach { it.setSupers(symbolTable) }
} }
fun IrClass.simpleFunctions(): List<IrSimpleFunction> = this.declarations.flatMap { fun IrClass.simpleFunctions(): List<IrSimpleFunction> = this.declarations.flatMap {
@@ -161,32 +244,56 @@ fun IrClass.simpleFunctions(): List<IrSimpleFunction> = this.declarations.flatMa
} }
fun IrClass.createParameterDeclarations() { fun IrClass.createParameterDeclarations() {
descriptor.thisAsReceiverParameter.let { thisReceiver = IrValueParameterImpl(
thisReceiver = IrValueParameterImpl( startOffset, endOffset,
innerStartOffset(it), innerEndOffset(it), IrDeclarationOrigin.INSTANCE_RECEIVER,
IrDeclarationOrigin.INSTANCE_RECEIVER, descriptor.thisAsReceiverParameter,
it this.symbol.typeWith(this.typeParameters.map { it.defaultType }),
).also { valueParameter -> null
valueParameter.parent = this ).also { valueParameter ->
} valueParameter.parent = this
} }
assert(typeParameters.isEmpty()) assert(typeParameters.isEmpty())
descriptor.declaredTypeParameters.mapTo(typeParameters) { assert(descriptor.declaredTypeParameters.isEmpty())
IrTypeParameterImpl(
innerStartOffset(it), innerEndOffset(it),
IrDeclarationOrigin.DEFINED,
it
).also { typeParameter ->
typeParameter.parent = this
}
}
} }
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.superDescriptors().toSet() == supers.map { it.descriptor }.toSet())
assert(this.superClasses.isEmpty()) assert(this.superTypes.isEmpty())
supers.mapTo(this.superClasses) { it.symbol } this.superTypes += superTypes
val superMembers = supers.flatMap { val superMembers = supers.flatMap {
it.simpleFunctions() it.simpleFunctions()
@@ -206,48 +313,38 @@ private fun IrClass.superDescriptors() =
this.descriptor.typeConstructor.supertypes.map { it.constructor.declarationDescriptor as ClassDescriptor } this.descriptor.typeConstructor.supertypes.map { it.constructor.declarationDescriptor as ClassDescriptor }
fun IrClass.setSuperSymbols(symbolTable: SymbolTable) { fun IrClass.setSuperSymbols(symbolTable: SymbolTable) {
assert(this.superClasses.isEmpty()) assert(this.superTypes.isEmpty())
this.superDescriptors().mapTo(this.superClasses) { symbolTable.referenceClass(it) } this.descriptor.typeConstructor.supertypes.mapTo(this.superTypes) { symbolTable.translateErased(it) }
this.simpleFunctions().forEach { this.simpleFunctions().forEach {
it.setOverrides(symbolTable) it.setOverrides(symbolTable)
} }
this.typeParameters.forEach {
it.setSupers(symbolTable)
}
} }
fun IrTypeParameter.setSupers(symbolTable: SymbolTable) { fun IrClass.setSuperSymbolsAndAddFakeOverrides(superTypes: List<IrType>) {
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>) {
val overriddenSuperMembers = this.declarations.map { it.descriptor } 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 { val unoverriddenSuperMembers = superTypes.map { it.getClass()!! }.flatMap {
it.declarations.mapNotNull { it.declarations.filter { it.descriptor !in overriddenSuperMembers }.mapNotNull {
when (it) { when (it) {
is IrSimpleFunction -> it.descriptor is IrSimpleFunction -> it.descriptor to it
is IrProperty -> it.descriptor is IrProperty -> it.descriptor to it
else -> null else -> null
} }
} }
} - overriddenSuperMembers }.toMap()
val irClass = this val irClass = this
val overridingStrategy = object : OverridingStrategy() { val overridingStrategy = object : OverridingStrategy() {
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) { 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) { 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( OverridingUtil.generateOverridesInFunctionGroup(
name, name,
members, members,
@@ -269,7 +366,7 @@ fun IrClass.setSuperSymbolsAndAddFakeOverrides(supers: List<IrClass>) {
) )
} }
this.setSuperSymbols(supers) this.setSuperSymbols(superTypes)
} }
private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int = private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int =
@@ -327,7 +424,7 @@ object CheckDeclarationParentsVisitor : IrElementVisitor<Unit, IrDeclarationPare
} }
override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclarationParent?) { override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclarationParent?) {
if (declaration !is IrVariable) { if (declaration !is IrVariable && declaration !is IrValueParameter && declaration !is IrTypeParameter) {
checkParent(declaration, data) checkParent(declaration, data)
} else { } else {
// Don't check IrVariable parent. // Don't check IrVariable parent.
@@ -376,7 +473,7 @@ internal fun KonanBackendContext.report(declaration: IrDeclaration, message: Str
} }
fun IrBuilderWithScope.irForceNotNull(expression: IrExpression): IrExpression { fun IrBuilderWithScope.irForceNotNull(expression: IrExpression): IrExpression {
if (!TypeUtils.isNullableType(expression.type)) { if (!expression.type.containsNull()) {
return expression return expression
} }
@@ -384,9 +481,263 @@ fun IrBuilderWithScope.irForceNotNull(expression: IrExpression): IrExpression {
val temporary = irTemporaryVar(expression) val temporary = irTemporaryVar(expression)
+irIfNull( +irIfNull(
expression.type, expression.type,
subject = irGet(temporary.symbol), subject = irGet(temporary),
thenPart = irThrowNpe(IrStatementOrigin.EXCLEXCL), 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 //For KT-6020
import kotlin.reflect.KProperty1 import kotlin.reflect.KProperty1
import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KMutableProperty1
@@ -47,7 +47,7 @@ class Worker(val id: WorkerId) {
* until all scheduled jobs processed, or terminate immediately. * until all scheduled jobs processed, or terminate immediately.
*/ */
fun requestTermination(processScheduledJobs: Boolean = true) = 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, * Schedule a job for further execution in the worker. Schedule is a two-phase operation,