Compiler symbolization part 3

This commit is contained in:
Igor Chevdar
2018-11-07 18:32:24 +03:00
parent e144321083
commit 99d32e0b8d
26 changed files with 1756 additions and 2488 deletions
@@ -6,16 +6,13 @@
package org.jetbrains.kotlin.backend.konan package org.jetbrains.kotlin.backend.konan
import llvm.* import llvm.*
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe
import org.jetbrains.kotlin.backend.konan.llvm.* import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
@@ -23,8 +20,9 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType 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.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -67,52 +65,41 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la
val parameterType = unboxedType val parameterType = unboxedType
val returnType = boxedType val returnType = boxedType
val descriptor = SimpleFunctionDescriptorImpl.create(
inlinedClass.descriptor,
Annotations.EMPTY,
Name.special("<box>"),
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE
)
val parameter = ValueParameterDescriptorImpl(
descriptor,
null,
0,
Annotations.EMPTY,
Name.identifier("value"),
parameterType.toKotlinType(),
false,
false,
false,
null,
SourceElement.NO_SOURCE
)
descriptor.initialize(
null,
null,
emptyList(),
listOf(parameter),
returnType.toKotlinType(),
Modality.FINAL,
Visibilities.PUBLIC
)
val startOffset = inlinedClass.startOffset val startOffset = inlinedClass.startOffset
val endOffset = inlinedClass.endOffset val endOffset = inlinedClass.endOffset
IrFunctionImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, descriptor, returnType).apply { val descriptor = WrappedSimpleFunctionDescriptor()
this.valueParameters.add(IrValueParameterImpl( IrFunctionImpl(
startOffset, startOffset, endOffset,
endOffset, IrDeclarationOrigin.DEFINED,
IrDeclarationOrigin.DEFINED, IrSimpleFunctionSymbolImpl(descriptor),
parameter, Name.special("<box>"),
parameterType, Visibilities.PUBLIC,
null Modality.FINAL,
)) returnType,
isInline = false,
this.parent = inlinedClass isExternal = false,
isTailrec = false,
isSuspend = false
).also { function ->
function.valueParameters.add(WrappedValueParameterDescriptor().let {
IrValueParameterImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
IrValueParameterSymbolImpl(it),
Name.identifier("value"),
index = 0,
varargElementType = null,
isCrossinline = false,
type = parameterType,
isNoinline = false
).apply {
it.bind(this)
parent = function
}
})
descriptor.bind(function)
function.parent = inlinedClass
} }
} }
@@ -128,52 +115,41 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context.
val parameterType = boxedType val parameterType = boxedType
val returnType = unboxedType val returnType = unboxedType
val descriptor = SimpleFunctionDescriptorImpl.create(
inlinedClass.descriptor,
Annotations.EMPTY,
Name.special("<unbox>"),
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE
)
val parameter = ValueParameterDescriptorImpl(
descriptor,
null,
0,
Annotations.EMPTY,
Name.identifier("value"),
parameterType.toKotlinType(),
false,
false,
false,
null,
SourceElement.NO_SOURCE
)
descriptor.initialize(
null,
null,
emptyList(),
listOf(parameter),
returnType.toKotlinType(),
Modality.FINAL,
Visibilities.PUBLIC
)
val startOffset = inlinedClass.startOffset val startOffset = inlinedClass.startOffset
val endOffset = inlinedClass.endOffset val endOffset = inlinedClass.endOffset
IrFunctionImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, descriptor, returnType).apply { val descriptor = WrappedSimpleFunctionDescriptor()
this.valueParameters.add(IrValueParameterImpl( IrFunctionImpl(
startOffset, startOffset, endOffset,
endOffset, IrDeclarationOrigin.DEFINED,
IrDeclarationOrigin.DEFINED, IrSimpleFunctionSymbolImpl(descriptor),
parameter, Name.special("<unbox>"),
parameterType, Visibilities.PUBLIC,
null Modality.FINAL,
)) returnType,
isInline = false,
this.parent = inlinedClass isExternal = false,
isTailrec = false,
isSuspend = false
).also { function ->
function.valueParameters.add(WrappedValueParameterDescriptor().let {
IrValueParameterImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
IrValueParameterSymbolImpl(it),
Name.identifier("value"),
index = 0,
varargElementType = null,
isCrossinline = false,
type = parameterType,
isNoinline = false
).apply {
it.bind(this)
parent = function
}
})
descriptor.bind(function)
function.parent = inlinedClass
} }
} }
@@ -8,6 +8,8 @@ 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.DumpIrTreeWithDescriptorsVisitor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescriptor
import org.jetbrains.kotlin.backend.common.validateIrModule import org.jetbrains.kotlin.backend.common.validateIrModule
import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.KonanIr import org.jetbrains.kotlin.backend.konan.ir.KonanIr
@@ -20,8 +22,6 @@ 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
import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
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.SourceManager import org.jetbrains.kotlin.ir.SourceManager
@@ -29,15 +29,13 @@ 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.declarations.impl.IrTypeParameterImpl import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.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.builtins.konan.KonanBuiltIns import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -51,6 +49,8 @@ import org.jetbrains.kotlin.serialization.deserialization.getName
import java.lang.System.out import java.lang.System.out
import kotlin.LazyThreadSafetyMode.PUBLICATION import kotlin.LazyThreadSafetyMode.PUBLICATION
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
/** /**
* Offset for synthetic elements created by lowerings and not attributable to other places in the source code. * Offset for synthetic elements created by lowerings and not attributable to other places in the source code.
@@ -97,7 +97,7 @@ internal class SpecialDeclarationsFactory(val context: Context) {
} }
fun getLoweredEnum(enumClass: IrClass): LoweredEnum { fun getLoweredEnum(enumClass: IrClass): LoweredEnum {
assert(enumClass.kind == ClassKind.ENUM_CLASS, { "Expected enum class but was: ${enumClass.descriptor}" }) assert(enumClass.kind == ClassKind.ENUM_CLASS) { "Expected enum class but was: ${enumClass.descriptor}" }
return loweredEnums.getOrPut(enumClass) { return loweredEnums.getOrPut(enumClass) {
enumSpecialDeclarationsFactory.createLoweredEnum(enumClass) enumSpecialDeclarationsFactory.createLoweredEnum(enumClass)
} }
@@ -125,143 +125,81 @@ internal class SpecialDeclarationsFactory(val context: Context) {
fun getBridge(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): IrSimpleFunction { fun getBridge(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): IrSimpleFunction {
val irFunction = overriddenFunctionDescriptor.descriptor val irFunction = overriddenFunctionDescriptor.descriptor
assert(overriddenFunctionDescriptor.needBridge, assert(overriddenFunctionDescriptor.needBridge) {
{ "Function ${irFunction.descriptor} is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor.descriptor}" }) "Function ${irFunction.descriptor} is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor.descriptor}"
}
val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections
return bridgesDescriptors.getOrPut(irFunction to bridgeDirections) { return bridgesDescriptors.getOrPut(irFunction to bridgeDirections) {
createBridge(irFunction, bridgeDirections) createBridge(irFunction, bridgeDirections)
} }
} }
private fun createBridge(function: IrFunction, bridgeDirections: BridgeDirections): IrFunctionImpl { private fun createBridge(function: IrSimpleFunction,
bridgeDirections: BridgeDirections) = WrappedSimpleFunctionDescriptor().let { descriptor ->
val startOffset = function.startOffset
val endOffset = function.endOffset
val returnType = when (bridgeDirections.array[0]) { val returnType = when (bridgeDirections.array[0]) {
BridgeDirection.TO_VALUE_TYPE, BridgeDirection.TO_VALUE_TYPE,
BridgeDirection.NOT_NEEDED -> function.returnType BridgeDirection.NOT_NEEDED -> function.returnType
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType
} }
IrFunctionImpl(
val dispatchReceiver = when (bridgeDirections.array[1]) { startOffset, endOffset,
BridgeDirection.TO_VALUE_TYPE -> function.dispatchReceiverParameter!!
BridgeDirection.NOT_NEEDED -> function.dispatchReceiverParameter
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyClass.owner.thisReceiver!!
}
val extensionReceiverType = when (bridgeDirections.array[2]) {
BridgeDirection.TO_VALUE_TYPE -> function.extensionReceiverParameter!!.type
BridgeDirection.NOT_NEEDED -> function.extensionReceiverParameter?.type
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType
}
val valueParameterTypes = function.valueParameters.mapIndexed { index, valueParameter ->
when (bridgeDirections.array[index + 3]) {
BridgeDirection.TO_VALUE_TYPE -> valueParameter.type
BridgeDirection.NOT_NEEDED -> valueParameter.type
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType
}
}
val bridgeDescriptor = createBridgeDescriptor(
function,
bridgeDirections,
returnType,
dispatchReceiver,
extensionReceiverType,
valueParameterTypes
)
val bridge = IrFunctionImpl(
function.startOffset,
function.endOffset,
DECLARATION_ORIGIN_BRIDGE_METHOD(function), DECLARATION_ORIGIN_BRIDGE_METHOD(function),
bridgeDescriptor, IrSimpleFunctionSymbolImpl(descriptor),
returnType "<bridge-$bridgeDirections>${function.functionName}".synthesizedName,
function.visibility,
function.modality,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = function.isSuspend,
returnType = returnType
).apply { ).apply {
this.parent = function.parent descriptor.bind(this)
} parent = function.parent
bridge.dispatchReceiverParameter = dispatchReceiver?.let { val dispatchReceiver = when (bridgeDirections.array[1]) {
IrValueParameterImpl( BridgeDirection.TO_VALUE_TYPE -> function.dispatchReceiverParameter!!
it.startOffset, BridgeDirection.NOT_NEEDED -> function.dispatchReceiverParameter
it.endOffset, BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyClass.owner.thisReceiver!!
IrDeclarationOrigin.DEFINED, }
it.descriptor,
it.type,
null
)
}
extensionReceiverType?.let { val extensionReceiver = when (bridgeDirections.array[2]) {
val extensionReceiverParameter = function.extensionReceiverParameter!! BridgeDirection.TO_VALUE_TYPE -> function.extensionReceiverParameter!!
bridge.extensionReceiverParameter = IrValueParameterImpl( BridgeDirection.NOT_NEEDED -> function.extensionReceiverParameter
extensionReceiverParameter.startOffset, BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyClass.owner.thisReceiver!!
extensionReceiverParameter.endOffset, }
extensionReceiverParameter.origin,
bridge.descriptor.extensionReceiverParameter!!,
it, null
)
}
function.valueParameters.mapIndexedTo(bridge.valueParameters) { index, valueParameter ->
val type = valueParameterTypes[index]
IrValueParameterImpl( val valueParameterTypes = function.valueParameters.mapIndexed { index, valueParameter ->
valueParameter.startOffset, when (bridgeDirections.array[index + 3]) {
valueParameter.endOffset, BridgeDirection.TO_VALUE_TYPE -> valueParameter.type
valueParameter.origin, BridgeDirection.NOT_NEEDED -> valueParameter.type
bridge.descriptor.valueParameters[index], BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType
type, valueParameter.varargElementType }
) }
}
function.typeParameters.mapTo(bridge.typeParameters) { dispatchReceiverParameter = dispatchReceiver?.copyTo(this)
IrTypeParameterImpl(it.startOffset, it.endOffset, it.origin, it.descriptor).apply { extensionReceiverParameter = extensionReceiver?.copyTo(this)
superTypes += it.superTypes function.valueParameters.mapTo(valueParameters) { it.copyTo(this, type = valueParameterTypes[it.index]) }
function.typeParameters.mapIndexedTo(typeParameters) { index, parameter ->
WrappedTypeParameterDescriptor().let {
IrTypeParameterImpl(
startOffset, endOffset,
origin,
IrTypeParameterSymbolImpl(it),
parameter.name,
index,
parameter.isReified,
parameter.variance
).apply {
it.bind(this)
superTypes += parameter.superTypes
}
}
} }
} }
return bridge
}
private fun createBridgeDescriptor(
function: IrFunction,
bridgeDirections: BridgeDirections,
returnType: IrType,
dispatchReceiverParameter: IrValueParameter?,
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 ->
ValueParameterDescriptorImpl(
containingDeclaration = valueParameterDescriptor.containingDeclaration,
original = null,
index = index,
annotations = Annotations.EMPTY,
name = valueParameterDescriptor.name,
outType = valueParameterTypes[index].toKotlinType(),
declaresDefaultValue = valueParameterDescriptor.declaresDefaultValue(),
isCrossinline = valueParameterDescriptor.isCrossinline,
isNoinline = valueParameterDescriptor.isNoinline,
varargElementType = valueParameterDescriptor.varargElementType,
source = SourceElement.NO_SOURCE)
}
bridgeDescriptor.initialize(
/* receiverParameterType = */ extensionReceiverType?.toKotlinType(),
/* dispatchReceiverParameter = */ dispatchReceiverParameter?.descriptor as ReceiverParameterDescriptor?,
/* typeParameters = */ descriptor.typeParameters,
/* unsubstitutedValueParameters = */ valueParameters,
/* unsubstitutedReturnType = */ returnType.toKotlinType(),
/* modality = */ descriptor.modality,
/* visibility = */ descriptor.visibility).apply {
isSuspend = descriptor.isSuspend
}
return bridgeDescriptor
} }
} }
@@ -5,143 +5,123 @@
package org.jetbrains.kotlin.backend.konan package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedFieldDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor 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.konan.descriptors.enumEntries import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.impl.*
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.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
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.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
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.receivers.ImplicitClassReceiver
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.*
internal object DECLARATION_ORIGIN_ENUM : internal object DECLARATION_ORIGIN_ENUM : IrDeclarationOriginImpl("ENUM")
IrDeclarationOriginImpl("ENUM")
internal data class LoweredEnum(val implObject: IrClass, internal data class LoweredEnum(val implObject: IrClass,
val valuesField: IrField, val valuesField: IrField,
val valuesGetter: IrSimpleFunction, val valuesGetter: IrSimpleFunction,
val itemGetterSymbol: IrSimpleFunctionSymbol, val itemGetterSymbol: IrSimpleFunctionSymbol,
val itemGetterDescriptor: FunctionDescriptor,
val entriesMap: Map<Name, Int>) val entriesMap: Map<Name, Int>)
internal class EnumSpecialDeclarationsFactory(val context: Context) { internal class EnumSpecialDeclarationsFactory(val context: Context) {
fun createLoweredEnum(enumClass: IrClass): LoweredEnum { private val symbols = context.ir.symbols
val enumClassDescriptor = enumClass.descriptor
fun createLoweredEnum(enumClass: IrClass): LoweredEnum {
val startOffset = enumClass.startOffset val startOffset = enumClass.startOffset
val endOffset = enumClass.endOffset val endOffset = enumClass.endOffset
val implObjectDescriptor = ClassDescriptorImpl(enumClassDescriptor, "OBJECT".synthesizedName, Modality.FINAL, val implObject = WrappedClassDescriptor().let {
ClassKind.OBJECT, listOf(context.builtIns.anyType), SourceElement.NO_SOURCE, false, LockBasedStorageManager.NO_LOCKS) IrClassImpl(
startOffset, endOffset,
val implObject = IrClassImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, implObjectDescriptor).apply { DECLARATION_ORIGIN_ENUM,
createParameterDeclarations() IrClassSymbolImpl(it),
"OBJECT".synthesizedName,
ClassKind.OBJECT,
Visibilities.PUBLIC,
Modality.FINAL,
isCompanion = false,
isInner = false,
isData = false,
isExternal = false,
isInline = false
).apply {
it.bind(this)
parent = enumClass
createParameterDeclarations()
}
} }
val valuesProperty = createEnumValuesField(enumClassDescriptor, implObjectDescriptor) val valuesType = symbols.array.typeWith(enumClass.defaultType)
val valuesType = context.ir.symbols.array.typeWith(enumClass.defaultType) val valuesField = WrappedFieldDescriptor().let {
val valuesField = IrFieldImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, valuesProperty, valuesType) IrFieldImpl(
startOffset, endOffset,
val valuesGetterDescriptor = createValuesGetterDescriptor(enumClassDescriptor, implObjectDescriptor) DECLARATION_ORIGIN_ENUM,
val valuesGetter = IrFunctionImpl( IrFieldSymbolImpl(it),
startOffset, endOffset, "VALUES".synthesizedName,
DECLARATION_ORIGIN_ENUM, valuesType,
valuesGetterDescriptor, Visibilities.PRIVATE,
valuesType isFinal = true,
).also { isExternal = false,
it.parent = implObject isStatic = false
it.createDispatchReceiverParameter() ).apply {
it.bind(this)
parent = implObject
}
} }
val memberScope = MemberScope.Empty val valuesGetter = WrappedSimpleFunctionDescriptor().let {
IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrSimpleFunctionSymbolImpl(it),
"get-VALUES".synthesizedName,
Visibilities.PUBLIC,
Modality.FINAL,
valuesType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false
).apply {
it.bind(this)
parent = implObject
}
}
val constructorOfAny = context.irBuiltIns.anyClass.owner.constructors.first() val constructorOfAny = context.irBuiltIns.anyClass.owner.constructors.first()
// TODO: why primary? implObject.addSimpleDelegatingConstructor(
val constructor = implObject.addSimpleDelegatingConstructor(
constructorOfAny, constructorOfAny,
context.irBuiltIns, context.irBuiltIns,
DECLARATION_ORIGIN_ENUM, true // TODO: why primary?
true
) )
val constructorDescriptor = constructor.descriptor
implObjectDescriptor.initialize(memberScope, setOf(constructorDescriptor), constructorDescriptor) implObject.superTypes += context.irBuiltIns.anyType
implObject.setSuperSymbolsAndAddFakeOverrides(listOf(context.irBuiltIns.anyType)) implObject.addFakeOverrides()
implObject.parent = enumClass
valuesField.parent = implObject
val (itemGetterSymbol, itemGetterDescriptor) = getEnumItemGetter(enumClassDescriptor) val itemGetterSymbol = symbols.array.functions.single { it.descriptor.name == Name.identifier("get") }
val enumEntriesMap = enumClass.declarations
.filterIsInstance<IrEnumEntry>()
.sortedBy { it.name }
.withIndex()
.associate { it.value.name to it.index }
.toMap()
return LoweredEnum( return LoweredEnum(
implObject, implObject,
valuesField, valuesField,
valuesGetter, valuesGetter,
itemGetterSymbol, itemGetterDescriptor, itemGetterSymbol,
createEnumEntriesMap(enumClassDescriptor)) enumEntriesMap)
} }
private fun createValuesGetterDescriptor(enumClassDescriptor: ClassDescriptor, implObjectDescriptor: ClassDescriptor)
: FunctionDescriptor {
val returnType = genericArrayType.defaultType.replace(listOf(TypeProjectionImpl(enumClassDescriptor.defaultType)))
val result = SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ implObjectDescriptor,
/* annotations = */ Annotations.EMPTY,
/* name = */ "get-VALUES".synthesizedName,
/* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED,
/* source = */ SourceElement.NO_SOURCE)
result.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ null,
/* typeParameters = */ listOf(),
/* unsubstitutedValueParameters = */ listOf(),
/* unsubstitutedReturnType = */ returnType,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PUBLIC)
return result
}
private fun createEnumValuesField(enumClassDescriptor: ClassDescriptor, implObjectDescriptor: ClassDescriptor): PropertyDescriptor {
val valuesArrayType = context.builtIns.getArrayType(Variance.INVARIANT, enumClassDescriptor.defaultType)
val receiver = ReceiverParameterDescriptorImpl(
implObjectDescriptor,
ImplicitClassReceiver(implObjectDescriptor, null),
Annotations.EMPTY
)
return PropertyDescriptorImpl.create(implObjectDescriptor, Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC,
false, "VALUES".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE,
false, false, false, false, false, false).apply {
this.setType(valuesArrayType, emptyList(), receiver, null)
this.initialize(null, null)
}
}
private val genericArrayType = context.ir.symbols.array.descriptor
private fun getEnumItemGetter(enumClassDescriptor: ClassDescriptor): Pair<IrSimpleFunctionSymbol, FunctionDescriptor> {
val getter = context.ir.symbols.array.functions.single { it.descriptor.name == Name.identifier("get") }
val typeParameterT = genericArrayType.declaredTypeParameters[0]
val enumClassType = enumClassDescriptor.defaultType
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumClassType)))
return getter to getter.descriptor.substitute(typeSubstitutor)!!
}
private fun createEnumEntriesMap(enumClassDescriptor: ClassDescriptor): Map<Name, Int> {
val map = mutableMapOf<Name, Int>()
enumClassDescriptor.enumEntries
.sortedBy { it.name }
.forEachIndexed { index, entry -> map.put(entry.name, index) }
return map
}
} }
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.backend.konan.lower.ExpectDeclarationsRemoving
import org.jetbrains.kotlin.backend.konan.lower.FinallyBlocksLowering import org.jetbrains.kotlin.backend.konan.lower.FinallyBlocksLowering
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.SharedVariablesLowering
import org.jetbrains.kotlin.backend.konan.lower.VarargInjectionLowering import org.jetbrains.kotlin.backend.konan.lower.VarargInjectionLowering
import org.jetbrains.kotlin.backend.konan.lower.loops.ForLoopsLowering import org.jetbrains.kotlin.backend.konan.lower.loops.ForLoopsLowering
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
@@ -65,10 +64,6 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager)
irModule.files.forEach(InteropLoweringPart1(context)::lower) irModule.files.forEach(InteropLoweringPart1(context)::lower)
} }
phaser.phase(KonanPhase.LOWER_LATEINIT) {
irModule.files.forEach(LateinitLowering(context)::lower)
}
val symbolTable = context.ir.symbols.symbolTable val symbolTable = context.ir.symbols.symbolTable
do { do {
@@ -82,6 +77,9 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager)
} }
private fun lowerFile(irFile: IrFile, phaser: PhaseManager) { private fun lowerFile(irFile: IrFile, phaser: PhaseManager) {
phaser.phase(KonanPhase.LOWER_LATEINIT) {
LateinitLowering(context).lower(irFile)
}
phaser.phase(KonanPhase.LOWER_STRING_CONCAT) { phaser.phase(KonanPhase.LOWER_STRING_CONCAT) {
StringConcatenationLowering(context).lower(irFile) StringConcatenationLowering(context).lower(irFile)
} }
@@ -94,13 +92,6 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager)
phaser.phase(KonanPhase.LOWER_ENUMS) { phaser.phase(KonanPhase.LOWER_ENUMS) {
EnumClassLowering(context).run(irFile) EnumClassLowering(context).run(irFile)
} }
/**
* TODO: this is workaround for issue of unitialized parents in IrDeclaration,
* the last one detected in [EnumClassLowering]. The issue appears in [DefaultArgumentStubGenerator].
*/
irFile.patchDeclarationParents()
phaser.phase(KonanPhase.LOWER_INITIALIZERS) { phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
InitializersLowering(context).runOnFilePostfix(irFile) InitializersLowering(context).runOnFilePostfix(irFile)
} }
@@ -113,12 +104,6 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager)
phaser.phase(KonanPhase.LOWER_CALLABLES) { phaser.phase(KonanPhase.LOWER_CALLABLES) {
CallableReferenceLowering(context).lower(irFile) CallableReferenceLowering(context).lower(irFile)
} }
/**
* TODO: this is workaround for issue of unitialized parents in IrDeclaration,
* the last one detected in [CallableReferenceLowering]. The issue appears in [LocalDeclarationsLowering].
*/
irFile.patchDeclarationParents()
phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) { phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) {
LocalDeclarationsLowering(context).runOnFilePostfix(irFile) LocalDeclarationsLowering(context).runOnFilePostfix(irFile)
} }
@@ -14,7 +14,6 @@ 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
import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.config.coroutinesIntrinsicsPackageFqName import org.jetbrains.kotlin.config.coroutinesIntrinsicsPackageFqName
import org.jetbrains.kotlin.config.coroutinesPackageFqName import org.jetbrains.kotlin.config.coroutinesPackageFqName
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
@@ -370,6 +369,9 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
val getContinuation = symbolTable.referenceSimpleFunction( val getContinuation = symbolTable.referenceSimpleFunction(
context.getInternalFunctions("getContinuation").single()) context.getInternalFunctions("getContinuation").single())
val returnIfSuspended = symbolTable.referenceSimpleFunction(
context.getInternalFunctions("returnIfSuspended").single())
val konanSuspendCoroutineUninterceptedOrReturn = symbolTable.referenceSimpleFunction( val konanSuspendCoroutineUninterceptedOrReturn = symbolTable.referenceSimpleFunction(
context.getInternalFunctions("suspendCoroutineUninterceptedOrReturn").single()) context.getInternalFunctions("suspendCoroutineUninterceptedOrReturn").single())
@@ -435,10 +437,14 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
} && !it.isExpect } && !it.isExpect
} }
val isInitializedGetterDescriptor = isInitializedPropertyDescriptor.getter!! val isInitializedGetter = symbolTable.referenceSimpleFunction(isInitializedPropertyDescriptor.getter!!)
val kFunctionImpl = symbolTable.referenceClass(context.reflectionTypes.kFunctionImpl) val kFunctionImpl = symbolTable.referenceClass(context.reflectionTypes.kFunctionImpl)
val kMutableProperty0 = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty0)
val kMutableProperty1 = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty1)
val kMutableProperty2 = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty2)
val kProperty0Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty0Impl) val kProperty0Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty0Impl)
val kProperty1Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty1Impl) val kProperty1Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty1Impl)
val kProperty2Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty2Impl) val kProperty2Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty2Impl)
@@ -502,32 +508,6 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
val topLevelSuite = getKonanTestClass("TopLevelSuite") val topLevelSuite = getKonanTestClass("TopLevelSuite")
val testFunctionKind = getKonanTestClass("TestFunctionKind") val testFunctionKind = getKonanTestClass("TestFunctionKind")
val baseClassSuiteConstructor = baseClassSuite.descriptor.constructors.single {
it.valueParameters.size == 2 &&
KotlinBuiltIns.isString(it.valueParameters[0].type) && // name: String
KotlinBuiltIns.isBoolean(it.valueParameters[1].type) // ignored: Boolean
}
val topLevelSuiteConstructor = symbolTable.referenceConstructor(topLevelSuite.descriptor.constructors.single {
it.valueParameters.size == 1 &&
KotlinBuiltIns.isString(it.valueParameters[0].type) // name: String
})
val topLevelSuiteRegisterFunction =
getFunction(Name.identifier("registerFunction"), topLevelSuite.descriptor.defaultType) {
it.valueParameters.size == 2 &&
it.valueParameters[0].type == testFunctionKind.descriptor.defaultType && // kind: TestFunctionKind
it.valueParameters[1].type.isFunctionType // function: () -> Unit
}
val topLevelSuiteRegisterTestCase =
getFunction(Name.identifier("registerTestCase"), topLevelSuite.descriptor.defaultType) {
it.valueParameters.size == 3 &&
KotlinBuiltIns.isString(it.valueParameters[0].type) && // name: String
it.valueParameters[1].type.isFunctionType && // function: () -> Unit
KotlinBuiltIns.isBoolean(it.valueParameters[2].type) // ignored: Boolean
}
private val testFunctionKindCache = mutableMapOf<TestProcessor.FunctionKind, IrEnumEntrySymbol>() private val testFunctionKindCache = mutableMapOf<TestProcessor.FunctionKind, IrEnumEntrySymbol>()
fun getTestFunctionKind(kind: TestProcessor.FunctionKind): IrEnumEntrySymbol = testFunctionKindCache.getOrPut(kind) { fun getTestFunctionKind(kind: TestProcessor.FunctionKind): IrEnumEntrySymbol = testFunctionKindCache.getOrPut(kind) {
symbolTable.referenceEnumEntry(testFunctionKind.descriptor.unsubstitutedMemberScope.getContributedClassifier( symbolTable.referenceEnumEntry(testFunctionKind.descriptor.unsubstitutedMemberScope.getContributedClassifier(
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.AbstractValueUsageTransformer import org.jetbrains.kotlin.backend.common.AbstractValueUsageTransformer
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.atMostOne import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
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
@@ -15,9 +17,7 @@ import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass
import org.jetbrains.kotlin.backend.konan.irasdescriptors.containsNull import org.jetbrains.kotlin.backend.konan.irasdescriptors.containsNull
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isOverridable import org.jetbrains.kotlin.backend.konan.irasdescriptors.isOverridable
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isSuspend import org.jetbrains.kotlin.backend.konan.irasdescriptors.isSuspend
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
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.*
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
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
@@ -67,17 +68,17 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
} }
} }
private var currentFunctionDescriptor: IrFunction? = null private var currentFunction: IrFunction? = null
override fun visitFunction(declaration: IrFunction): IrStatement { override fun visitFunction(declaration: IrFunction): IrStatement {
currentFunctionDescriptor = declaration currentFunction = declaration
val result = super.visitFunction(declaration) val result = super.visitFunction(declaration)
currentFunctionDescriptor = null currentFunction = null
return result return result
} }
override fun IrExpression.useAsReturnValue(returnTarget: IrReturnTargetSymbol): IrExpression = when (returnTarget) { override fun IrExpression.useAsReturnValue(returnTarget: IrReturnTargetSymbol): IrExpression = when (returnTarget) {
is IrSimpleFunctionSymbol -> if (returnTarget.owner.isSuspend && returnTarget == currentFunctionDescriptor?.symbol) { is IrSimpleFunctionSymbol -> if (returnTarget.owner.isSuspend && returnTarget == currentFunction?.symbol) {
this.useAs(irBuiltIns.anyNType) this.useAs(irBuiltIns.anyNType)
} else { } else {
this.useAs(returnTarget.owner.returnType) this.useAs(returnTarget.owner.returnType)
@@ -389,6 +390,7 @@ private class InlineClassTransformer(private val context: Context) : IrBuildingT
} }
(irConstructor.body as IrBlockBody).statements.forEach { statement -> (irConstructor.body as IrBlockBody).statements.forEach { statement ->
statement.setDeclarationsParent(result)
+statement.transform(object : IrElementTransformerVoid() { +statement.transform(object : IrElementTransformerVoid() {
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.transformChildrenVoid() expression.transformChildrenVoid()
@@ -435,38 +437,22 @@ private val Context.getLoweredInlineClassConstructor: (IrConstructor) -> IrSimpl
require(irConstructor.constructedClass.isInlined()) require(irConstructor.constructedClass.isInlined())
require(!irConstructor.isPrimary) require(!irConstructor.isPrimary)
val descriptor = SimpleFunctionDescriptorImpl.create( val descriptor = WrappedSimpleFunctionDescriptor(irConstructor.descriptor.annotations, irConstructor.descriptor.source)
irConstructor.descriptor.containingDeclaration,
irConstructor.descriptor.annotations,
Name.special("<constructor>"),
CallableMemberDescriptor.Kind.SYNTHESIZED,
irConstructor.descriptor.source
)
val parameterDescriptors = irConstructor.descriptor.valueParameters.map {
it.copy(descriptor, it.name, it.index)
}
descriptor.initialize(
null,
null,
emptyList(),
parameterDescriptors,
irConstructor.descriptor.returnType,
Modality.FINAL,
irConstructor.visibility
)
IrFunctionImpl( IrFunctionImpl(
irConstructor.startOffset, irConstructor.startOffset, irConstructor.endOffset,
irConstructor.endOffset,
IrDeclarationOrigin.DEFINED, IrDeclarationOrigin.DEFINED,
descriptor, IrSimpleFunctionSymbolImpl(descriptor),
irConstructor.returnType Name.special("<constructor>"),
irConstructor.visibility,
Modality.FINAL,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false,
returnType = irConstructor.returnType
).apply { ).apply {
descriptor.bind(this)
parent = irConstructor.parent parent = irConstructor.parent
irConstructor.valueParameters.mapTo(this.valueParameters) { irConstructor.valueParameters.mapTo(valueParameters) { it.copyTo(this) }
it.copy(this.descriptor.valueParameters[it.index])
}
} }
} }
@@ -7,15 +7,14 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
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.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.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
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.*
@@ -26,6 +25,8 @@ 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.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isNullableAny import org.jetbrains.kotlin.ir.types.isNullableAny
import org.jetbrains.kotlin.ir.util.simpleFunctions import org.jetbrains.kotlin.ir.util.simpleFunctions
@@ -64,54 +65,41 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
val job = expression.getValueArgument(3) as IrFunctionReference val job = expression.getValueArgument(3) as IrFunctionReference
val jobFunction = (job.symbol as IrSimpleFunctionSymbol).owner val jobFunction = (job.symbol as IrSimpleFunctionSymbol).owner
val jobDescriptor = job.descriptor
val arg = jobDescriptor.valueParameters[0]
if (!::runtimeJobFunction.isInitialized) { if (!::runtimeJobFunction.isInitialized) {
val runtimeJobDescriptor = SimpleFunctionDescriptorImpl.create( val arg = jobFunction.valueParameters[0]
jobDescriptor.containingDeclaration, val startOffset = jobFunction.startOffset
jobDescriptor.annotations, val endOffset = jobFunction.endOffset
jobDescriptor.name, runtimeJobFunction = WrappedSimpleFunctionDescriptor().let {
jobDescriptor.kind, IrFunctionImpl(
jobDescriptor.source startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(it),
jobFunction.name,
jobFunction.visibility,
jobFunction.modality,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false,
returnType = context.irBuiltIns.anyNType
).apply { ).apply {
initialize( it.bind(this)
null, }
null,
emptyList(),
listOf(ValueParameterDescriptorImpl(
containingDeclaration = this,
original = null,
index = 0,
annotations = Annotations.EMPTY,
name = arg.name,
outType = nullableAnyType,
declaresDefaultValue = arg.declaresDefaultValue(),
isCrossinline = arg.isCrossinline,
isNoinline = arg.isNoinline,
varargElementType = arg.varargElementType,
source = arg.source
)),
nullableAnyType,
jobDescriptor.modality,
jobDescriptor.visibility
)
} }
runtimeJobFunction = IrFunctionImpl( runtimeJobFunction.valueParameters += WrappedValueParameterDescriptor().let {
jobFunction.startOffset, IrValueParameterImpl(
jobFunction.endOffset, startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
runtimeJobDescriptor,
context.irBuiltIns.anyNType
).also {
it.valueParameters += IrValueParameterImpl(
it.startOffset,
it.endOffset,
IrDeclarationOrigin.DEFINED, IrDeclarationOrigin.DEFINED,
it.descriptor.valueParameters.single(), IrValueParameterSymbolImpl(it),
context.irBuiltIns.anyNType, arg.name,
null arg.index,
) type = context.irBuiltIns.anyNType,
varargElementType = null,
isCrossinline = arg.isCrossinline,
isNoinline = arg.isNoinline
).apply { it.bind(this) }
} }
} }
val overriddenJobDescriptor = OverriddenFunctionDescriptor(jobFunction, runtimeJobFunction) val overriddenJobDescriptor = OverriddenFunctionDescriptor(jobFunction, runtimeJobFunction)
@@ -7,6 +7,8 @@ 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.*
import org.jetbrains.kotlin.backend.common.ir.copyTo
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
@@ -15,14 +17,7 @@ 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.isFunctionOrKFunctionType
import org.jetbrains.kotlin.backend.konan.llvm.functionName import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
import org.jetbrains.kotlin.descriptors.* 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.ClassDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.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.*
@@ -32,9 +27,8 @@ 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.* 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.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.* 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.* import org.jetbrains.kotlin.ir.types.*
@@ -42,8 +36,6 @@ 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.storage.LockBasedStorageManager
internal class CallableReferenceLowering(val context: Context): FileLoweringPass { internal class CallableReferenceLowering(val context: Context): FileLoweringPass {
@@ -108,12 +100,9 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
} }
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().last() val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().last()
val loweredFunctionReference = FunctionReferenceBuilder( val loweredFunctionReference = FunctionReferenceBuilder(parent, expression).build()
currentScope!!.scope.scopeOwner, val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol,
parent, expression.startOffset, expression.endOffset)
expression
).build()
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
return irBuilder.irBlock(expression) { return irBuilder.irBlock(expression) {
+loweredFunctionReference.functionReferenceClass +loweredFunctionReference.functionReferenceClass
+irCall(loweredFunctionReference.functionReferenceConstructor.symbol).apply { +irCall(loweredFunctionReference.functionReferenceConstructor.symbol).apply {
@@ -138,34 +127,64 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
private val getContinuationSymbol = symbols.getContinuation private val getContinuationSymbol = symbols.getContinuation
private inner class FunctionReferenceBuilder(val containingDeclaration: DeclarationDescriptor, private inner class FunctionReferenceBuilder(val parent: IrDeclarationParent,
val parent: IrDeclarationParent,
val functionReference: IrFunctionReference) { val functionReference: IrFunctionReference) {
private val functionDescriptor = functionReference.descriptor.original private val startOffset = functionReference.startOffset
private val irFunction = functionReference.symbol.owner private val endOffset = functionReference.endOffset
private val functionParameters = irFunction.explicitParameters private val referencedFunction = functionReference.symbol.owner
private val functionParameters = referencedFunction.explicitParameters
private val boundFunctionParameters = functionReference.getArgumentsWithIr().map { it.first } private val boundFunctionParameters = functionReference.getArgumentsWithIr().map { it.first }
private val unboundFunctionParameters = functionParameters - boundFunctionParameters private val unboundFunctionParameters = functionParameters - boundFunctionParameters
private lateinit var functionReferenceClassDescriptor: ClassDescriptorImpl private val typeArgumentsMap = referencedFunction.typeParameters.associate { typeParam ->
private lateinit var functionReferenceClass: IrClassImpl typeParam.symbol to functionReference.getTypeArgument(typeParam.index)!!
private lateinit var functionReferenceThis: IrValueParameterSymbol }
private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrField>
private val functionReferenceClass = WrappedClassDescriptor().let {
IrClassImpl(
startOffset,endOffset,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
IrClassSymbolImpl(it),
"${referencedFunction.name}\$FUNCTION_REFERENCE\$${context.functionReferenceCount++}".synthesizedName,
ClassKind.CLASS,
Visibilities.PRIVATE,
Modality.FINAL,
isCompanion = false,
isInner = false,
isData = false,
isExternal = false,
isInline = false
).apply {
it.bind(this)
parent = this@FunctionReferenceBuilder.parent
createParameterDeclarations()
}
}
private val functionReferenceThis = functionReferenceClass.thisReceiver!!
private val argumentToPropertiesMap = boundFunctionParameters.associate {
it to createField(
startOffset, endOffset,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
it.type,
it.name,
isMutable = false,
owner = functionReferenceClass
)
}
private val kFunctionImplSymbol = symbols.kFunctionImpl private val kFunctionImplSymbol = symbols.kFunctionImpl
private val kFunctionImplConstructorSymbol = kFunctionImplSymbol.constructors.single() private val kFunctionImplConstructorSymbol = kFunctionImplSymbol.constructors.single()
val isKFunction = functionReference.type.classifierOrNull?.descriptor val isKFunction = functionReference.type.isKFunction()
?.getFunctionalClassKind() == FunctionClassDescriptor.Kind.KFunction
fun build(): BuiltFunctionReference { fun build(): BuiltFunctionReference {
val startOffset = functionReference.startOffset
val endOffset = functionReference.endOffset
val superClassType = if (isKFunction) { val superClassType = if (isKFunction) {
kFunctionImplSymbol.typeWith(irFunction.returnType) kFunctionImplSymbol.typeWith(referencedFunction.returnType)
} else { } else {
irBuiltIns.anyType irBuiltIns.anyType
} }
@@ -181,7 +200,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
} }
val functionParameterTypes = unboundFunctionParameters.map { it.type } val functionParameterTypes = unboundFunctionParameters.map { it.type }
val functionClassTypeParameters = functionParameterTypes + irFunction.returnType val functionClassTypeParameters = functionParameterTypes + referencedFunction.returnType
superTypes += functionIrClass.symbol.typeWith(functionClassTypeParameters) superTypes += functionIrClass.symbol.typeWith(functionClassTypeParameters)
var suspendFunctionIrClass: IrClass? = null var suspendFunctionIrClass: IrClass? = null
@@ -190,136 +209,65 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
lastParameterType as IrSimpleType lastParameterType as IrSimpleType
// If the last parameter is Continuation<> inherit from SuspendFunction. // If the last parameter is Continuation<> inherit from SuspendFunction.
suspendFunctionIrClass = symbols.suspendFunctions[numberOfParameters - 1].owner suspendFunctionIrClass = symbols.suspendFunctions[numberOfParameters - 1].owner
var suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) + val suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) +
(lastParameterType.arguments.single().typeOrNull ?: irBuiltIns.anyNType) (lastParameterType.arguments.single().typeOrNull ?: irBuiltIns.anyNType)
superTypes += suspendFunctionIrClass.symbol.typeWith(suspendFunctionClassTypeParameters) superTypes += suspendFunctionIrClass.symbol.typeWith(suspendFunctionClassTypeParameters)
} }
functionReferenceClassDescriptor = object : ClassDescriptorImpl( val constructor = buildConstructor()
/* containingDeclaration = */ containingDeclaration, buildInvokeMethod(functionIrClass.simpleFunctions().single { it.name.asString() == "invoke" })
/* name = */ "${functionDescriptor.name}\$FUNCTION_REFERENCE\$${context.functionReferenceCount++}".synthesizedName, suspendFunctionIrClass?.let { buildInvokeMethod(it.simpleFunctions().single { it.name.asString() == "invoke" }) }
/* modality = */ Modality.FINAL,
/* kind = */ ClassKind.CLASS,
/* superTypes = */ superTypes.map { it.toKotlinType() },
/* source = */ SourceElement.NO_SOURCE,
/* isExternal = */ false,
/* storageManager = */ LockBasedStorageManager.NO_LOCKS
) {
override fun getVisibility() = Visibilities.PRIVATE
}
functionReferenceClass = IrClassImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
descriptor = functionReferenceClassDescriptor
)
functionReferenceClass.parent = this.parent
functionReferenceClass.superTypes += superTypes
functionReferenceClass.addFakeOverrides()
val constructorBuilder = createConstructorBuilder() return BuiltFunctionReference(functionReferenceClass, constructor)
val invokeFunctionSymbol =
functionIrClass.simpleFunctions().single { it.name.asString() == "invoke" }.symbol
val invokeMethodBuilder = createInvokeMethodBuilder(invokeFunctionSymbol, functionReferenceClass)
var suspendInvokeMethodBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>? = null
if (suspendFunctionIrClass != null) {
val suspendInvokeFunctionSymbol =
suspendFunctionIrClass.simpleFunctions().single { it.name.asString() == "invoke" }.symbol
suspendInvokeMethodBuilder = createInvokeMethodBuilder(suspendInvokeFunctionSymbol, functionReferenceClass)
}
val memberScope = stub<MemberScope>("callable reference class")
functionReferenceClassDescriptor.initialize(
memberScope, setOf(constructorBuilder.symbol.descriptor), null)
functionReferenceClass.createParameterDeclarations()
functionReferenceThis = functionReferenceClass.thisReceiver!!.symbol
constructorBuilder.initialize()
functionReferenceClass.addChild(constructorBuilder.ir)
invokeMethodBuilder.initialize()
functionReferenceClass.addChild(invokeMethodBuilder.ir)
suspendInvokeMethodBuilder?.let {
it.initialize()
functionReferenceClass.addChild(it.ir)
}
functionReferenceClass.setSuperSymbolsAndAddFakeOverrides(superTypes)
return BuiltFunctionReference(functionReferenceClass, constructorBuilder.ir)
} }
private fun createConstructorBuilder() private fun buildConstructor() = WrappedClassConstructorDescriptor().let {
= object : SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() { IrConstructorImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
IrConstructorSymbolImpl(it),
Name.special("<init>"),
Visibilities.PUBLIC,
functionReferenceClass.defaultType,
isInline = false,
isExternal = false,
isPrimary = true
).apply {
it.bind(this)
parent = functionReferenceClass
functionReferenceClass.declarations += this
override fun buildSymbol() = IrConstructorSymbolImpl( boundFunctionParameters.mapIndexedTo(valueParameters) { index, parameter ->
ClassConstructorDescriptorImpl.create( parameter.copyTo(this, DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, index,
/* containingDeclaration = */ functionReferenceClassDescriptor, type = parameter.type.substitute(typeArgumentsMap))
/* annotations = */ Annotations.EMPTY,
/* isPrimary = */ false,
/* source = */ SourceElement.NO_SOURCE
)
)
override fun doInitialize() {
val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
val constructorParameters = boundFunctionParameters.mapIndexed { index, parameter ->
parameter.descriptor.copyAsValueParameter(descriptor, index)
}
descriptor.initialize(constructorParameters, Visibilities.PUBLIC)
descriptor.returnType = functionReferenceClassDescriptor.defaultType
}
override fun buildIr(): IrConstructor {
argumentToPropertiesMap = boundFunctionParameters.associate {
it.descriptor to buildField(it.name, it.type, false)
} }
val startOffset = functionReference.startOffset body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody {
val endOffset = functionReference.endOffset if (!isKFunction)
return IrConstructorImpl( +irDelegatingConstructorCall(irBuiltIns.anyClass.owner.constructors.single())
startOffset = startOffset, else +irDelegatingConstructorCall(kFunctionImplConstructorSymbol.owner).apply {
endOffset = endOffset, val stringType = irBuiltIns.stringType
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, val name = IrConstImpl(startOffset, endOffset, stringType,
symbol = symbol, IrConstKind.String, referencedFunction.name.asString())
returnType = functionReferenceClass.defaultType putValueArgument(0, name)
).apply { val fqName = IrConstImpl(startOffset, endOffset, stringType, IrConstKind.String,
(functionReference.symbol.owner).fullName)
val irBuilder = context.createIrBuilder(this.symbol, startOffset, endOffset) putValueArgument(1, fqName)
val bound = IrConstImpl.boolean(startOffset, endOffset, context.irBuiltIns.booleanType,
boundFunctionParameters.mapIndexedTo(this.valueParameters) { index, parameter -> boundFunctionParameters.isNotEmpty())
parameter.copy(descriptor.valueParameters[index]) putValueArgument(2, bound)
val needReceiver = boundFunctionParameters.singleOrNull()?.descriptor is ReceiverParameterDescriptor
val receiver = if (needReceiver) irGet(valueParameters.single()) else irNull()
putValueArgument(3, receiver)
putValueArgument(4, irKType(this@CallableReferenceLowering.context, referencedFunction.returnType))
} }
+IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, irBuiltIns.unitType)
body = irBuilder.irBlockBody { // Save all arguments to fields.
if (!isKFunction) +irDelegatingConstructorCall(irBuiltIns.anyClass.owner.constructors.single()) boundFunctionParameters.forEachIndexed { index, parameter ->
else +IrDelegatingConstructorCallImpl(startOffset, endOffset, +irSetField(irGet(functionReferenceThis), argumentToPropertiesMap[parameter]!!, irGet(valueParameters[index]))
context.irBuiltIns.unitType,
kFunctionImplConstructorSymbol, kFunctionImplConstructorSymbol.descriptor, 0).apply {
val stringType = irBuiltIns.stringType
val name = IrConstImpl(startOffset, endOffset, stringType,
IrConstKind.String, functionDescriptor.name.asString())
putValueArgument(0, name)
val fqName = IrConstImpl(startOffset, endOffset, stringType, IrConstKind.String,
(functionReference.symbol.owner).fullName)
putValueArgument(1, fqName)
val bound = IrConstImpl.boolean(startOffset, endOffset, context.irBuiltIns.booleanType,
boundFunctionParameters.isNotEmpty())
putValueArgument(2, bound)
val needReceiver = boundFunctionParameters.singleOrNull()?.descriptor is ReceiverParameterDescriptor
val receiver = if (needReceiver) irGet(valueParameters.single()) else irNull()
putValueArgument(3, receiver)
putValueArgument(4, irKType(this@CallableReferenceLowering.context, irFunction.returnType))
}
+IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, irBuiltIns.unitType)
// Save all arguments to fields.
boundFunctionParameters.forEachIndexed { index, parameter ->
+irSetField(irGet(functionReferenceThis.owner), argumentToPropertiesMap[parameter.descriptor]!!, irGet(valueParameters[index]))
}
} }
} }
} }
@@ -328,108 +276,65 @@ 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(superFunctionSymbol: IrSimpleFunctionSymbol, parent: IrClass) private fun buildInvokeMethod(superFunction: IrSimpleFunction) = WrappedSimpleFunctionDescriptor().let {
= object : SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() { IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
IrSimpleFunctionSymbolImpl(it),
superFunction.name,
Visibilities.PRIVATE,
Modality.FINAL,
referencedFunction.returnType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = superFunction.isSuspend
).apply {
it.bind(this)
val function = this
parent = functionReferenceClass
functionReferenceClass.declarations += function
val superFunctionDescriptor: FunctionDescriptor = superFunctionSymbol.descriptor this.createDispatchReceiverParameter()
override fun buildSymbol() = IrSimpleFunctionSymbolImpl( superFunction.valueParameters.mapIndexedTo(valueParameters) { index, parameter ->
SimpleFunctionDescriptorImpl.create( parameter.copyTo(this, DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, index,
/* containingDeclaration = */ functionReferenceClassDescriptor, type = parameter.type.substitute(typeArgumentsMap))
/* annotations = */ Annotations.EMPTY,
/* name = */ Name.identifier("invoke"),
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE
)
)
override fun doInitialize() {
val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl
val valueParameters = superFunctionDescriptor.valueParameters
.map { it.copyAsValueParameter(descriptor, it.index) }
descriptor.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ functionReferenceClassDescriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(),
/* unsubstitutedValueParameters = */ valueParameters,
/* unsubstitutedReturnType = */ superFunctionDescriptor.returnType,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE).apply {
overriddenDescriptors += superFunctionDescriptor
isSuspend = superFunctionDescriptor.isSuspend
} }
}
override fun buildIr(): IrSimpleFunction { overriddenSymbols += superFunction.symbol
val startOffset = functionReference.startOffset
val endOffset = functionReference.endOffset
val ourSymbol = symbol
return IrFunctionImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
symbol = ourSymbol,
returnType = superFunctionSymbol.owner.returnType // FIXME: substitute
).apply {
val function = this body = context.createIrBuilder(function.symbol, startOffset, endOffset).irBlockBody(startOffset, endOffset) {
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset) +irReturn(
irCall(functionReference.symbol).apply {
this.parent = parent var unboundIndex = 0
val unboundArgsSet = unboundFunctionParameters.toSet()
this.createDispatchReceiverParameter() for (parameter in functionParameters) {
val argument =
superFunctionSymbol.owner.valueParameters.mapTo(this.valueParameters) { if (!unboundArgsSet.contains(parameter))
it.copy(descriptor.valueParameters[it.index]) // FIXME: substitute // Bound parameter - read from field.
} irGetField(
irGet(function.dispatchReceiverParameter!!),
body = irBuilder.irBlockBody(startOffset, endOffset) { argumentToPropertiesMap[parameter]!!
+irReturn( )
irCall(functionReference.symbol).apply { else {
var unboundIndex = 0 if (function.isSuspend && unboundIndex == valueParameters.size)
val unboundArgsSet = unboundFunctionParameters.toSet() // For suspend functions the last argument is continuation and it is implicit.
functionParameters.forEach { irCall(getContinuationSymbol.owner, listOf(returnType))
val argument = else
if (!unboundArgsSet.contains(it)) irGet(valueParameters[unboundIndex++])
// Bound parameter - read from field. }
irGetField( when (parameter) {
irGet(function.dispatchReceiverParameter!!), referencedFunction.dispatchReceiverParameter -> dispatchReceiver = argument
argumentToPropertiesMap[it.descriptor]!! referencedFunction.extensionReceiverParameter -> extensionReceiver = argument
) else -> putValueArgument(parameter.index, argument)
else {
if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size)
// For suspend functions the last argument is continuation and it is implicit.
irCall(getContinuationSymbol.owner,
listOf(returnType))
else
irGet(valueParameters[unboundIndex++])
}
when (it) {
irFunction.dispatchReceiverParameter -> dispatchReceiver = argument
irFunction.extensionReceiverParameter -> extensionReceiver = 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" }
} }
)
} }
} }
} }
private fun buildField(name: Name, type: IrType, isMutable: Boolean): IrField = createField(
functionReference.startOffset,
functionReference.endOffset,
type,
name,
isMutable,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
functionReferenceClassDescriptor
).also {
functionReferenceClass.addChild(it)
}
} }
} }
@@ -57,12 +57,11 @@ internal class DataClassOperatorsLowering(val context: Context): FunctionLowerin
extensionReceiver = argument extensionReceiver = argument
} }
} else { } else {
val tmp = scope.createTemporaryVariable(argument)
val call = irCall(newCallee, typeArguments).apply {
extensionReceiver = irGet(tmp)
}
irBlock(argument) { irBlock(argument) {
+tmp val tmp = irTemporary(argument)
val call = irCall(newCallee, typeArguments).apply {
extensionReceiver = irGet(tmp)
}
+irIfThenElse(call.type, +irIfThenElse(call.type,
irEqeqeq(irGet(tmp), irNull()), irEqeqeq(irGet(tmp), irNull()),
if (isToString) if (isToString)
@@ -71,7 +71,7 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
} }
override fun visitField(declaration: IrField) { override fun visitField(declaration: IrField) {
(declaration.descriptor as WrappedPropertyDescriptor).bind(declaration) (declaration.descriptor as WrappedFieldDescriptor).bind(declaration)
declaration.acceptChildrenVoid(this) declaration.acceptChildrenVoid(this)
} }
@@ -130,7 +130,7 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
WrappedClassDescriptor(descriptor.annotations, descriptor.source) WrappedClassDescriptor(descriptor.annotations, descriptor.source)
override fun remapDeclaredField(descriptor: PropertyDescriptor) = override fun remapDeclaredField(descriptor: PropertyDescriptor) =
WrappedPropertyDescriptor(descriptor.annotations, descriptor.source) WrappedFieldDescriptor(descriptor.annotations, descriptor.source)
override fun remapDeclaredSimpleFunction(descriptor: FunctionDescriptor) = override fun remapDeclaredSimpleFunction(descriptor: FunctionDescriptor) =
WrappedSimpleFunctionDescriptor(descriptor.annotations, descriptor.source) WrappedSimpleFunctionDescriptor(descriptor.annotations, descriptor.source)
@@ -7,6 +7,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.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.descriptors.WrappedFieldDescriptor
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
@@ -19,7 +20,6 @@ import org.jetbrains.kotlin.backend.konan.SYNTHETIC_OFFSET
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
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.impl.PropertyDescriptorImpl
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.IrDeclarationOriginImpl import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
@@ -33,19 +33,15 @@ 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.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.types.typeWith
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.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.replace
internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass { internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass {
private var tempIndex = 0 private var tempIndex = 0
@@ -59,7 +55,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
val classSymbol = val classSymbol =
if (isLocal) { if (isLocal) {
assert(receiverTypes.isEmpty(), { "Local delegated property cannot have explicit receiver" }) assert(receiverTypes.isEmpty()) { "Local delegated property cannot have explicit receiver" }
when { when {
isMutable -> symbols.kLocalDelegatedMutablePropertyImpl isMutable -> symbols.kLocalDelegatedMutablePropertyImpl
else -> symbols.kLocalDelegatedPropertyImpl else -> symbols.kLocalDelegatedPropertyImpl
@@ -87,29 +83,37 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
return classSymbol.constructors.single() to arguments return classSymbol.constructors.single() to arguments
} }
private fun ClassDescriptor.replace(vararg type: KotlinType): SimpleType {
return this.defaultType.replace(type.map(::TypeProjectionImpl))
}
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.owner val arrayClass = context.ir.symbols.array.owner
val arrayItemGetter = arrayClass.functions.single { it.descriptor.name == Name.identifier("get") } val arrayItemGetter = arrayClass.functions.single { it.name == Name.identifier("get") }
val anyType = context.irBuiltIns.anyType val anyType = context.irBuiltIns.anyType
val kPropertyImplType = context.ir.symbols.kProperty1Impl.typeWith(anyType, anyType) val kPropertyImplType = context.ir.symbols.kProperty1Impl.typeWith(anyType, anyType)
val kPropertiesFieldType: IrType = context.ir.symbols.array.typeWith(kPropertyImplType) val kPropertiesFieldType: IrType = context.ir.symbols.array.typeWith(kPropertyImplType)
val kPropertiesField = IrFieldImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, val kPropertiesField = WrappedFieldDescriptor(
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION, Annotations.create(listOf(AnnotationDescriptorImpl(context.ir.symbols.sharedImmutable.defaultType,
createKPropertiesFieldDescriptor(irFile.packageFragmentDescriptor, emptyMap(), SourceElement.NO_SOURCE)))
kPropertiesFieldType.toKotlinType() ).let {
), IrFieldImpl(
kPropertiesFieldType SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
) DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
IrFieldSymbolImpl(it),
"KPROPERTIES".synthesizedName,
kPropertiesFieldType,
Visibilities.PRIVATE,
isFinal = true,
isExternal = false,
isStatic = true
).apply {
it.bind(this)
parent = irFile
}
}
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() { irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
@@ -135,18 +139,20 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, startOffset, endOffset) val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, startOffset, endOffset)
irBuilder.run { irBuilder.run {
val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null } val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null }
if (receiversCount == 1) // Has receiver. return when (receiversCount) {
return createKProperty(expression, this) 1 -> createKProperty(expression, this) // Has receiver.
else if (receiversCount == 2)
throw AssertionError("Callable reference to properties with two receivers is not allowed: ${expression.descriptor}")
else { // Cache KProperties with no arguments.
val field = kProperties.getOrPut(expression.descriptor) {
createKProperty(expression, this) to kProperties.size
}
return irCall(arrayItemGetter).apply { 2 -> error("Callable reference to properties with two receivers is not allowed: ${expression.descriptor}")
dispatchReceiver = irGetField(null, kPropertiesField)
putValueArgument(0, irInt(field.second)) else -> { // Cache KProperties with no arguments.
val field = kProperties.getOrPut(expression.descriptor) {
createKProperty(expression, this) to kProperties.size
}
irCall(arrayItemGetter).apply {
dispatchReceiver = irGetField(null, kPropertiesField)
putValueArgument(0, irInt(field.second))
}
} }
} }
} }
@@ -188,11 +194,8 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
// TODO: move to object for lazy initialization. // TODO: move to object for lazy initialization.
irFile.declarations.add(0, kPropertiesField.apply { irFile.declarations.add(0, kPropertiesField.apply {
initializer = IrExpressionBodyImpl(startOffset, endOffset, initializer = IrExpressionBodyImpl(startOffset, endOffset,
context.createArrayOfExpression(kPropertyImplType, initializers, context.createArrayOfExpression(startOffset, endOffset, kPropertyImplType, initializers))
startOffset, endOffset))
}) })
kPropertiesField.parent = irFile
} }
} }
@@ -235,15 +238,18 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
type = getterKFunctionType, type = getterKFunctionType,
symbol = expression.getter!!, symbol = expression.getter!!,
descriptor = getter.descriptor, descriptor = getter.descriptor,
typeArgumentsCount = 0 typeArgumentsCount = getter.typeParameters.size,
valueArgumentsCount = getter.valueParameters.size
).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) }
for (index in 0 until expression.typeArgumentsCount)
putTypeArgument(index, expression.getTypeArgument(index))
} }
} }
val setterCallableReference = expression.setter?.owner?.let { val setterCallableReference = expression.setter?.owner?.let { setter ->
if (!isKMutablePropertyType(expression.type.toKotlinType())) null if (!isKMutablePropertyType(expression.type)) null
else { else {
val setterKFunctionType = this@PropertyDelegationLowering.context.ir.symbols.getKFunctionType( val setterKFunctionType = this@PropertyDelegationLowering.context.ir.symbols.getKFunctionType(
context.irBuiltIns.unitType, context.irBuiltIns.unitType,
@@ -254,11 +260,14 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
endOffset = endOffset, endOffset = endOffset,
type = setterKFunctionType, type = setterKFunctionType,
symbol = expression.setter!!, symbol = expression.setter!!,
descriptor = it.descriptor, descriptor = setter.descriptor,
typeArgumentsCount = 0 typeArgumentsCount = setter.typeParameters.size,
valueArgumentsCount = setter.valueParameters.size
).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) }
for (index in 0 until expression.typeArgumentsCount)
putTypeArgument(index, expression.getTypeArgument(index))
} }
} }
} }
@@ -297,32 +306,20 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
} }
} }
private fun isKMutablePropertyType(type: KotlinType): Boolean { private fun isKMutablePropertyType(type: IrType): Boolean {
val arguments = type.arguments if (type !is IrSimpleType) return false
val expectedClassDescriptor = when (arguments.size) { val expectedClass = when (type.arguments.size) {
0 -> return false 0 -> return false
1 -> context.reflectionTypes.kMutableProperty0 1 -> context.ir.symbols.kMutableProperty0
2 -> context.reflectionTypes.kMutableProperty1 2 -> context.ir.symbols.kMutableProperty1
3 -> context.reflectionTypes.kMutableProperty2 3 -> context.ir.symbols.kMutableProperty2
else -> throw AssertionError("More than 2 receivers is not allowed") else -> throw AssertionError("More than 2 receivers is not allowed")
} }
return type == expectedClassDescriptor.defaultType.replace(arguments) return type.classifier == expectedClass
} }
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: KotlinType): PropertyDescriptorImpl {
return PropertyDescriptorImpl.create(containingDeclaration,
Annotations.create(listOf(AnnotationDescriptorImpl(context.ir.symbols.sharedImmutable.defaultType,
emptyMap(), SourceElement.NO_SOURCE))), Modality.FINAL, Visibilities.PRIVATE,
false, "KPROPERTIES".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE,
false, false, false, false, false, false).apply {
this.setType(fieldType, emptyList(), null, null)
this.initialize(null, null)
}
}
} }
internal fun IrBuilderWithScope.irKType(context: KonanBackendContext, type: IrType): IrExpression { internal fun IrBuilderWithScope.irKType(context: KonanBackendContext, type: IrType): IrExpression {
@@ -8,7 +8,11 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass 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.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor
import org.jetbrains.kotlin.backend.common.ir.copyTo
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.common.runOnFilePostfix import org.jetbrains.kotlin.backend.common.runOnFilePostfix
@@ -17,8 +21,6 @@ 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.konan.irasdescriptors.constructedClass import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
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.*
@@ -28,14 +30,17 @@ import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin.ARGUMENTS_REORDERIN
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.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.types.typeWith
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.scopes.MemberScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager
internal class EnumSyntheticFunctionsBuilder(val context: Context) { internal class EnumSyntheticFunctionsBuilder(val context: Context) {
fun buildValuesExpression(startOffset: Int, endOffset: Int, fun buildValuesExpression(startOffset: Int, endOffset: Int,
@@ -105,9 +110,7 @@ internal class EnumUsageLowering(val context: Context)
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
val descriptor = expression.descriptor as? FunctionDescriptor if (expression.symbol != enumValuesSymbol && expression.symbol != enumValueOfSymbol)
?: return expression
if (descriptor.original != enumValuesDescriptor && descriptor.original != enumValueOfDescriptor)
return expression return expression
val irClassSymbol = expression.getTypeArgument(0)!!.classifierOrNull as? IrClassSymbol val irClassSymbol = expression.getTypeArgument(0)!!.classifierOrNull as? IrClassSymbol
@@ -119,19 +122,17 @@ internal class EnumUsageLowering(val context: Context)
assert (irClass.kind == ClassKind.ENUM_CLASS) assert (irClass.kind == ClassKind.ENUM_CLASS)
return if (descriptor.original == enumValuesDescriptor) { return if (expression.symbol == enumValuesSymbol) {
enumSyntheticFunctionsBuilder.buildValuesExpression(expression.startOffset, expression.endOffset, irClass) 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, irClass, value) enumSyntheticFunctionsBuilder.buildValueOfExpression(expression.startOffset, expression.endOffset, irClass, value)
} }
} }
private val enumValueOfSymbol = context.ir.symbols.enumValueOf private val enumValueOfSymbol = context.ir.symbols.enumValueOf
private val enumValueOfDescriptor = enumValueOfSymbol.descriptor
private val enumValuesSymbol = context.ir.symbols.enumValues private val enumValuesSymbol = context.ir.symbols.enumValues
private val enumValuesDescriptor = enumValuesSymbol.descriptor
private fun loadEnumEntry(startOffset: Int, endOffset: Int, enumClass: IrClass, name: Name): IrExpression { private fun loadEnumEntry(startOffset: Int, endOffset: Int, enumClass: IrClass, name: Name): IrExpression {
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClass) val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClass)
@@ -154,8 +155,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
} }
override fun lower(irClass: IrClass) { override fun lower(irClass: IrClass) {
val descriptor = irClass.descriptor if (irClass.kind != ClassKind.ENUM_CLASS) return
if (descriptor.kind != ClassKind.ENUM_CLASS) return
EnumClassTransformer(irClass).run() EnumClassTransformer(irClass).run()
} }
@@ -166,10 +166,9 @@ 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) private val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(irClass)
private val loweredEnumConstructors = mutableMapOf<ClassConstructorDescriptor, IrConstructor>() private val loweredEnumConstructors = mutableMapOf<IrConstructor, IrConstructor>()
private val descriptorToIrConstructorWithDefaultArguments = mutableMapOf<ClassConstructorDescriptor, IrConstructor>() private val defaultEnumEntryConstructors = mutableMapOf<IrConstructor, IrConstructor>()
private val defaultEnumEntryConstructors = mutableMapOf<ClassConstructorDescriptor, IrConstructor>() private val loweredEnumConstructorParameters = mutableMapOf<IrValueParameter, IrValueParameter>()
private val loweredEnumConstructorParameters = mutableMapOf<ValueParameterDescriptor, ValueParameterDescriptor>()
private val enumSyntheticFunctionsBuilder = EnumSyntheticFunctionsBuilder(context) private val enumSyntheticFunctionsBuilder = EnumSyntheticFunctionsBuilder(context)
fun run() { fun run() {
@@ -177,9 +176,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
lowerEnumConstructors(irClass) lowerEnumConstructors(irClass)
lowerEnumEntriesClasses() lowerEnumEntriesClasses()
val defaultClass = createDefaultClassForEnumEntries() val defaultClass = createDefaultClassForEnumEntries()
lowerEnumClassBody() lowerEnumClassBody(defaultClass)
if (defaultClass != null)
irClass.addChild(defaultClass)
createImplObject() createImplObject()
} }
@@ -225,48 +222,44 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
} }
private fun createDefaultClassForEnumEntries(): IrClass? { private fun createDefaultClassForEnumEntries(): IrClass? {
if (!irClass.declarations.any({ it is IrEnumEntry && it.correspondingClass == null })) return null if (!irClass.declarations.any { it is IrEnumEntry && it.correspondingClass == null }) return null
val startOffset = irClass.startOffset val defaultClass = WrappedClassDescriptor().let {
val endOffset = irClass.endOffset IrClassImpl(
val descriptor = irClass.descriptor irClass.startOffset, irClass.endOffset,
val defaultClassDescriptor = ClassDescriptorImpl(descriptor, "DEFAULT".synthesizedName, Modality.FINAL, DECLARATION_ORIGIN_ENUM,
ClassKind.CLASS, listOf(descriptor.defaultType), SourceElement.NO_SOURCE, false, LockBasedStorageManager.NO_LOCKS) IrClassSymbolImpl(it),
val defaultClass = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, defaultClassDescriptor) "DEFAULT".synthesizedName,
defaultClass.createParameterDeclarations() ClassKind.CLASS,
Visibilities.PRIVATE,
Modality.FINAL,
val constructors = mutableSetOf<ClassConstructorDescriptor>() isCompanion = false,
isInner = false,
descriptor.constructors.forEach { isData = false,
val loweredEnumIrConstructor = loweredEnumConstructors[it]!! isExternal = false,
val loweredEnumConstructor = loweredEnumIrConstructor.descriptor isInline = false
).apply {
val constructor = defaultClass.addSimpleDelegatingConstructor( it.bind(this)
loweredEnumIrConstructor, parent = irClass
context.irBuiltIns, irClass.declarations += this
DECLARATION_ORIGIN_ENUM createParameterDeclarations()
)
val constructorDescriptor = constructor.descriptor
constructors.add(constructorDescriptor)
defaultEnumEntryConstructors.put(loweredEnumConstructor, constructor)
val irConstructor = descriptorToIrConstructorWithDefaultArguments[loweredEnumConstructor]
if (irConstructor != null) {
it.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument ->
val loweredArgument = loweredEnumConstructor.valueParameters[argument.loweredIndex()]
val body = irConstructor.getDefault(loweredArgument)!!.deepCopyWithVariables()
body.transformChildrenVoid(ParameterMapper(constructor))
body.accept(SetDeclarationsParentVisitor, constructor)
constructor.putDefault(constructorDescriptor.valueParameters[loweredArgument.index], body)
}
} }
} }
val memberScope = stub<MemberScope>("enum default class") for (superConstructor in irClass.constructors) {
defaultClassDescriptor.initialize(memberScope, constructors, null) val constructor = defaultClass.addSimpleDelegatingConstructor(superConstructor, context.irBuiltIns)
defaultEnumEntryConstructors[superConstructor] = constructor
defaultClass.setSuperSymbolsAndAddFakeOverrides(listOf(irClass.defaultType)) for (parameter in constructor.valueParameters) {
val defaultValue = superConstructor.valueParameters[parameter.index].defaultValue ?: continue
val body = defaultValue.deepCopyWithVariables()
body.transformChildrenVoid(ParameterMapper(superConstructor, constructor, false))
body.patchDeclarationParents(constructor)
parameter.defaultValue = body
}
}
defaultClass.superTypes += irClass.defaultType
defaultClass.addFakeOverrides()
return defaultClass return defaultClass
} }
@@ -302,39 +295,42 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
++i ++i
} }
implObject.addChild(createSyntheticValuesPropertyDeclaration(enumEntries)) implObject.declarations += createSyntheticValuesPropertyDeclaration(enumEntries)
implObject.addChild(createValuesPropertyInitializer(enumEntries)) implObject.declarations += createValuesPropertyInitializer(enumEntries)
irClass.addChild(implObject) irClass.declarations += implObject
} }
private val genericCreateUninitializedInstanceSymbol = context.ir.symbols.createUninitializedInstance private val createUninitializedInstance = context.ir.symbols.createUninitializedInstance.owner
private val genericCreateUninitializedInstanceDescriptor = genericCreateUninitializedInstanceSymbol.descriptor
private fun createSyntheticValuesPropertyDeclaration(enumEntries: List<IrEnumEntry>): IrPropertyImpl { private fun createSyntheticValuesPropertyDeclaration(enumEntries: List<IrEnumEntry>): IrPropertyImpl {
val startOffset = irClass.startOffset val startOffset = irClass.startOffset
val endOffset = irClass.endOffset val endOffset = irClass.endOffset
val irValuesInitializer = context.createArrayOfExpression(irClass.defaultType, val irValuesInitializer = context.createArrayOfExpression(
startOffset, endOffset,
irClass.defaultType,
enumEntries enumEntries
.sortedBy { it.descriptor.name } .sortedBy { it.name }
.map { .map {
val initializer = it.initializerExpression val initializer = it.initializerExpression
val entryConstructorCall = when { val entryConstructorCall = when {
initializer is IrCall -> initializer initializer is IrCall -> initializer
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL ->
initializer.statements.last() as IrCall initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL ->
else -> error("Unexpected initializer: $initializer") initializer.statements.last() as IrCall
}
val entryConstructor = entryConstructorCall.symbol.owner as IrConstructor else -> error("Unexpected initializer: $initializer")
val entryClass = entryConstructor.constructedClass }
val entryClass = (entryConstructorCall.symbol.owner as IrConstructor).constructedClass
irCall(startOffset, endOffset, irCall(startOffset, endOffset,
genericCreateUninitializedInstanceSymbol.owner, createUninitializedInstance,
listOf(entryClass.defaultType) listOf(entryClass.defaultType)
) )
}, startOffset, endOffset) }
)
val irField = loweredEnum.valuesField.apply { val irField = loweredEnum.valuesField.apply {
initializer = IrExpressionBodyImpl(startOffset, endOffset, irValuesInitializer) initializer = IrExpressionBodyImpl(startOffset, endOffset, irValuesInitializer)
} }
@@ -344,15 +340,13 @@ 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( val value = IrGetFieldImpl(
startOffset, startOffset, endOffset,
endOffset,
loweredEnum.valuesField.symbol, loweredEnum.valuesField.symbol,
loweredEnum.valuesField.type, loweredEnum.valuesField.type,
receiver receiver
) )
val returnStatement = IrReturnImpl( val returnStatement = IrReturnImpl(
startOffset, startOffset, endOffset,
endOffset,
context.irBuiltIns.nothingType, context.irBuiltIns.nothingType,
loweredEnum.valuesGetter.symbol, loweredEnum.valuesGetter.symbol,
value value
@@ -360,14 +354,14 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
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,
false, loweredEnum.valuesField.descriptor, irField, getter, null).also { false, loweredEnum.valuesField.descriptor, irField, getter, null).apply {
it.parent = loweredEnum.implObject parent = loweredEnum.implObject
} }
} }
private val initInstanceSymbol = context.ir.symbols.initInstance private val initInstanceSymbol = context.ir.symbols.initInstance
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.owner.name == Name.identifier("get") }
private val arrayType = context.ir.symbols.array.typeWith(irClass.defaultType) private val arrayType = context.ir.symbols.array.typeWith(irClass.defaultType)
@@ -376,17 +370,23 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val endOffset = irClass.endOffset val endOffset = irClass.endOffset
fun IrBlockBodyBuilder.initInstanceCall(instance: IrCall, constructor: IrCall): IrCall = fun IrBlockBodyBuilder.initInstanceCall(instance: IrCall, constructor: IrCall): IrCall =
irCall(initInstanceSymbol).apply { irCall(initInstanceSymbol).apply {
putValueArgument(0, instance) putValueArgument(0, instance)
putValueArgument(1, constructor) putValueArgument(1, constructor)
} }
return IrAnonymousInitializerImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, loweredEnum.implObject.descriptor).apply { val implObject = loweredEnum.implObject
parent = irClass return IrAnonymousInitializerImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrAnonymousInitializerSymbolImpl(WrappedClassDescriptor())
).apply {
parent = implObject
body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody(irClass) { body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody(irClass) {
val instances = irTemporary(irGetField(irGet(loweredEnum.implObject.thisReceiver!!), loweredEnum.valuesField)) val receiver = implObject.thisReceiver!!
val instances = irTemporary(irGetField(irGet(receiver), loweredEnum.valuesField))
enumEntries enumEntries
.sortedBy { it.descriptor.name } .sortedBy { it.name }
.withIndex() .withIndex()
.forEach { .forEach {
val instance = irCall(arrayGetSymbol).apply { val instance = irCall(arrayGetSymbol).apply {
@@ -394,19 +394,22 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
putValueArgument(0, irInt(it.index)) putValueArgument(0, irInt(it.index))
} }
val initializer = it.value.initializerExpression!! val initializer = it.value.initializerExpression!!
initializer.patchDeclarationParents(implObject)
when { when {
initializer is IrCall -> +initInstanceCall(instance, initializer) initializer is IrCall -> +initInstanceCall(instance, initializer)
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> { initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> {
val statements = initializer.statements val statements = initializer.statements
val constructorCall = statements.last() as IrCall val constructorCall = statements.last() as IrCall
statements[statements.lastIndex] = initInstanceCall(instance, constructorCall) statements[statements.lastIndex] = initInstanceCall(instance, constructorCall)
+initializer +initializer
} }
else -> error("Unexpected initializer: $initializer") else -> error("Unexpected initializer: $initializer")
} }
} }
+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!!) extensionReceiver = irGet(receiver)
} }
} }
} }
@@ -456,85 +459,75 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
private fun transformEnumConstructor(enumConstructor: IrConstructor): IrConstructor { private fun transformEnumConstructor(enumConstructor: IrConstructor): IrConstructor {
val loweredEnumConstructor = lowerEnumConstructor(enumConstructor) val loweredEnumConstructor = lowerEnumConstructor(enumConstructor)
enumConstructor.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach { for (parameter in enumConstructor.valueParameters) {
val body = enumConstructor.getDefault(it)!! val defaultValue = parameter.defaultValue ?: continue
body.transformChildrenVoid(object: IrElementTransformerVoid() { defaultValue.transformChildrenVoid(ParameterMapper(enumConstructor, loweredEnumConstructor, true))
override fun visitGetValue(expression: IrGetValue): IrExpression { loweredEnumConstructor.valueParameters[parameter.loweredIndex].defaultValue = defaultValue
val descriptor = expression.descriptor defaultValue.patchDeclarationParents(loweredEnumConstructor)
when (descriptor) {
is ValueParameterDescriptor -> {
val parameter = loweredEnumConstructor.valueParameters[descriptor.loweredIndex()]
return IrGetValueImpl(expression.startOffset,
expression.endOffset,
parameter.type,
parameter.symbol)
}
}
return expression
}
})
loweredEnumConstructor.valueParameters[it.loweredIndex()].defaultValue = body
descriptorToIrConstructorWithDefaultArguments[loweredEnumConstructor.descriptor] = loweredEnumConstructor
} }
return loweredEnumConstructor
}
private fun lowerEnumConstructor(enumConstructor: IrConstructor): IrConstructorImpl {
val loweredConstructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
enumConstructor.descriptor.containingDeclaration,
enumConstructor.descriptor.annotations,
enumConstructor.descriptor.isPrimary,
enumConstructor.descriptor.source
)
val valueParameters =
listOf(
loweredConstructorDescriptor.createValueParameter(
0,
"name",
context.irBuiltIns.stringType,
enumConstructor.startOffset,
enumConstructor.endOffset
),
loweredConstructorDescriptor.createValueParameter(
1,
"ordinal",
context.irBuiltIns.intType,
enumConstructor.startOffset,
enumConstructor.endOffset
)
) +
enumConstructor.valueParameters.map {
val descriptor = it.descriptor as ValueParameterDescriptor
val loweredValueParameterDescriptor = descriptor.copy(
loweredConstructorDescriptor,
it.name,
descriptor.loweredIndex()
)
loweredEnumConstructorParameters[descriptor] = loweredValueParameterDescriptor
it.copy(loweredValueParameterDescriptor)
}
loweredConstructorDescriptor.initialize(
valueParameters.map { it.descriptor as ValueParameterDescriptor },
Visibilities.PROTECTED
)
loweredConstructorDescriptor.returnType = enumConstructor.descriptor.returnType
val loweredEnumConstructor = IrConstructorImpl(
enumConstructor.startOffset, enumConstructor.endOffset, enumConstructor.origin,
loweredConstructorDescriptor,
enumConstructor.returnType,
enumConstructor.body!!
)
loweredEnumConstructor.valueParameters += valueParameters
loweredEnumConstructor.parent = enumConstructor.parent
loweredEnumConstructors[enumConstructor.descriptor] = loweredEnumConstructor
return loweredEnumConstructor return loweredEnumConstructor
} }
private fun lowerEnumClassBody() { private fun lowerEnumConstructor(constructor: IrConstructor): IrConstructorImpl {
irClass.transformChildrenVoid(EnumClassBodyTransformer()) val startOffset = constructor.startOffset
val endOffset = constructor.endOffset
val loweredConstructor = WrappedClassConstructorDescriptor(
constructor.descriptor.annotations,
constructor.descriptor.source
).let {
IrConstructorImpl(
startOffset, endOffset,
constructor.origin,
IrConstructorSymbolImpl(it),
constructor.name,
Visibilities.PROTECTED,
constructor.returnType,
isInline = false,
isExternal = false,
isPrimary = constructor.isPrimary
).apply {
it.bind(this)
parent = constructor.parent
body = constructor.body!! // Will be transformed later.
}
}
fun createSynthesizedValueParameter(index: Int, name: String, type: IrType) =
WrappedValueParameterDescriptor().let {
IrValueParameterImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrValueParameterSymbolImpl(it),
Name.identifier(name),
index,
type,
varargElementType = null,
isCrossinline = false,
isNoinline = false
).apply {
it.bind(this)
parent = loweredConstructor
}
}
loweredConstructor.valueParameters += createSynthesizedValueParameter(0, "name", context.irBuiltIns.stringType)
loweredConstructor.valueParameters += createSynthesizedValueParameter(1, "ordinal", context.irBuiltIns.intType)
constructor.valueParameters.mapTo(loweredConstructor.valueParameters) {
it.copyTo(loweredConstructor, index = it.loweredIndex).apply {
loweredEnumConstructorParameters[it] = this
}
}
loweredEnumConstructors[constructor] = loweredConstructor
return loweredConstructor
}
private fun lowerEnumClassBody(defaultClass: IrClass?) {
irClass.transformChildrenVoid(EnumClassBodyTransformer(defaultClass))
// Enum entries's classes have already been pulled out to the upper level - clear them up.
irClass.declarations.filterIsInstance<IrEnumEntry>().forEach { it.correspondingClass = null }
} }
private inner class InEnumClassConstructor(val enumClassConstructor: IrConstructor) : private inner class InEnumClassConstructor(val enumClassConstructor: IrConstructor) :
@@ -544,11 +537,12 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val endOffset = enumConstructorCall.endOffset val endOffset = enumConstructorCall.endOffset
val origin = enumConstructorCall.origin val origin = enumConstructorCall.origin
val result = IrDelegatingConstructorCallImpl(startOffset, endOffset, val result = IrDelegatingConstructorCallImpl(
startOffset, endOffset,
context.irBuiltIns.unitType, context.irBuiltIns.unitType,
enumConstructorCall.symbol, enumConstructorCall.descriptor, enumConstructorCall.typeArgumentsCount) enumConstructorCall.symbol)
assert(result.descriptor.valueParameters.size == 2) { assert(result.symbol.owner.valueParameters.size == 2) {
"Enum(String, Int) constructor call expected:\n${result.dump()}" "Enum(String, Int) constructor call expected:\n${result.dump()}"
} }
@@ -570,16 +564,18 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
} }
override fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression { override fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression {
val descriptor = delegatingConstructorCall.descriptor
val startOffset = delegatingConstructorCall.startOffset val startOffset = delegatingConstructorCall.startOffset
val endOffset = delegatingConstructorCall.endOffset val endOffset = delegatingConstructorCall.endOffset
val loweredDelegatedConstructor = loweredEnumConstructors.getOrElse(descriptor) { val delegatingConstructor = delegatingConstructorCall.symbol.owner
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $descriptor") val loweredDelegatingConstructor = loweredEnumConstructors.getOrElse(delegatingConstructor) {
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $delegatingConstructor")
} }
val result = IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.unitType, val result = IrDelegatingConstructorCallImpl(
loweredDelegatedConstructor.symbol, loweredDelegatedConstructor.descriptor, 0) startOffset, endOffset,
context.irBuiltIns.unitType,
loweredDelegatingConstructor.symbol)
val firstParameter = enumClassConstructor.valueParameters[0] val firstParameter = enumClassConstructor.valueParameters[0]
result.putValueArgument(0, result.putValueArgument(0,
@@ -588,25 +584,26 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
result.putValueArgument(1, result.putValueArgument(1,
IrGetValueImpl(startOffset, endOffset, secondParameter.type, secondParameter.symbol)) IrGetValueImpl(startOffset, endOffset, secondParameter.type, secondParameter.symbol))
descriptor.valueParameters.forEach { valueParameter -> delegatingConstructor.valueParameters.forEach {
result.putValueArgument(valueParameter.loweredIndex(), delegatingConstructorCall.getValueArgument(valueParameter)) result.putValueArgument(it.loweredIndex, delegatingConstructorCall.getValueArgument(it.index))
} }
return result return result
} }
} }
private abstract inner class InEnumEntry(private val enumEntry: ClassDescriptor) : EnumConstructorCallTransformer { private abstract inner class InEnumEntry(private val enumEntry: IrEnumEntry) : EnumConstructorCallTransformer {
override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression { override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression {
val name = enumEntry.name.asString() val name = enumEntry.name.asString()
val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(enumEntry) val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(enumEntry.descriptor)
val descriptor = enumConstructorCall.descriptor
val startOffset = enumConstructorCall.startOffset val startOffset = enumConstructorCall.startOffset
val endOffset = enumConstructorCall.endOffset val endOffset = enumConstructorCall.endOffset
val loweredConstructor = loweredEnumConstructors.getOrElse(descriptor) { val enumConstructor = enumConstructorCall.symbol.owner
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $descriptor") val loweredConstructor = loweredEnumConstructors.getOrElse(enumConstructor) {
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $enumConstructor")
} }
val result = createConstructorCall(startOffset, endOffset, loweredConstructor.symbol) val result = createConstructorCall(startOffset, endOffset, loweredConstructor.symbol)
@@ -616,9 +613,8 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
result.putValueArgument(1, result.putValueArgument(1,
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, ordinal)) IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, ordinal))
descriptor.valueParameters.forEach { valueParameter -> enumConstructor.valueParameters.forEach {
val i = valueParameter.index result.putValueArgument(it.loweredIndex, enumConstructorCall.getValueArgument(it.index))
result.putValueArgument(i + 2, enumConstructorCall.getValueArgument(i))
} }
return result return result
@@ -631,7 +627,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
abstract fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrMemberAccessExpression abstract fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrMemberAccessExpression
} }
private inner class InEnumEntryClassConstructor(enumEntry: ClassDescriptor) : InEnumEntry(enumEntry) { private inner class InEnumEntryClassConstructor(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) {
override fun createConstructorCall( override fun createConstructorCall(
startOffset: Int, startOffset: Int,
endOffset: Int, endOffset: Int,
@@ -640,25 +636,23 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
startOffset, startOffset,
endOffset, endOffset,
context.irBuiltIns.unitType, context.irBuiltIns.unitType,
loweredConstructor, loweredConstructor
loweredConstructor.descriptor,
0
) )
} }
private inner class InEnumEntryInitializer(enumEntry: ClassDescriptor) : InEnumEntry(enumEntry) { private inner class InEnumEntryInitializer(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) {
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrCall { override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrCall {
val irConstructorSymbol = defaultEnumEntryConstructors[loweredConstructor.descriptor]?.symbol val irConstructorSymbol = defaultEnumEntryConstructors[loweredConstructor.owner]?.symbol
?: loweredConstructor ?: loweredConstructor
return IrCallImpl(startOffset, endOffset, irConstructorSymbol.owner.returnType, irConstructorSymbol) return IrCallImpl(startOffset, endOffset, irConstructorSymbol.owner.returnType, irConstructorSymbol)
} }
} }
private inner class EnumClassBodyTransformer : IrElementTransformerVoid() { private inner class EnumClassBodyTransformer(val defaultClass: IrClass?) : IrElementTransformerVoid() {
private var enumConstructorCallTransformer: EnumConstructorCallTransformer? = null private var enumConstructorCallTransformer: EnumConstructorCallTransformer? = null
override fun visitClass(declaration: IrClass): IrStatement { override fun visitClass(declaration: IrClass): IrStatement {
if (declaration.descriptor.kind == ClassKind.ENUM_CLASS) if (declaration.kind == ClassKind.ENUM_CLASS || declaration == defaultClass)
return declaration return declaration
return super.visitClass(declaration) return super.visitClass(declaration)
} }
@@ -666,27 +660,25 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
override fun visitEnumEntry(declaration: IrEnumEntry): IrStatement { override fun visitEnumEntry(declaration: IrEnumEntry): IrStatement {
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" } assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
enumConstructorCallTransformer = InEnumEntryInitializer(declaration.descriptor) enumConstructorCallTransformer = InEnumEntryInitializer(declaration)
var result: IrEnumEntry = IrEnumEntryImpl(declaration.startOffset, declaration.endOffset, declaration.origin, declaration.initializerExpression = declaration.initializerExpression?.transform(this, data = null)
declaration.descriptor, null, declaration.initializerExpression)
result = super.visitEnumEntry(result) as IrEnumEntry
enumConstructorCallTransformer = null enumConstructorCallTransformer = null
return result return declaration
} }
override fun visitConstructor(declaration: IrConstructor): IrStatement { override fun visitConstructor(declaration: IrConstructor): IrStatement {
val constructorDescriptor = declaration.descriptor val containingClass = declaration.parentAsClass
val containingClass = constructorDescriptor.containingDeclaration
// TODO local (non-enum) class in enum class constructor? // TODO local (non-enum) class in enum class constructor?
val previous = enumConstructorCallTransformer val previous = enumConstructorCallTransformer
if (containingClass.kind == ClassKind.ENUM_ENTRY) { if (containingClass.kind == ClassKind.ENUM_ENTRY) {
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" } assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
enumConstructorCallTransformer = InEnumEntryClassConstructor(containingClass) val entry = irClass.declarations.filterIsInstance<IrEnumEntry>().single { it.correspondingClass == containingClass }
enumConstructorCallTransformer = InEnumEntryClassConstructor(entry)
} else if (containingClass.kind == ClassKind.ENUM_CLASS) { } else if (containingClass.kind == ClassKind.ENUM_CLASS) {
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" } assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
enumConstructorCallTransformer = InEnumClassConstructor(declaration) enumConstructorCallTransformer = InEnumClassConstructor(declaration)
@@ -703,7 +695,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
val callTransformer = enumConstructorCallTransformer ?: val callTransformer = enumConstructorCallTransformer ?:
throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump()) throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump())
return callTransformer.transform(expression) return callTransformer.transform(expression)
@@ -712,9 +704,9 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
if (expression.descriptor.containingDeclaration.kind == ClassKind.ENUM_CLASS) { if (expression.symbol.owner.parentAsClass.kind == ClassKind.ENUM_CLASS) {
val callTransformer = enumConstructorCallTransformer ?: val callTransformer = enumConstructorCallTransformer ?:
throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump()) throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump())
return callTransformer.transform(expression) return callTransformer.transform(expression)
} }
@@ -722,34 +714,36 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
} }
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
val loweredParameter = loweredEnumConstructorParameters[expression.descriptor] val parameter = expression.symbol.owner
if (loweredParameter != null) { val loweredParameter = loweredEnumConstructorParameters[parameter]
val loweredEnumConstructor = loweredEnumConstructors[expression.descriptor.containingDeclaration]!! return if (loweredParameter == null) {
val loweredIrParameter = loweredEnumConstructor.valueParameters[loweredParameter.index] expression
assert(loweredIrParameter.descriptor == loweredParameter)
return IrGetValueImpl(expression.startOffset, expression.endOffset, loweredIrParameter.type,
loweredIrParameter.symbol, expression.origin)
} else { } else {
return expression IrGetValueImpl(expression.startOffset, expression.endOffset, loweredParameter.type,
loweredParameter.symbol, expression.origin)
} }
} }
} }
} }
} }
private fun ValueParameterDescriptor.loweredIndex(): Int = index + 2 private val IrValueParameter.loweredIndex: Int get() = index + 2
private class ParameterMapper(superConstructor: IrConstructor,
val constructor: IrConstructor,
val useLoweredIndex: Boolean) : IrElementTransformerVoid() {
private val valueParameters = superConstructor.valueParameters.toSet()
private class ParameterMapper(val originalConstructor: IrConstructor) : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
val descriptor = expression.descriptor
when (descriptor) { val superParameter = expression.symbol.owner as? IrValueParameter ?: return expression
is ValueParameterDescriptor -> { if (valueParameters.contains(superParameter)) {
val parameter = originalConstructor.valueParameters[descriptor.index] val index = if (useLoweredIndex) superParameter.loweredIndex else superParameter.index
return IrGetValueImpl(expression.startOffset, val parameter = constructor.valueParameters[index]
expression.endOffset, return IrGetValueImpl(
parameter.type, expression.startOffset, expression.endOffset,
parameter.symbol) parameter.type,
} parameter.symbol)
} }
return expression return expression
} }
@@ -6,6 +6,7 @@
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.WrappedVariableDescriptor
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
import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.common.push
@@ -16,11 +17,11 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl 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.*
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.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.util.getArguments
@@ -87,24 +88,33 @@ internal class EnumWhenLowering(private val context: Context) : IrElementTransfo
return expression return expression
} }
private fun createEnumOrdinalVariable(enumVariable: IrVariable): IrVariable { // Create temporary variable for subject's ordinal.
val ordinalPropertyGetter = context.ir.symbols.enum.getPropertyGetter("ordinal")!! private fun createEnumOrdinalVariable(enumVariable: IrVariable) = WrappedVariableDescriptor().let {
val getOrdinal = IrCallImpl( IrVariableImpl(
enumVariable.startOffset, enumVariable.endOffset, enumVariable.startOffset, enumVariable.endOffset,
ordinalPropertyGetter.owner.returnType, IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
ordinalPropertyGetter IrVariableSymbolImpl(it),
Name.identifier(enumVariable.name.asString() + "_ordinal"),
context.irBuiltIns.intType,
isVar = false,
isConst = false,
isLateinit = false
).apply { ).apply {
dispatchReceiver = IrGetValueImpl( it.bind(this)
parent = enumVariable.parent
val ordinalPropertyGetter = context.ir.symbols.enum.getPropertyGetter("ordinal")!!
initializer = IrCallImpl(
enumVariable.startOffset, enumVariable.endOffset, enumVariable.startOffset, enumVariable.endOffset,
enumVariable.type, enumVariable.symbol ordinalPropertyGetter.owner.returnType,
) ordinalPropertyGetter
).apply {
dispatchReceiver = IrGetValueImpl(
enumVariable.startOffset, enumVariable.endOffset,
enumVariable.type, enumVariable.symbol
)
}
} }
// Create temporary variable for subject's ordinal.
val ordinalDescriptor = IrTemporaryVariableDescriptorImpl(enumVariable.descriptor.containingDeclaration,
Name.identifier(enumVariable.name.asString() + "_ordinal"), context.builtIns.intType)
return IrVariableImpl(enumVariable.startOffset, enumVariable.endOffset,
IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, ordinalDescriptor,
context.irBuiltIns.intType, getOrdinal)
} }
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
@@ -7,16 +7,13 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor
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.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
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.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl 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.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrReturnTargetSymbol import org.jetbrains.kotlin.ir.symbols.IrReturnTargetSymbol
@@ -25,17 +22,15 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.setDeclarationsParent
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.typeUtil.isNothing
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 = context.ir.symbols
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
@@ -66,7 +61,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
private abstract class Scope private abstract class Scope
private class ReturnableScope(val descriptor: CallableDescriptor): Scope() private class ReturnableScope(val symbol: IrReturnTargetSymbol): Scope()
private class LoopScope(val loop: IrLoop): Scope() private class LoopScope(val loop: IrLoop): Scope()
@@ -92,7 +87,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
} }
override fun visitFunctionNew(declaration: IrFunction): IrStatement { override fun visitFunctionNew(declaration: IrFunction): IrStatement {
using(ReturnableScope(declaration.descriptor)) { using(ReturnableScope(declaration.symbol)) {
return super.visitFunctionNew(declaration) return super.visitFunctionNew(declaration)
} }
} }
@@ -101,7 +96,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
if (expression !is IrReturnableBlockImpl) if (expression !is IrReturnableBlockImpl)
return super.visitContainerExpression(expression) return super.visitContainerExpression(expression)
using(ReturnableScope(expression.descriptor)) { using(ReturnableScope(expression.symbol)) {
return super.visitContainerExpression(expression) return super.visitContainerExpression(expression)
} }
} }
@@ -142,7 +137,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
return performHighLevelJump( return performHighLevelJump(
targetScopePredicate = { it is ReturnableScope && it.descriptor == expression.returnTarget }, targetScopePredicate = { it is ReturnableScope && it.symbol == expression.returnTargetSymbol },
jump = Return(expression.returnTargetSymbol), jump = Return(expression.returnTargetSymbol),
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
@@ -184,7 +179,7 @@ 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 type = (jump as? Return)?.target?.owner?.returnType ?: value.type val type = (jump as? Return)?.target?.owner?.returnType ?: value.type
val symbol = getIrReturnableBlockSymbol(jump.toString(), type) val symbol = IrReturnableBlockSymbolImpl(WrappedSimpleFunctionDescriptor())
with(currentTryScope) { with(currentTryScope) {
irBuilder.run { irBuilder.run {
val inlinedFinally = irInlineFinally(symbol, type, expression, finallyExpression) val inlinedFinally = irInlineFinally(symbol, type, expression, finallyExpression)
@@ -223,14 +218,21 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
type = context.irBuiltIns.nothingType type = context.irBuiltIns.nothingType
) )
val transformedFinallyExpression = finallyExpression.transform(transformer, null) val transformedFinallyExpression = finallyExpression.transform(transformer, null)
val parameter = IrTemporaryVariableDescriptorImpl( val catchParameter = WrappedVariableDescriptor().let {
containingDeclaration = currentScope!!.scope.scopeOwner, IrVariableImpl(
name = Name.identifier("t"), startOffset, endOffset,
outType = context.builtIns.throwable.defaultType IrDeclarationOrigin.CATCH_PARAMETER,
) IrVariableSymbolImpl(it),
val catchParameter = IrVariableImpl( Name.identifier("t"),
startOffset, endOffset, IrDeclarationOrigin.CATCH_PARAMETER, parameter, symbols.throwable.owner.defaultType,
symbols.throwable.owner.defaultType) isVar = false,
isConst = false,
isLateinit = false
).apply {
it.bind(this)
parent = this@run.parent
}
}
val syntheticTry = IrTryImpl( val syntheticTry = IrTryImpl(
startOffset = startOffset, startOffset = startOffset,
@@ -240,7 +242,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
catches = listOf( catches = listOf(
irCatch(catchParameter).apply { irCatch(catchParameter).apply {
result = irBlock { result = irBlock {
+finallyExpression.copy() +copy(finallyExpression)
+irThrow(irGet(catchParameter)) +irThrow(irGet(catchParameter))
} }
}), }),
@@ -248,7 +250,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
) )
using(TryScope(syntheticTry, transformedFinallyExpression, this)) { using(TryScope(syntheticTry, transformedFinallyExpression, this)) {
val fallThroughType = aTry.type val fallThroughType = aTry.type
val fallThroughSymbol = getIrReturnableBlockSymbol("fallThrough", fallThroughType) val fallThroughSymbol = IrReturnableBlockSymbolImpl(WrappedSimpleFunctionDescriptor())
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) {
@@ -264,39 +266,32 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
private fun IrBuilderWithScope.irInlineFinally(symbol: IrReturnableBlockSymbol, type: IrType, private fun IrBuilderWithScope.irInlineFinally(symbol: IrReturnableBlockSymbol, type: IrType,
value: IrExpression, value: IrExpression,
finallyExpression: IrExpression): IrExpression { finallyExpression: IrExpression): IrExpression {
val returnType = symbol.descriptor.returnType!! val returnTypeClassifier = (type as? IrSimpleType)?.classifier
return when { return when (returnTypeClassifier) {
returnType.isUnit() || returnType.isNothing() -> irBlock(value, null, type) { symbols.unit, symbols.nothing -> irBlock(value, null, type) {
+irReturnableBlock(symbol, type) { +irReturnableBlock(symbol, type) {
+value +value
} }
+finallyExpression.copy() +copy(finallyExpression)
} }
else -> irBlock(value, null, type) { else -> irBlock(value, null, type) {
val tmp = irTemporary(irReturnableBlock(symbol, type) { val tmp = irTemporary(irReturnableBlock(symbol, type) {
+irReturn(symbol, value) +irReturn(symbol, value)
}) })
+finallyExpression.copy() +copy(finallyExpression)
+irGet(tmp) +irGet(tmp)
} }
} }
} }
private fun getFakeFunctionDescriptor(name: String, returnType: KotlinType) = private inline fun <reified T : IrElement> IrBuilderWithScope.copy(element: T) =
SimpleFunctionDescriptorImpl.create(currentScope!!.scope.scopeOwner, Annotations.EMPTY, name.synthesizedName, element.deepCopyWithVariables().setDeclarationsParent(parent)
CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE).apply {
initialize(null, null, emptyList(), emptyList(), returnType, Modality.ABSTRACT, Visibilities.PRIVATE)
}
private fun getIrReturnableBlockSymbol(name: String, returnType: IrType): IrReturnableBlockSymbol =
IrReturnableBlockSymbolImpl(getFakeFunctionDescriptor(name, returnType.toKotlinType()))
private inline fun <reified T : IrElement> T.copy() = this.deepCopyWithVariables()
fun IrBuilderWithScope.irReturn(target: IrReturnTargetSymbol, value: IrExpression) = fun IrBuilderWithScope.irReturn(target: IrReturnTargetSymbol, value: IrExpression) =
IrReturnImpl(startOffset, endOffset, context.irBuiltIns.nothingType, target, value) IrReturnImpl(startOffset, endOffset, context.irBuiltIns.nothingType, target, value)
inline fun IrBuilderWithScope.irReturnableBlock(symbol: IrReturnableBlockSymbol, type: IrType, body: IrBlockBuilder.() -> Unit) = private inline fun IrBuilderWithScope.irReturnableBlock(symbol: IrReturnableBlockSymbol,
type: IrType, body: IrBlockBuilder.() -> Unit) =
IrReturnableBlockImpl(startOffset, endOffset, type, symbol, null, IrReturnableBlockImpl(startOffset, endOffset, type, symbol, null,
IrBlockBuilder(context, scope, startOffset, endOffset, null, type) IrBlockBuilder(context, scope, startOffset, endOffset, null, type)
.block(body).statements) .block(body).statements)
@@ -10,6 +10,7 @@ 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.explicitParameters
import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole
import org.jetbrains.kotlin.backend.common.lower.CoroutineIntrinsicLambdaOrigin
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke
@@ -150,7 +151,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerWithC
if (!callSite.descriptor.needsInlining) if (!callSite.descriptor.needsInlining)
return callSite return callSite
val functionDescriptor = callSite.descriptor.resolveFakeOverride().original val functionDescriptor = callSite.descriptor.resolveFakeOverride().original
if (functionDescriptor == context.ir.symbols.isInitializedGetterDescriptor) if (callSite.symbol == context.ir.symbols.isInitializedGetter)
return callSite return callSite
val callee = getFunctionDeclaration(functionDescriptor) val callee = getFunctionDeclaration(functionDescriptor)
@@ -7,13 +7,12 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
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.descriptors.synthesizedName import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.isNonGeneratedAnnotation import org.jetbrains.kotlin.backend.konan.isNonGeneratedAnnotation
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.irDelegatingConstructorCall import org.jetbrains.kotlin.ir.builders.irDelegatingConstructorCall
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -21,10 +20,10 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* 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.symbols.impl.IrSimpleFunctionSymbolImpl
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.js.descriptorUtils.hasPrimaryConstructor
internal class InitializersLowering(val context: CommonBackendContext) : ClassLoweringPass { internal class InitializersLowering(val context: CommonBackendContext) : ClassLoweringPass {
@@ -41,8 +40,8 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
fun lowerInitializers() { fun lowerInitializers() {
collectAndRemoveInitializers() collectAndRemoveInitializers()
val initializerMethodSymbol = createInitializerMethod() val initializeMethodSymbol = createInitializerMethod()
lowerConstructors(initializerMethodSymbol) lowerConstructors(initializeMethodSymbol)
} }
private fun collectAndRemoveInitializers() { private fun collectAndRemoveInitializers() {
@@ -63,7 +62,9 @@ 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.irBuiltIns.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( IrGetValueImpl(
@@ -72,7 +73,8 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
), ),
initializer.expression, initializer.expression,
context.irBuiltIns.unitType, context.irBuiltIns.unitType,
STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER)))) STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER)))
)
declaration.initializer = null declaration.initializer = null
return declaration return declaration
} }
@@ -88,52 +90,54 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
private fun createInitializerMethod(): IrSimpleFunctionSymbol? { private fun createInitializerMethod(): IrSimpleFunctionSymbol? {
if (irClass.declarations.any { it is IrConstructor && it.isPrimary }) if (irClass.declarations.any { it is IrConstructor && it.isPrimary })
return null // Place initializers in the primary constructor. return null // Place initializers in the primary constructor.
val initializerMethodDescriptor = SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ irClass.descriptor,
/* annotations = */ Annotations.EMPTY,
/* name = */ "INITIALIZER".synthesizedName,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE)
initializerMethodDescriptor.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ irClass.descriptor.thisAsReceiverParameter,
/* typeParameters = */ listOf(),
/* unsubstitutedValueParameters = */ listOf(),
/* returnType = */ context.builtIns.unitType,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE)
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 initializeFun = WrappedSimpleFunctionDescriptor().let {
initializerMethodDescriptor, context.irBuiltIns.unitType) IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ANONYMOUS_INITIALIZER,
IrSimpleFunctionSymbolImpl(it),
"INITIALIZER".synthesizedName,
Visibilities.PRIVATE,
Modality.FINAL,
context.irBuiltIns.unitType,
isInline = false,
isSuspend = false,
isExternal = false,
isTailrec = false
).apply {
it.bind(this)
parent = irClass
irClass.declarations.add(this)
initializer.body = IrBlockBodyImpl(startOffset, endOffset, initializers) createDispatchReceiverParameter()
initializer.parent = irClass body = IrBlockBodyImpl(startOffset, endOffset, initializers)
initializer.createDispatchReceiverParameter() }
}
initializers.forEach { for (initializer in initializers) {
it.transformChildrenVoid(object : IrElementTransformerVoid() { initializer.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
if (expression.symbol == irClass.thisReceiver!!.symbol) { if (expression.symbol == irClass.thisReceiver!!.symbol) {
return IrGetValueImpl( return IrGetValueImpl(
expression.startOffset, expression.startOffset,
expression.endOffset, expression.endOffset,
initializer.dispatchReceiverParameter!!.type, initializeFun.dispatchReceiverParameter!!.type,
initializer.dispatchReceiverParameter!!.symbol initializeFun.dispatchReceiverParameter!!.symbol
) )
} }
return expression return expression
} }
}) })
initializer.patchDeclarationParents(initializeFun)
} }
irClass.declarations.add(initializer) return initializeFun.symbol
return initializer.symbol
} }
private fun lowerConstructors(initializerMethodSymbol: IrSimpleFunctionSymbol?) { private fun lowerConstructors(initializeMethodSymbol: IrSimpleFunctionSymbol?) {
if (irClass.kind == ClassKind.ANNOTATION_CLASS) { if (irClass.kind == ClassKind.ANNOTATION_CLASS) {
if (irClass.isNonGeneratedAnnotation()) return if (irClass.isNonGeneratedAnnotation()) return
@@ -158,14 +162,16 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
blockBody.statements.transformFlat { blockBody.statements.transformFlat {
when { when {
it is IrInstanceInitializerCall -> { it is IrInstanceInitializerCall -> {
if (initializerMethodSymbol == null) { if (initializeMethodSymbol == null) {
assert(declaration.descriptor.isPrimary) assert(declaration.isPrimary)
for (initializer in initializers)
initializer.patchDeclarationParents(declaration)
initializers initializers
} else { } else {
val startOffset = it.startOffset val startOffset = it.startOffset
val endOffset = it.endOffset val endOffset = it.endOffset
listOf(IrCallImpl(startOffset, endOffset, listOf(IrCallImpl(startOffset, endOffset,
context.irBuiltIns.unitType, initializerMethodSymbol context.irBuiltIns.unitType, initializeMethodSymbol
).apply { ).apply {
dispatchReceiver = IrGetValueImpl( dispatchReceiver = IrGetValueImpl(
startOffset, endOffset, startOffset, endOffset,
@@ -174,20 +180,24 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
}) })
} }
} }
/**
* IR for kotlin.Any is: /**
* BLOCK_BODY * IR for kotlin.Any is:
* DELEGATING_CONSTRUCTOR_CALL 'constructor Any()' * BLOCK_BODY
* INSTANCE_INITIALIZER_CALL classDescriptor='Any' * DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
* * INSTANCE_INITIALIZER_CALL classDescriptor='Any'
* to avoid possible recursion we manually reject body generation for Any. *
*/ * to avoid possible recursion we manually reject body generation for Any.
it is IrDelegatingConstructorCall && irClass.descriptor == context.builtIns.any */
&& it.descriptor == declaration.descriptor -> listOf() it is IrDelegatingConstructorCall
&& irClass.symbol == context.irBuiltIns.anyClass
&& it.symbol == declaration.symbol -> {
listOf()
}
else -> null else -> null
} }
} }
declaration.parent = irClass
return declaration return declaration
} }
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.lower.callsSuper import org.jetbrains.kotlin.backend.common.lower.callsSuper
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
@@ -21,9 +20,12 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
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.IrFieldSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.parentAsClass
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.scopes.receivers.ImplicitClassReceiver
internal class InnerClassLowering(val context: Context) : ClassLoweringPass { internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
override fun lower(irClass: IrClass) { override fun lower(irClass: IrClass) {
@@ -31,12 +33,10 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
} }
private inner class InnerClassTransformer(val irClass: IrClass) { private inner class InnerClassTransformer(val irClass: IrClass) {
val classDescriptor = irClass.descriptor
lateinit var outerThisFieldSymbol: IrFieldSymbol lateinit var outerThisFieldSymbol: IrFieldSymbol
fun lowerInnerClass() { fun lowerInnerClass() {
if (!irClass.descriptor.isInner) return if (!irClass.isInner) return
createOuterThisField() createOuterThisField()
lowerOuterThisReferences() lowerOuterThisReferences()
@@ -84,10 +84,9 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
val implicitThisClass = expression.descriptor.getClassDescriptorForImplicitThis() ?: val implicitThisClass = (expression.symbol.owner.parent as? IrClass) ?: return expression
return expression
if (implicitThisClass == classDescriptor) return expression if (implicitThisClass == irClass) return expression
val constructorSymbol = currentFunction!!.scope.scopeOwnerSymbol as? IrConstructorSymbol val constructorSymbol = currentFunction!!.scope.scopeOwnerSymbol as? IrConstructorSymbol
@@ -97,27 +96,27 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
var irThis: IrExpression var irThis: IrExpression
var innerClass: IrClass var innerClass: IrClass
if (constructorSymbol == null || constructorSymbol.descriptor.constructedClass != classDescriptor) { if (constructorSymbol == null || constructorSymbol.owner.parentAsClass != irClass) {
innerClass = irClass 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 thisParameter = if (currentFunctionReceiver?.descriptor == irClass.thisReceiver!!.descriptor) { val thisParameter =
currentFunctionReceiver if (currentFunctionReceiver?.type?.classifierOrNull == irClass.symbol)
} else { currentFunctionReceiver
irClass.thisReceiver!! else
} irClass.thisReceiver!!
irThis = IrGetValueImpl(startOffset, endOffset, thisParameter.type, thisParameter.symbol, 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 = irClass.parent as? IrClass ?: innerClass = irClass.parent as? IrClass ?:
throw AssertionError("No containing class for inner class $classDescriptor") throw AssertionError("No containing class for inner class ${irClass.dump()}")
val thisParameter = constructorSymbol.owner.dispatchReceiverParameter!! val thisParameter = constructorSymbol.owner.dispatchReceiverParameter!!
irThis = IrGetValueImpl(startOffset, endOffset, thisParameter.type, thisParameter.symbol, origin) irThis = IrGetValueImpl(startOffset, endOffset, thisParameter.type, thisParameter.symbol, origin)
} }
while (innerClass.descriptor != implicitThisClass) { while (innerClass != 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.
@@ -134,23 +133,13 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
val outer = innerClass.parent val outer = innerClass.parent
innerClass = outer as? IrClass ?: innerClass = outer as? IrClass ?:
throw AssertionError("Unexpected containing declaration for inner class ${innerClass.descriptor}: $outer") throw AssertionError("Unexpected containing declaration for inner class ${innerClass.dump()}: $outer")
} }
return irThis return irThis
} }
}) })
} }
private fun ValueDescriptor.getClassDescriptorForImplicitThis(): ClassDescriptor? {
if (this is ReceiverParameterDescriptor) {
val receiverValue = value
if (receiverValue is ImplicitClassReceiver) {
return receiverValue.classDescriptor
}
}
return null
}
} }
} }
@@ -9,10 +9,7 @@ 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.Context import org.jetbrains.kotlin.backend.konan.Context
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.backend.konan.irasdescriptors.isReal
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
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.* import org.jetbrains.kotlin.ir.declarations.*
@@ -21,45 +18,29 @@ 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.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.util.dump
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.name.Name
internal class LateinitLowering( internal class LateinitLowering(
val context: Context, val context: Context,
private val generateParameterNameInAssertion: Boolean = false private val generateParameterNameInAssertion: Boolean = false
) : FileLoweringPass { ) : FileLoweringPass {
private val isInitializedGetterDescriptor = context.ir.symbols.isInitializedGetterDescriptor private val isInitializedGetter = context.ir.symbols.isInitializedGetter
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 {
declaration.transformChildrenVoid(this) declaration.transformChildrenVoid(this)
val descriptor = declaration.descriptor if (!declaration.isLateinit) return declaration
if (!descriptor.isLateInit) return declaration
assert(declaration.initializer == null, { "'lateinit' modifier is not allowed for variables with initializer" }) assert(declaration.initializer == null) {
assert(!KotlinBuiltIns.isPrimitiveType(descriptor.type), { "'lateinit' modifier is not allowed on primitive types" }) "'lateinit' modifier is not allowed for variables with initializer"
}
builder.at(declaration).run { builder.at(declaration).run {
declaration.initializer = irNull() declaration.initializer = irNull()
} }
@@ -68,16 +49,14 @@ internal class LateinitLowering(
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
val symbol = expression.symbol val symbol = expression.symbol
val descriptor = symbol.descriptor as? VariableDescriptor if (symbol !is IrVariableSymbol || !symbol.owner.isLateinit) return expression
if (descriptor == null || !descriptor.isLateInit) return expression
assert(!KotlinBuiltIns.isPrimitiveType(descriptor.type), { "'lateinit' modifier is not allowed on primitive types" })
builder.at(expression).run { builder.at(expression).run {
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(expression.type, symbol)), irEqualsNull(irGet(expression.type, symbol)),
throwUninitializedPropertyAccessException(symbol) throwUninitializedPropertyAccessException(symbol.owner.name)
) )
+irGet(expression.type, symbol) +irGet(expression.type, symbol)
} }
@@ -87,17 +66,17 @@ internal class LateinitLowering(
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
val descriptor = expression.descriptor if (expression.symbol != isInitializedGetter) return expression
if (descriptor != isInitializedGetterDescriptor) return expression
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) {
val propertyDescriptor = propertyReference.descriptor.resolveFakeOverride().original "'lateinit' modifier is not allowed on extension properties"
}
val getter = propertyReference.getter?.owner ?: TODO(propertyReference.dump())
val property = getter.resolveFakeOverride().correspondingProperty!!
val type = propertyDescriptor.type
assert(!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" })
builder.at(expression).run { builder.at(expression).run {
val field = lateinitPropertyToField[propertyDescriptor]!! val field = property.backingField!!
val fieldValue = irGetField(propertyReference.dispatchReceiver, field) val fieldValue = irGetField(propertyReference.dispatchReceiver, field)
return irNotEquals(fieldValue, irNull()) return irNotEquals(fieldValue, irNull())
} }
@@ -106,13 +85,15 @@ internal class LateinitLowering(
override fun visitProperty(declaration: IrProperty): IrStatement { override fun visitProperty(declaration: IrProperty): IrStatement {
declaration.transformChildrenVoid(this) declaration.transformChildrenVoid(this)
if (!declaration.descriptor.isLateInit || !declaration.descriptor.kind.isReal) if (!declaration.isLateinit || !declaration.isReal)
return declaration return declaration
val backingField = declaration.backingField!! val backingField = declaration.backingField!!
transformGetter(backingField, 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)
irBuilder.run { irBuilder.run {
backingField.initializer = irExprBody(irNull()) backingField.initializer = irExprBody(irNull())
@@ -122,8 +103,6 @@ internal class LateinitLowering(
} }
private fun transformGetter(backingField: IrField, getter: IrFunction) { private fun transformGetter(backingField: IrField, getter: IrFunction) {
val type = backingField.descriptor.type
assert(!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" })
val irBuilder = context.createIrBuilder(getter.symbol, getter.startOffset, getter.endOffset) val irBuilder = context.createIrBuilder(getter.symbol, getter.startOffset, getter.endOffset)
irBuilder.run { irBuilder.run {
getter.body = irBlockBody { getter.body = irBlockBody {
@@ -134,7 +113,7 @@ internal class LateinitLowering(
context.irBuiltIns.nothingType, context.irBuiltIns.nothingType,
irNotEquals(irGet(resultVar), irNull()), irNotEquals(irGet(resultVar), irNull()),
irReturn(irGet(resultVar)), irReturn(irGet(resultVar)),
throwUninitializedPropertyAccessException(backingField.symbol) throwUninitializedPropertyAccessException(backingField.name)
) )
} }
} }
@@ -142,7 +121,7 @@ internal class LateinitLowering(
}) })
} }
private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(backingFieldSymbol: IrSymbol) = private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(name: Name) =
irCall(throwErrorFunction, context.irBuiltIns.nothingType).apply { irCall(throwErrorFunction, context.irBuiltIns.nothingType).apply {
if (generateParameterNameInAssertion) { if (generateParameterNameInAssertion) {
putValueArgument( putValueArgument(
@@ -151,7 +130,7 @@ internal class LateinitLowering(
startOffset, startOffset,
endOffset, endOffset,
context.irBuiltIns.stringType, context.irBuiltIns.stringType,
backingFieldSymbol.descriptor.name.asString() name.asString()
) )
) )
} }
@@ -8,19 +8,20 @@ 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.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.irGetObject import org.jetbrains.kotlin.ir.builders.irGetObject
import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.IrConstructor
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.expressions.IrBlockBody import org.jetbrains.kotlin.ir.expressions.IrBlockBody
import org.jetbrains.kotlin.ir.types.classifierOrNull
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.types.typeUtil.isUnit
internal class ReturnsInsertionLowering(val context: Context) : FileLoweringPass { internal class ReturnsInsertionLowering(val context: Context) : FileLoweringPass {
private val symbols = context.ir.symbols
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
irFile.acceptVoid(object : IrElementVisitorVoid { irFile.acceptVoid(object : IrElementVisitorVoid {
@@ -32,10 +33,10 @@ internal class ReturnsInsertionLowering(val context: Context) : FileLoweringPass
declaration.acceptChildrenVoid(this) declaration.acceptChildrenVoid(this)
val body = declaration.body val body = declaration.body
if ((declaration.descriptor is ConstructorDescriptor || declaration.descriptor.returnType!!.isUnit()) && body != null) { if ((declaration is IrConstructor || declaration.returnType.classifierOrNull == symbols.unit) && body != null) {
val irBuilder = context.createIrBuilder(declaration.symbol, declaration.startOffset, declaration.endOffset) val irBuilder = context.createIrBuilder(declaration.symbol, declaration.startOffset, declaration.endOffset)
irBuilder.run { irBuilder.run {
(body as IrBlockBody).statements += irReturn(irGetObject(this@ReturnsInsertionLowering.context.ir.symbols.unit)) (body as IrBlockBody).statements += irReturn(irGetObject(symbols.unit))
} }
} }
} }
@@ -1,127 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.visitors.*
import java.util.*
object CoroutineIntrinsicLambdaOrigin: IrStatementOriginImpl("Coroutine intrinsic lambda")
// TODO: Fix .parent for variables and use from common backend.
class SharedVariablesLowering(val context: BackendContext) : FunctionLoweringPass {
override fun lower(irFunction: IrFunction) {
SharedVariablesTransformer(irFunction).lowerSharedVariables()
}
private inner class SharedVariablesTransformer(val irFunction: IrFunction) {
val sharedVariables = mutableSetOf<IrVariable>()
fun lowerSharedVariables() {
collectSharedVariables()
if (sharedVariables.isEmpty()) return
rewriteSharedVariables()
}
private fun collectSharedVariables() {
irFunction.acceptVoid(object : IrElementVisitorVoid {
val relevantVars = mutableSetOf<IrVariable>()
val functionsVariables = mutableListOf<MutableSet<IrVariable>>()
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitFunction(declaration: IrFunction) {
functionsVariables.push(mutableSetOf())
declaration.acceptChildrenVoid(this)
functionsVariables.pop()
}
override fun visitContainerExpression(expression: IrContainerExpression) {
if (expression !is IrReturnableBlock || expression.origin != CoroutineIntrinsicLambdaOrigin)
super.visitContainerExpression(expression)
else {
functionsVariables.push(mutableSetOf())
expression.acceptChildrenVoid(this)
functionsVariables.pop()
}
}
override fun visitVariable(declaration: IrVariable) {
declaration.acceptChildrenVoid(this)
if (declaration.isVar) {
relevantVars.add(declaration)
functionsVariables.peek()!!.add(declaration)
}
}
override fun visitVariableAccess(expression: IrValueAccessExpression) {
expression.acceptChildrenVoid(this)
val value = expression.symbol.owner
//if (descriptor in relevantVars && descriptor.containingDeclaration != currentDeclaration) {
// TODO: fix lowerings to match check `(value as IrVariable).parent != currentDeclaration`
if (value in relevantVars && !functionsVariables.peek()!!.contains(value)) {
sharedVariables.add(value as IrVariable)
}
}
})
}
private fun rewriteSharedVariables() {
val transformedVariableSymbols = HashMap<IrValueSymbol, IrVariableSymbol>()
irFunction.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitVariable(declaration: IrVariable): IrStatement {
declaration.transformChildrenVoid(this)
if (declaration !in sharedVariables) return declaration
val newDeclaration = context.sharedVariablesManager.declareSharedVariable(declaration)
transformedVariableSymbols[declaration.symbol] = newDeclaration.symbol
return context.sharedVariablesManager.defineSharedValue(declaration, newDeclaration)
}
})
irFunction.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this)
val newSymbol = getTransformedSymbol(expression.symbol) ?: return expression
return context.sharedVariablesManager.getSharedValue(newSymbol, expression)
}
override fun visitSetVariable(expression: IrSetVariable): IrExpression {
expression.transformChildrenVoid(this)
val newDescriptor = getTransformedSymbol(expression.symbol) ?: return expression
return context.sharedVariablesManager.setSharedValue(newDescriptor, expression)
}
private fun getTransformedSymbol(oldSymbol: IrValueSymbol): IrVariableSymbol? =
transformedVariableSymbols.getOrElse(oldSymbol) {
assert(oldSymbol.owner !in sharedVariables) {
"Shared variable is not transformed: $oldSymbol"
}
null
}
})
}
}
}
@@ -5,47 +5,38 @@
package org.jetbrains.kotlin.backend.konan.lower package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.descriptors.replace import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.ir.createFakeOverrideDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.lower.SymbolWithIrBuilder
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.reportWarning 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.fqNameSafe
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWithStarProjections import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWithStarProjections
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWithoutArguments import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWithoutArguments
import org.jetbrains.kotlin.backend.konan.SYNTHETIC_OFFSET import org.jetbrains.kotlin.backend.konan.SYNTHETIC_OFFSET
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.isFunctionType
import org.jetbrains.kotlin.descriptors.* 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.ClassDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.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.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.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.*
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
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
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.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
internal class TestProcessor (val context: KonanBackendContext) { internal class TestProcessor (val context: KonanBackendContext) {
@@ -60,72 +51,65 @@ internal class TestProcessor (val context: KonanBackendContext) {
val IGNORE_FQ_NAME = FqName.fromSegments(listOf("kotlin", "test" , "Ignore")) val IGNORE_FQ_NAME = FqName.fromSegments(listOf("kotlin", "test" , "Ignore"))
} }
val symbols = context.ir.symbols private val symbols = context.ir.symbols
val baseClassSuiteDescriptor = symbols.baseClassSuite.descriptor private val baseClassSuite = symbols.baseClassSuite.owner
private val topLevelSuiteNames = mutableSetOf<String>() private val topLevelSuiteNames = mutableSetOf<String>()
// region Useful extensions. // region Useful extensions.
var testSuiteCnt = 0 private var testSuiteCnt = 0
fun Name.synthesizeSuiteClassName() = identifier.synthesizeSuiteClassName() private fun Name.synthesizeSuiteClassName() = identifier.synthesizeSuiteClassName()
fun String.synthesizeSuiteClassName() = "$this\$test\$${testSuiteCnt++}".synthesizedName private fun String.synthesizeSuiteClassName() = "$this\$test\$${testSuiteCnt++}".synthesizedName
// IrFile always uses a forward slash as a directory separator. // IrFile always uses a forward slash as a directory separator.
private val IrFile.fileName private val IrFile.fileName
get() = name.substringAfterLast('/') get() = name.substringAfterLast('/')
private val IrFile.topLevelSuiteName: String private val IrFile.topLevelSuiteName: String
get() { get() {
val packageFqName = packageFragmentDescriptor.fqName val packageFqName = fqName
val shortFileName = PackagePartClassUtils.getFilePartShortName(fileName) val shortFileName = PackagePartClassUtils.getFilePartShortName(fileName)
return if (packageFqName.isRoot) shortFileName else "$packageFqName.$shortFileName" return if (packageFqName.isRoot) shortFileName else "$packageFqName.$shortFileName"
} }
private fun MutableList<TestFunction>.registerFunction( private fun MutableList<TestFunction>.registerFunction(
function: IrFunctionSymbol, function: IrFunction,
kinds: Collection<Pair<FunctionKind, /* ignored: */ Boolean>>) = kinds: Collection<Pair<FunctionKind, /* ignored: */ Boolean>>) =
kinds.forEach { (kind, ignored) -> kinds.forEach { (kind, ignored) ->
add(TestFunction(function, kind, ignored)) add(TestFunction(function, kind, ignored))
} }
private fun MutableList<TestFunction>.registerFunction( private fun MutableList<TestFunction>.registerFunction(
function: IrFunctionSymbol, function: IrFunction,
kind: FunctionKind, kind: FunctionKind,
ignored: Boolean ignored: Boolean
) = add(TestFunction(function, kind, ignored)) ) = add(TestFunction(function, kind, ignored))
private fun <T: IrElement> IrStatementsBuilder<T>.generateFunctionRegistration( private fun <T: IrElement> IrStatementsBuilder<T>.generateFunctionRegistration(
receiver: IrValueDeclaration, receiver: IrValueDeclaration,
registerTestCase: IrFunctionSymbol, registerTestCase: IrFunction,
registerFunction: IrFunctionSymbol, registerFunction: IrFunction,
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, registerTestCase.descriptor.returnType!!.toErasedIrType()).apply { +irCall(registerTestCase).apply {
dispatchReceiver = irGet(receiver) dispatchReceiver = irGet(receiver)
putValueArgument(0, IrConstImpl.string( putValueArgument(0, irString(it.function.name.identifier))
SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET,
context.irBuiltIns.stringType,
it.function.descriptor.name.identifier)
)
putValueArgument(1, IrFunctionReferenceImpl( putValueArgument(1, IrFunctionReferenceImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
descriptor.valueParameters[1].type.toErasedIrType(), registerTestCase.valueParameters[1].type,
it.function, it.function.symbol,
it.function.descriptor, 0)) it.function.descriptor,
putValueArgument(2, IrConstImpl.boolean( typeArgumentsCount = 0,
SYNTHETIC_OFFSET, valueArgumentsCount = 0))
SYNTHETIC_OFFSET, putValueArgument(2, irBoolean(it.ignored))
context.irBuiltIns.booleanType,
it.ignored
))
} }
} else { } else {
// Call registerFunction(kind: TestFunctionKind, () -> Unit) method. // Call registerFunction(kind: TestFunctionKind, () -> Unit) method.
+irCall(registerFunction, registerFunction.descriptor.returnType!!.toErasedIrType()).apply { +irCall(registerFunction).apply {
dispatchReceiver = irGet(receiver) dispatchReceiver = irGet(receiver)
val testKindEntry = it.kind.runtimeKind val testKindEntry = it.kind.runtimeKind
putValueArgument(0, IrGetEnumValueImpl( putValueArgument(0, IrGetEnumValueImpl(
@@ -134,12 +118,13 @@ internal class TestProcessor (val context: KonanBackendContext) {
symbols.testFunctionKind.typeWithoutArguments, symbols.testFunctionKind.typeWithoutArguments,
testKindEntry) testKindEntry)
) )
putValueArgument(1, IrFunctionReferenceImpl( putValueArgument(1, IrFunctionReferenceImpl(SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET, registerFunction.valueParameters[1].type,
descriptor.valueParameters[1].type.toErasedIrType(), it.function.symbol,
it.function, it.function.descriptor,
it.function.descriptor, 0)) typeArgumentsCount = 0,
valueArgumentsCount = 0))
} }
} }
} }
@@ -149,7 +134,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
// region Classes for annotation collection. // region Classes for annotation collection.
internal enum class FunctionKind(annotationNameString: String, runtimeKindString: String) { internal enum class FunctionKind(annotationNameString: String, runtimeKindString: String) {
TEST("kotlin.test.Test", "") { TEST("kotlin.test.Test", "") {
override val runtimeKindName: Name get() = throw NotImplementedError() override val runtimeKindName: Name get() = throw NotImplementedError()
}, },
BEFORE_EACH("kotlin.test.BeforeEach", "BEFORE_EACH"), BEFORE_EACH("kotlin.test.BeforeEach", "BEFORE_EACH"),
@@ -169,34 +154,34 @@ internal class TestProcessor (val context: KonanBackendContext) {
private val FunctionKind.runtimeKind: IrEnumEntrySymbol private val FunctionKind.runtimeKind: IrEnumEntrySymbol
get() = symbols.getTestFunctionKind(this) get() = symbols.getTestFunctionKind(this)
private fun IrType.isTestFunctionKind() = classifierOrNull == symbols.testFunctionKind
private data class TestFunction( private data class TestFunction(
val function: IrFunctionSymbol, val function: IrFunction,
val kind: FunctionKind, val kind: FunctionKind,
val ignored: Boolean val ignored: Boolean
) )
private inner class TestClass(val ownerClass: IrClassSymbol) { private inner class TestClass(val ownerClass: IrClass) {
var companion: IrClassSymbol? = null var companion: IrClass? = null
val functions = mutableListOf<TestFunction>() val functions = mutableListOf<TestFunction>()
fun registerFunction( fun registerFunction(
function: IrFunctionSymbol, function: IrFunction,
kinds: Collection<Pair<FunctionKind, /* ignored: */ Boolean>> kinds: Collection<Pair<FunctionKind, /* ignored: */ Boolean>>
) = functions.registerFunction(function, kinds) ) = functions.registerFunction(function, kinds)
fun registerFunction(function: IrFunctionSymbol, kind: FunctionKind, ignored: Boolean) =
fun registerFunction(function: IrFunction, kind: FunctionKind, ignored: Boolean) =
functions.registerFunction(function, kind, ignored) functions.registerFunction(function, kind, ignored)
} }
private inner class AnnotationCollector(val irFile: IrFile) : IrElementVisitorVoid { private inner class AnnotationCollector(val irFile: IrFile) : IrElementVisitorVoid {
val testClasses = mutableMapOf<IrClassSymbol, TestClass>() val testClasses = mutableMapOf<IrClass, TestClass>()
val topLevelFunctions = mutableListOf<TestFunction>() val topLevelFunctions = mutableListOf<TestFunction>()
private fun MutableMap<IrClassSymbol, TestClass>.getTestClass(key: IrClassSymbol) = private fun MutableMap<IrClass, TestClass>.getTestClass(key: IrClass) =
getOrPut(key) { TestClass(key) } getOrPut(key) { TestClass(key) }
private fun MutableMap<IrClassSymbol, TestClass>.getTestClass(key: ClassDescriptor) =
getTestClass(symbols.symbolTable.referenceClass(key))
override fun visitElement(element: IrElement) { override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this) element.acceptChildrenVoid(this)
} }
@@ -227,45 +212,50 @@ internal class TestProcessor (val context: KonanBackendContext) {
} }
} }
fun registerClassFunction(classDescriptor: ClassDescriptor, fun registerClassFunction(irClass: IrClass,
function: IrFunctionSymbol, function: IrFunction,
kinds: Collection<Pair<FunctionKind, /* ignored: */ Boolean>>) { kinds: Collection<Pair<FunctionKind, /* ignored: */ Boolean>>) {
fun warn(msg: String) = context.reportWarning(msg, irFile, function.owner) fun warn(msg: String) = context.reportWarning(msg, irFile, function)
kinds.forEach { (kind, ignored) -> kinds.forEach { (kind, ignored) ->
val annotation = kind.annotationFqName val annotation = kind.annotationFqName
when (kind) { when (kind) {
in FunctionKind.INSTANCE_KINDS -> with(classDescriptor) { in FunctionKind.INSTANCE_KINDS -> with(irClass) {
when { when {
isInner -> isInner ->
warn("Annotation $annotation is not allowed for methods of an inner class") warn("Annotation $annotation is not allowed for methods of an inner class")
isAbstract() -> { isAbstract() -> {
// We cannot create an abstract test class but it's allowed to mark its methods as // We cannot create an abstract test class but it's allowed to mark its methods as
// tests because the class can be extended. So skip this case without warnings. // tests because the class can be extended. So skip this case without warnings.
} }
isCompanionObject ->
isCompanion ->
warn("Annotation $annotation is not allowed for methods of a companion object") warn("Annotation $annotation is not allowed for methods of a companion object")
constructors.none { it.valueParameters.size == 0 } -> constructors.none { it.valueParameters.size == 0 } ->
warn("Test class has no default constructor: ${fqNameSafe}") warn("Test class has no default constructor: $fqNameSafe")
else -> else ->
testClasses.getTestClass(classDescriptor).registerFunction(function, kind, ignored) testClasses.getTestClass(irClass).registerFunction(function, kind, ignored)
} }
} }
in FunctionKind.COMPANION_KINDS -> in FunctionKind.COMPANION_KINDS ->
when { when {
classDescriptor.isCompanionObject -> { irClass.isCompanion -> {
val containingClass = classDescriptor.containingDeclaration as ClassDescriptor val containingClass = irClass.parentAsClass
val testClass = testClasses.getTestClass(containingClass) val testClass = testClasses.getTestClass(containingClass)
testClass.companion = symbols.symbolTable.referenceClass(classDescriptor) testClass.companion = irClass
testClass.registerFunction(function, kind, ignored) testClass.registerFunction(function, kind, ignored)
} }
classDescriptor.kind == ClassKind.OBJECT -> {
testClasses.getTestClass(classDescriptor).registerFunction(function, kind, ignored) irClass.kind == ClassKind.OBJECT -> {
testClasses.getTestClass(irClass).registerFunction(function, kind, ignored)
} }
else -> warn("Annotation $annotation is only allowed for methods of an object " + else -> warn("Annotation $annotation is only allowed for methods of an object " +
"(named or companion) or top level functions") "(named or companion) or top level functions")
} }
else -> throw IllegalStateException("Unreachable") else -> throw IllegalStateException("Unreachable")
} }
@@ -274,14 +264,14 @@ internal class TestProcessor (val context: KonanBackendContext) {
fun IrFunction.checkFunctionSignature() { fun IrFunction.checkFunctionSignature() {
// Test runner requires test functions to have the following signature: () -> Unit. // Test runner requires test functions to have the following signature: () -> Unit.
if (descriptor.returnType != context.builtIns.unitType) { if (!returnType.isUnit()) {
context.reportCompilationError( context.reportCompilationError(
"Test function must return Unit: ${descriptor.fqNameSafe}", irFile, this "Test function must return Unit: $fqNameSafe", irFile, this
) )
} }
if (descriptor.valueParameters.isNotEmpty()) { if (valueParameters.isNotEmpty()) {
context.reportCompilationError( context.reportCompilationError(
"Test function must have no arguments: ${descriptor.fqNameSafe}", irFile, this "Test function must have no arguments: $fqNameSafe", irFile, this
) )
} }
} }
@@ -314,7 +304,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
// TODO: Use symbols instead of containingDeclaration when such information is available. // TODO: Use symbols instead of containingDeclaration when such information is available.
override fun visitFunction(declaration: IrFunction) { override fun visitFunction(declaration: IrFunction) {
val symbol = declaration.symbol val symbol = declaration.symbol
val owner = declaration.descriptor.containingDeclaration val parent = declaration.parent
warnAboutLoneIgnore(symbol) warnAboutLoneIgnore(symbol)
val kinds = FunctionKind.values().mapNotNull { kind -> val kinds = FunctionKind.values().mapNotNull { kind ->
@@ -329,10 +319,10 @@ internal class TestProcessor (val context: KonanBackendContext) {
} }
declaration.checkFunctionSignature() declaration.checkFunctionSignature()
when (owner) { when (parent) {
is PackageFragmentDescriptor -> topLevelFunctions.registerFunction(symbol, kinds) is IrPackageFragment -> topLevelFunctions.registerFunction(declaration, kinds)
is ClassDescriptor -> registerClassFunction(owner, symbol, kinds) is IrClass -> registerClassFunction(parent, declaration, kinds)
else -> UnsupportedOperationException("Cannot create test function $declaration (defined in $owner") else -> UnsupportedOperationException("Cannot create test function $declaration (defined in $parent")
} }
} }
} }
@@ -340,60 +330,36 @@ internal class TestProcessor (val context: KonanBackendContext) {
//region Symbol and IR builders //region Symbol and IR builders
/** Base class for getters (createInstance and getCompanion). */
private abstract inner class GetterBuilder(val returnType: IrType,
val testSuite: IrClassSymbol,
val getterName: Name)
: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrFunction>() {
val superFunction = baseClassSuiteDescriptor
.unsubstitutedMemberScope
.getContributedFunctions(getterName, NoLookupLocation.FROM_BACKEND)
.single { it.valueParameters.isEmpty() }
override fun doInitialize() {
val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl
descriptor.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ testSuite.descriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(),
/* unsubstitutedValueParameters = */ emptyList(),
/* returnType = */ returnType.toKotlinType(),
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PROTECTED
).apply {
overriddenDescriptors += superFunction
}
}
override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ testSuite.descriptor,
/* annotations = */ Annotations.EMPTY,
/* name = */ getterName,
/* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED,
/* source = */ SourceElement.NO_SOURCE
)
)
}
/** /**
* Builds a method in `[testSuite]` class with name `[getterName]` * Builds a method in `[owner]` class with name `[getterName]`
* 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 fun buildObjectGetter(objectSymbol: IrClassSymbol,
: GetterBuilder(objectSymbol.typeWithoutArguments, testSuite, getterName) { owner: IrClass,
getterName: Name) = WrappedSimpleFunctionDescriptor().let { descriptor ->
override fun buildIr(): IrFunction = IrFunctionImpl( IrFunctionImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
TEST_SUITE_GENERATED_MEMBER, TEST_SUITE_GENERATED_MEMBER,
symbol, IrSimpleFunctionSymbolImpl(descriptor),
this@ObjectGetterBuilder.returnType getterName,
Visibilities.PROTECTED,
Modality.FINAL,
objectSymbol.typeWithStarProjections,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false
).apply { ).apply {
val builder = context.createIrBuilder(symbol) descriptor.bind(this)
createParameterDeclarations(context.ir.symbols.symbolTable) parent = owner
body = builder.irBlockBody {
val superFunction = baseClassSuite.simpleFunctions()
.single { it.name == getterName && it.valueParameters.isEmpty() }
createDispatchReceiverParameter()
overriddenSymbols += superFunction.symbol
body = context.createIrBuilder(symbol).irBlockBody {
+irReturn(IrGetObjectValueImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, +irReturn(IrGetObjectValueImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
objectSymbol.typeWithoutArguments, objectSymbol) objectSymbol.typeWithoutArguments, objectSymbol)
) )
@@ -405,234 +371,202 @@ internal class TestProcessor (val context: KonanBackendContext) {
* Builds a method in `[testSuite]` class with name `[getterName]` * Builds a method in `[testSuite]` class with name `[getterName]`
* 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 fun buildInstanceGetter(classSymbol: IrClassSymbol,
: GetterBuilder(classSymbol.typeWithStarProjections, testSuite, getterName) { owner: IrClass,
getterName: Name) = WrappedSimpleFunctionDescriptor().let { descriptor ->
override fun buildIr() = IrFunctionImpl( IrFunctionImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
TEST_SUITE_GENERATED_MEMBER, TEST_SUITE_GENERATED_MEMBER,
symbol, IrSimpleFunctionSymbolImpl(descriptor),
this@InstanceGetterBuilder.returnType getterName,
Visibilities.PROTECTED,
Modality.FINAL,
classSymbol.typeWithStarProjections,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false
).apply { ).apply {
val builder = context.createIrBuilder(symbol) descriptor.bind(this)
createParameterDeclarations(context.ir.symbols.symbolTable) parent = owner
body = builder.irBlockBody {
val superFunction = baseClassSuite.simpleFunctions()
.single { it.name == getterName && it.valueParameters.isEmpty() }
createDispatchReceiverParameter()
overriddenSymbols += superFunction.symbol
body = context.createIrBuilder(symbol).irBlockBody {
val constructor = classSymbol.owner.constructors.single { it.valueParameters.isEmpty() } val constructor = classSymbol.owner.constructors.single { it.valueParameters.isEmpty() }
+irReturn(irCall(constructor)) +irReturn(irCall(constructor))
} }
} }
} }
private val baseClassSuiteConstructor = baseClassSuite.constructors.single {
it.valueParameters.size == 2
&& it.valueParameters[0].type.isString() // name: String
&& it.valueParameters[1].type.isBoolean() // ignored: Boolean
}
/** /**
* Builds a constructor for a test suite class representing a test class (any class in the original IrFile with * Builds a constructor for 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> * method(s) annotated with @Test). The test suite class is a subclass of ClassTestSuite<T>
* where T is the test class. * where T is the test class.
*/ */
private inner class ClassSuiteConstructorBuilder(val suiteName: String, private fun buildClassSuiteConstructor(suiteName: String,
val testClassType: KotlinType, testClassType: IrType,
val testCompanionType: KotlinType, testCompanionType: IrType,
val testSuite: IrClassSymbol, testSuite: IrClassSymbol,
val functions: Collection<TestFunction>, owner: IrClass,
val ignored: Boolean) functions: Collection<TestFunction>,
: SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() { ignored: Boolean) = WrappedClassConstructorDescriptor().let { descriptor ->
IrConstructorImpl(
private fun IrClassSymbol.getFunction(name: String, predicate: (FunctionDescriptor) -> Boolean) =
symbols.symbolTable.referenceFunction(descriptor.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND)
.single(predicate))
override fun buildIr() = IrConstructorImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
TEST_SUITE_GENERATED_MEMBER, TEST_SUITE_GENERATED_MEMBER,
symbol, IrConstructorSymbolImpl(descriptor),
testSuite.typeWithStarProjections Name.special("<init>"),
Visibilities.PUBLIC,
testSuite.typeWithStarProjections,
isInline = false,
isExternal = false,
isPrimary = true
).apply { ).apply {
descriptor.bind(this)
parent = owner
createParameterDeclarations(context.ir.symbols.symbolTable) fun IrClass.getFunction(name: String, predicate: (IrSimpleFunction) -> Boolean) =
simpleFunctions().single { it.name.asString() == name && predicate(it) }
val registerTestCase = symbols.baseClassSuite.getFunction("registerTestCase") { val registerTestCase = baseClassSuite.getFunction("registerTestCase") {
it.valueParameters.size == 3 && it.valueParameters.size == 3
KotlinBuiltIns.isString(it.valueParameters[0].type) && // name: String && it.valueParameters[0].type.isString() // name: String
it.valueParameters[1].type.isFunctionType && // function: testClassType.() -> Unit && it.valueParameters[1].type.isFunction() // function: testClassType.() -> Unit
KotlinBuiltIns.isBoolean(it.valueParameters[2].type) // ignored: Boolean && it.valueParameters[2].type.isBoolean() // ignored: Boolean
} }
val registerFunction = symbols.baseClassSuite.getFunction("registerFunction") { val registerFunction = 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.isTestFunctionKind() // kind: TestFunctionKind
it.valueParameters[1].type.isFunctionType // function: () -> Unit && it.valueParameters[1].type.isFunction() // function: () -> Unit
} }
body = context.createIrBuilder(symbol).irBlockBody { body = context.createIrBuilder(symbol).irBlockBody {
val superConstructor = symbols.baseClassSuiteConstructor +irDelegatingConstructorCall(baseClassSuiteConstructor).apply {
+IrDelegatingConstructorCallImpl( putTypeArgument(0, testClassType)
startOffset = SYNTHETIC_OFFSET, putTypeArgument(1, testCompanionType)
endOffset = SYNTHETIC_OFFSET,
type = context.irBuiltIns.unitType,
symbol = symbols.symbolTable.referenceConstructor(superConstructor),
descriptor = superConstructor,
typeArgumentsCount = 2
).apply {
putTypeArgument(0, testClassType.toErasedIrType())
putTypeArgument(1, testCompanionType.toErasedIrType())
putValueArgument(0, IrConstImpl.string( putValueArgument(0, irString(suiteName))
SYNTHETIC_OFFSET, putValueArgument(1, irBoolean(ignored))
SYNTHETIC_OFFSET,
context.irBuiltIns.stringType,
suiteName)
)
putValueArgument(1, IrConstImpl.boolean(
SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET,
context.irBuiltIns.booleanType,
ignored
))
} }
generateFunctionRegistration(testSuite.owner.thisReceiver!!, generateFunctionRegistration(testSuite.owner.thisReceiver!!,
registerTestCase, registerFunction, functions) registerTestCase, registerFunction, functions)
} }
} }
override fun doInitialize() {
val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
descriptor.initialize(emptyList(), Visibilities.PUBLIC).apply {
returnType = testSuite.descriptor.defaultType
}
}
override fun buildSymbol() = IrConstructorSymbolImpl(
ClassConstructorDescriptorImpl.createSynthesized(
testSuite.descriptor,
Annotations.EMPTY,
true,
SourceElement.NO_SOURCE
)
)
} }
private fun KotlinType.toErasedIrType(): IrType = context.ir.translateErased(this) private val IrClass.ignored: Boolean get() = descriptor.annotations.hasAnnotation(IGNORE_FQ_NAME)
/** /**
* 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.
*/ */
private inner class ClassSuiteBuilder(testClass: IrClassSymbol, private fun buildClassSuite(testClass: IrClass,
testCompanion: IrClassSymbol?, testCompanion: IrClass?,
val containingDeclaration: DeclarationDescriptor, functions: Collection<TestFunction>) = WrappedClassDescriptor().let { descriptor ->
val functions: Collection<TestFunction>) IrClassImpl(
: SymbolWithIrBuilder<IrClassSymbol, IrClass>() { SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
private val IrClassSymbol.ignored: Boolean get() = descriptor.annotations.hasAnnotation(IGNORE_FQ_NAME)
private val IrClassSymbol.isObject: Boolean get() = descriptor.kind == ClassKind.OBJECT
val suiteName = testClass.descriptor.fqNameSafe.toString()
val suiteClassName = testClass.descriptor.name.synthesizeSuiteClassName()
val testClassType = testClass.descriptor.defaultType
val testCompanionType = if (testClass.isObject) {
testClassType
} else {
testCompanion?.descriptor?.defaultType ?: context.irBuiltIns.nothing
}
val superType = baseClassSuiteDescriptor.defaultType.replace(listOf(testClassType, testCompanionType))
val constructorBuilder = ClassSuiteConstructorBuilder(
suiteName, testClassType, testCompanionType, symbol, functions, testClass.ignored
)
val instanceGetterBuilder: GetterBuilder
val companionGetterBuilder: GetterBuilder?
init {
if (testClass.isObject) {
instanceGetterBuilder = ObjectGetterBuilder(testClass, symbol, INSTANCE_GETTER_NAME)
companionGetterBuilder = ObjectGetterBuilder(testClass, symbol, COMPANION_GETTER_NAME)
} else {
instanceGetterBuilder = InstanceGetterBuilder(testClass, symbol, INSTANCE_GETTER_NAME)
companionGetterBuilder = testCompanion?.let {
ObjectGetterBuilder(it, symbol, COMPANION_GETTER_NAME)
}
}
}
override fun buildIr() = symbols.symbolTable.declareClass(
SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET,
TEST_SUITE_CLASS, TEST_SUITE_CLASS,
symbol.descriptor).apply { IrClassSymbolImpl(descriptor),
testClass.name.synthesizeSuiteClassName(),
ClassKind.CLASS,
Visibilities.PRIVATE,
Modality.FINAL,
isCompanion = false,
isInner = false,
isData = false,
isExternal = false,
isInline = false
).apply {
descriptor.bind(this)
createParameterDeclarations() createParameterDeclarations()
addMember(constructorBuilder.ir)
addMember(instanceGetterBuilder.ir)
companionGetterBuilder?.let { addMember(it.ir) }
addFakeOverrides(symbols.symbolTable)
setSuperSymbols(symbols.symbolTable)
}
override fun doInitialize() { val testClassType = testClass.defaultType
val descriptor = symbol.descriptor as ClassDescriptorImpl val testCompanionType = if (testClass.kind == ClassKind.OBJECT) {
val constructorDescriptor = constructorBuilder.symbol.descriptor testClassType
} else {
testCompanion?.defaultType ?: context.irBuiltIns.nothingType
}
val contributedDescriptors = baseClassSuiteDescriptor val constructor = buildClassSuiteConstructor(
.unsubstitutedMemberScope testClass.fqNameSafe.toString(), testClassType, testCompanionType,
.getContributedDescriptors() symbol, this, functions, testClass.ignored
.map {
when {
it == instanceGetterBuilder.superFunction -> instanceGetterBuilder.symbol.descriptor
it == companionGetterBuilder?.superFunction -> companionGetterBuilder.symbol.descriptor
else -> it.createFakeOverrideDescriptor(symbol.descriptor as ClassDescriptorImpl)
}
}.filterNotNull()
descriptor.initialize(
SimpleMemberScope(contributedDescriptors),setOf(constructorDescriptor), constructorDescriptor
) )
constructorBuilder.initialize() val instanceGetter: IrFunction
instanceGetterBuilder.initialize() val companionGetter: IrFunction?
companionGetterBuilder?.initialize()
}
override fun buildSymbol() = symbols.symbolTable.referenceClass( if (testClass.kind == ClassKind.OBJECT) {
ClassDescriptorImpl( instanceGetter = buildObjectGetter(testClass.symbol, this, INSTANCE_GETTER_NAME)
/* containingDeclaration = */ containingDeclaration, companionGetter = buildObjectGetter(testClass.symbol, this, COMPANION_GETTER_NAME)
/* name = */ suiteClassName, } else {
/* modality = */ Modality.FINAL, instanceGetter = buildInstanceGetter(testClass.symbol, this, INSTANCE_GETTER_NAME)
/* kind = */ ClassKind.CLASS, companionGetter = testCompanion?.let {
/* superTypes = */ listOf(superType), buildObjectGetter(it.symbol, this, COMPANION_GETTER_NAME)
/* source = */ SourceElement.NO_SOURCE, }
/* isExternal = */ false, }
/* storageManager = */ LockBasedStorageManager.NO_LOCKS
) declarations += constructor
) declarations += instanceGetter
companionGetter?.let { declarations += it }
superTypes += symbols.baseClassSuite.typeWith(listOf(testClassType, testCompanionType))
addFakeOverrides()
}
} }
//endregion //endregion
// region IR generation methods // region IR generation methods
private fun generateClassSuite(irFile: IrFile, testClass: TestClass) = private fun generateClassSuite(irFile: IrFile, testClass: TestClass) =
with(ClassSuiteBuilder(testClass.ownerClass, with(buildClassSuite(testClass.ownerClass, testClass.companion,testClass.functions)) {
testClass.companion, irFile.addChild(this)
irFile.packageFragmentDescriptor, val irConstructor = constructors.single()
testClass.functions)) { context.createIrBuilder(irFile.symbol).run {
initialize() irFile.addTopLevelInitializer(
irFile.addChild(ir) irCall(irConstructor),
val irConstructor = ir.constructors.single() this@TestProcessor.context,
irFile.addTopLevelInitializer( threadLocal = true)
IrCallImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, irConstructor.returnType, irConstructor.symbol), }
context, threadLocal = true)
} }
/** Check if this fqName already used or not. */ /** Check if this fqName already used or not. */
private fun checkSuiteName(irFile: IrFile, name: String): Boolean { private fun checkSuiteName(irFile: IrFile, name: String): Boolean {
if (topLevelSuiteNames.contains(name)) { if (topLevelSuiteNames.contains(name)) {
context.reportCompilationError("Package '${irFile.packageFragmentDescriptor.fqName}' has top-level test " + context.reportCompilationError("Package '${irFile.fqName}' has top-level test " +
"functions in several files with the same name: '${irFile.fileName}'") "functions in several files with the same name: '${irFile.fileName}'")
return false
} }
topLevelSuiteNames.add(name) topLevelSuiteNames.add(name)
return true return true
} }
private val topLevelSuite = symbols.topLevelSuite.owner
private val topLevelSuiteConstructor = topLevelSuite.constructors.single {
it.valueParameters.size == 1
&& it.valueParameters[0].type.isString()
}
private val topLevelSuiteRegisterFunction = topLevelSuite.simpleFunctions().single {
it.name.asString() == "registerFunction"
&& it.valueParameters.size == 2
&& it.valueParameters[0].type.isTestFunctionKind()
&& it.valueParameters[1].type.isFunction()
}
private val topLevelSuiteRegisterTestCase = topLevelSuite.simpleFunctions().single {
it.name.asString() == "registerTestCase"
&& it.valueParameters.size == 3
&& it.valueParameters[0].type.isString()
&& it.valueParameters[1].type.isFunction()
&& it.valueParameters[2].type.isBoolean()
}
private fun generateTopLevelSuite(irFile: IrFile, functions: Collection<TestFunction>) { private fun generateTopLevelSuite(irFile: IrFile, functions: Collection<TestFunction>) {
val builder = context.createIrBuilder(irFile.symbol) val builder = context.createIrBuilder(irFile.symbol)
val suiteName = irFile.topLevelSuiteName val suiteName = irFile.topLevelSuiteName
@@ -643,14 +577,14 @@ internal class TestProcessor (val context: KonanBackendContext) {
// TODO: an awful hack, we make this initializer thread local, so that it doesn't freeze suite, // TODO: an awful hack, we make this initializer thread local, so that it doesn't freeze suite,
// and later on we could modify some suite's properties. This shall be redesigned. // and later on we could modify some suite's properties. This shall be redesigned.
irFile.addTopLevelInitializer(builder.irBlock { irFile.addTopLevelInitializer(builder.irBlock {
val constructorCall = irCall(symbols.topLevelSuiteConstructor).apply { val constructorCall = irCall(topLevelSuiteConstructor).apply {
putValueArgument(0, IrConstImpl.string(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, putValueArgument(0, IrConstImpl.string(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
context.irBuiltIns.stringType, suiteName)) context.irBuiltIns.stringType, suiteName))
} }
val testSuiteVal = irTemporary(constructorCall, "topLevelTestSuite") val testSuiteVal = irTemporary(constructorCall, "topLevelTestSuite")
generateFunctionRegistration(testSuiteVal, generateFunctionRegistration(testSuiteVal,
symbols.topLevelSuiteRegisterTestCase, topLevelSuiteRegisterTestCase,
symbols.topLevelSuiteRegisterFunction, topLevelSuiteRegisterFunction,
functions) functions)
}, context, threadLocal = true) }, context, threadLocal = true)
} }
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedString import org.jetbrains.kotlin.backend.common.descriptors.synthesizedString
import org.jetbrains.kotlin.backend.common.ir.ir2string import org.jetbrains.kotlin.backend.common.ir.ir2string
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.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
@@ -38,7 +39,6 @@ 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.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
class VarargInjectionLowering constructor(val context: CommonBackendContext): DeclarationContainerLoweringPass { class VarargInjectionLowering constructor(val context: CommonBackendContext): DeclarationContainerLoweringPass {
override fun lower(irDeclarationContainer: IrDeclarationContainer) { override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.forEach{ irDeclarationContainer.declarations.forEach{
@@ -99,63 +99,53 @@ class VarargInjectionLowering constructor(val context: CommonBackendContext): De
override fun visitVararg(expression: IrVararg): IrExpression { override fun visitVararg(expression: IrVararg): IrExpression {
expression.transformChildrenVoid(transformer) expression.transformChildrenVoid(transformer)
val hasSpreadElement = hasSpreadElement(expression) val hasSpreadElement = hasSpreadElement(expression)
val irBuilder = context.createIrBuilder(owner, expression.startOffset, expression.endOffset) val irBuilder = context.createIrBuilder(owner, expression.startOffset, expression.endOffset)
irBuilder.run { return irBuilder.irBlock(expression, null, expression.type) {
val type = expression.varargElementType val type = expression.varargElementType
log { "$expression: array type:$type, is array of primitives ${!expression.type.isArray()}" } log { "$expression: array type:$type, is array of primitives ${!expression.type.isArray()}" }
val arrayHandle = arrayType(expression.type) val arrayHandle = arrayType(expression.type)
val block = irBlock(expression.type)
val vars = expression.elements.map { val vars = expression.elements.map {
val initVar = scope.createTemporaryVariable( it to irTemporaryVar(
(it as? IrSpreadElement)?.expression ?: it as IrExpression, (it as? IrSpreadElement)?.expression ?: it as IrExpression,
"elem".synthesizedString, true) "elem".synthesizedString
block.statements.add(initVar) )
it to initVar
}.toMap() }.toMap()
val arraySize = calculateArraySize(arrayHandle, hasSpreadElement, scope, expression, vars) val arraySize = calculateArraySize(arrayHandle, hasSpreadElement, scope, expression, vars)
val array = arrayHandle.createArray(this, expression.varargElementType, arraySize) val array = arrayHandle.createArray(this, expression.varargElementType, arraySize)
val arrayTmpVariable = scope.createTemporaryVariable(array, "array".synthesizedString, true) val arrayTmpVariable = irTemporaryVar(array, "array".synthesizedString)
val indexTmpVariable = scope.createTemporaryVariable(kIntZero, "index".synthesizedString, true) lateinit var indexTmpVariable: IrVariable
block.statements.add(arrayTmpVariable) if (hasSpreadElement)
if (hasSpreadElement) { indexTmpVariable = irTemporaryVar(kIntZero, "index".synthesizedString)
block.statements.add(indexTmpVariable)
}
expression.elements.forEachIndexed { i, element -> expression.elements.forEachIndexed { i, element ->
irBuilder.startOffset = element.startOffset irBuilder.at(element.startOffset, element.endOffset)
irBuilder.endOffset = element.endOffset log { "element:$i> ${ir2string(element)}" }
irBuilder.apply { val dst = vars[element]!!
log { "element:$i> ${ir2string(element)}" } if (element !is IrSpreadElement) {
val dst = vars[element]!! +irCall(arrayHandle.setMethodSymbol.owner).apply {
if (element !is IrSpreadElement) { dispatchReceiver = irGet(arrayTmpVariable)
val setArrayElementCall = irCall(arrayHandle.setMethodSymbol.owner) putValueArgument(0, if (hasSpreadElement) irGet(indexTmpVariable) else irConstInt(i))
setArrayElementCall.dispatchReceiver = irGet(arrayTmpVariable) putValueArgument(1, irGet(dst))
setArrayElementCall.putValueArgument(0, if (hasSpreadElement) irGet(indexTmpVariable) else irConstInt(i))
setArrayElementCall.putValueArgument(1, irGet(dst))
block.statements.add(setArrayElementCall)
if (hasSpreadElement) {
block.statements.add(incrementVariable(indexTmpVariable, kIntOne))
}
} else {
val arraySizeVariable = scope.createTemporaryVariable(irArraySize(arrayHandle, irGet(dst)), "length".synthesizedString)
block.statements.add(arraySizeVariable)
val copyCall = irCall(arrayHandle.copyRangeToSymbol.owner).apply {
extensionReceiver = irGet(dst)
putValueArgument(0, irGet(arrayTmpVariable)) /* destination */
putValueArgument(1, kIntZero) /* fromIndex */
putValueArgument(2, irGet(arraySizeVariable)) /* toIndex */
putValueArgument(3, irGet(indexTmpVariable)) /* destinationIndex */
}
block.statements.add(copyCall)
block.statements.add(incrementVariable(indexTmpVariable, irGet(arraySizeVariable)))
log { "element:$i:spread element> ${ir2string(element.expression)}" }
} }
if (hasSpreadElement)
+incrementVariable(indexTmpVariable, kIntOne)
} else {
val arraySizeVariable = irTemporary(irArraySize(arrayHandle, irGet(dst)), "length".synthesizedString)
+irCall(arrayHandle.copyRangeToSymbol.owner).apply {
extensionReceiver = irGet(dst)
putValueArgument(0, irGet(arrayTmpVariable)) /* destination */
putValueArgument(1, kIntZero) /* fromIndex */
putValueArgument(2, irGet(arraySizeVariable)) /* toIndex */
putValueArgument(3, irGet(indexTmpVariable)) /* destinationIndex */
}
+incrementVariable(indexTmpVariable, irGet(arraySizeVariable))
log { "element:$i:spread element> ${ir2string(element.expression)}" }
} }
} }
block.statements.add(irGet(arrayTmpVariable)) +irGet(arrayTmpVariable)
return block
} }
} }
}) })
@@ -273,6 +263,5 @@ class VarargInjectionLowering constructor(val context: CommonBackendContext): De
private fun IrBuilderWithScope.irConstInt(value: Int): IrConst<Int> = private fun IrBuilderWithScope.irConstInt(value: Int): IrConst<Int> =
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, value) IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, value)
private fun IrBuilderWithScope.irBlock(type: IrType): IrBlock = IrBlockImpl(startOffset, endOffset, type)
private val IrBuilderWithScope.kIntZero get() = irConstInt(0) private val IrBuilderWithScope.kIntZero get() = irConstInt(0)
private val IrBuilderWithScope.kIntOne get() = irConstInt(1) private val IrBuilderWithScope.kIntOne get() = irConstInt(1)
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
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.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark
@@ -37,7 +37,7 @@ internal class BackingFieldVisitor(val context: Context) : IrElementVisitorVoid
override fun visitClass(declaration: IrClass) { override fun visitClass(declaration: IrClass) {
if (declaration.isInner) if (declaration.isInner)
declaration.addChild(context.specialDeclarationsFactory.getOuterThisField(declaration)) declaration.declarations += context.specialDeclarationsFactory.getOuterThisField(declaration)
// Mark all dangling fields (they are created when class is inherited via delegation). // Mark all dangling fields (they are created when class is inherited via delegation).
declaration.declarations.filterIsInstance<IrField>().forEach { declaration.declarations.filterIsInstance<IrField>().forEach {
@@ -6,22 +6,21 @@
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.common.descriptors.*
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
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.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
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.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor 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.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.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.* import org.jetbrains.kotlin.ir.declarations.impl.*
@@ -30,14 +29,15 @@ 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.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection 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.name.Name
import org.jetbrains.kotlin.resolve.OverridingStrategy
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.calls.checkers.isRestrictsSuspensionReceiver import org.jetbrains.kotlin.resolve.calls.checkers.isRestrictsSuspensionReceiver
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -50,38 +50,29 @@ internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrC
private var topLevelInitializersCounter = 0 private var topLevelInitializersCounter = 0
internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: KonanBackendContext, threadLocal: Boolean) { internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: KonanBackendContext, threadLocal: Boolean) {
val fieldDescriptor = PropertyDescriptorImpl.create( val descriptor = WrappedFieldDescriptor(
this.packageFragmentDescriptor,
if (threadLocal) if (threadLocal)
Annotations.create(listOf(AnnotationDescriptorImpl(context.ir.symbols.threadLocal.defaultType, Annotations.create(listOf(AnnotationDescriptorImpl(context.ir.symbols.threadLocal.defaultType,
emptyMap(), SourceElement.NO_SOURCE))) emptyMap(), SourceElement.NO_SOURCE)))
else else
Annotations.EMPTY, Annotations.EMPTY
Modality.FINAL,
Visibilities.PRIVATE,
false,
"topLevelInitializer${topLevelInitializersCounter++}".synthesizedName,
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE,
false,
false,
false,
false,
false,
false
) )
fieldDescriptor.setType(expression.type.toKotlinType(), emptyList(), null, null)
fieldDescriptor.initialize(null, null)
val irField = IrFieldImpl( val irField = IrFieldImpl(
expression.startOffset, expression.endOffset, expression.startOffset, expression.endOffset,
IrDeclarationOrigin.DEFINED, fieldDescriptor, expression.type IrDeclarationOrigin.DEFINED,
) IrFieldSymbolImpl(descriptor),
"topLevelInitializer${topLevelInitializersCounter++}".synthesizedName,
expression.type,
Visibilities.PRIVATE,
isFinal = true,
isExternal = false,
isStatic = true
).apply {
descriptor.bind(this)
irField.initializer = IrExpressionBodyImpl(expression.startOffset, expression.endOffset, expression) initializer = IrExpressionBodyImpl(expression.startOffset, expression.endOffset, expression)
}
this.addChild(irField) addChild(irField)
} }
fun IrClass.addFakeOverrides(symbolTable: SymbolTable) { fun IrClass.addFakeOverrides(symbolTable: SymbolTable) {
@@ -155,72 +146,6 @@ fun IrFunction.createParameterDeclarations(symbolTable: SymbolTable) {
} }
} }
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, returnType
).also {
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: ReferenceSymbolTable) { fun IrSimpleFunction.setOverrides(symbolTable: ReferenceSymbolTable) {
assert(this.overriddenSymbols.isEmpty()) assert(this.overriddenSymbols.isEmpty())
@@ -229,44 +154,6 @@ fun IrSimpleFunction.setOverrides(symbolTable: ReferenceSymbolTable) {
} }
} }
fun IrClass.simpleFunctions(): List<IrSimpleFunction> = this.declarations.flatMap {
when (it) {
is IrSimpleFunction -> listOf(it)
is IrProperty -> listOfNotNull(it.getter, it.setter)
else -> emptyList()
}
}
fun IrClass.createParameterDeclarations() {
thisReceiver = IrValueParameterImpl(
startOffset, endOffset,
IrDeclarationOrigin.INSTANCE_RECEIVER,
descriptor.thisAsReceiverParameter,
this.symbol.typeWith(this.typeParameters.map { it.defaultType }),
null
).also { valueParameter ->
valueParameter.parent = this
}
assert(typeParameters.isEmpty())
assert(descriptor.declaredTypeParameters.isEmpty())
}
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) { fun IrClass.createParameterDeclarations(symbolTable: SymbolTable) {
this.descriptor.declaredTypeParameters.mapTo(this.typeParameters) { this.descriptor.declaredTypeParameters.mapTo(this.typeParameters) {
IrTypeParameterImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, it).apply { IrTypeParameterImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, it).apply {
@@ -283,29 +170,6 @@ fun IrClass.createParameterDeclarations(symbolTable: SymbolTable) {
) )
} }
fun IrClass.setSuperSymbols(superTypes: List<IrType>) {
val supers = superTypes.map { it.getClass()!! }
assert(this.superDescriptors().toSet() == supers.map { it.descriptor }.toSet())
assert(this.superTypes.isEmpty())
this.superTypes += superTypes
val superMembers = supers.flatMap {
it.simpleFunctions()
}.associateBy { it.descriptor }
this.simpleFunctions().forEach {
assert(it.overriddenSymbols.isEmpty())
it.descriptor.overriddenDescriptors.mapTo(it.overriddenSymbols) {
val superMember = superMembers[it.original] ?: error(it.original)
superMember.symbol
}
}
}
private fun IrClass.superDescriptors() =
this.descriptor.typeConstructor.supertypes.map { it.constructor.declarationDescriptor as ClassDescriptor }
fun IrClass.setSuperSymbols(symbolTable: ReferenceSymbolTable) { fun IrClass.setSuperSymbols(symbolTable: ReferenceSymbolTable) {
assert(this.superTypes.isEmpty()) assert(this.superTypes.isEmpty())
this.descriptor.typeConstructor.supertypes.mapTo(this.superTypes) { symbolTable.translateErased(it) } this.descriptor.typeConstructor.supertypes.mapTo(this.superTypes) { symbolTable.translateErased(it) }
@@ -315,52 +179,110 @@ fun IrClass.setSuperSymbols(symbolTable: ReferenceSymbolTable) {
} }
} }
fun IrClass.setSuperSymbolsAndAddFakeOverrides(superTypes: List<IrType>) { fun IrClass.simpleFunctions() = declarations.flatMap {
val overriddenSuperMembers = this.declarations.map { it.descriptor } when (it) {
.filterIsInstance<CallableMemberDescriptor>().flatMap { it.overriddenDescriptors.map { it.original } }.toSet() is IrSimpleFunction -> listOf(it)
is IrProperty -> listOfNotNull(it.getter, it.setter)
else -> emptyList()
}
}
val unoverriddenSuperMembers = superTypes.map { it.getClass()!! }.flatMap { fun IrClass.createParameterDeclarations() {
it.declarations.filter { it.descriptor !in overriddenSuperMembers }.mapNotNull { assert (thisReceiver == null)
when (it) {
is IrSimpleFunction -> it.descriptor to it thisReceiver = WrappedReceiverParameterDescriptor().let {
is IrProperty -> it.descriptor to it IrValueParameterImpl(
else -> null startOffset, endOffset,
IrDeclarationOrigin.INSTANCE_RECEIVER,
IrValueParameterSymbolImpl(it),
Name.special("<this>"),
0,
symbol.typeWith(typeParameters.map { it.defaultType }),
null,
false,
false
).apply {
it.bind(this)
parent = this@createParameterDeclarations
}
}
}
fun IrFunction.createDispatchReceiverParameter(origin: IrDeclarationOrigin? = null) {
assert(dispatchReceiverParameter == null)
dispatchReceiverParameter = WrappedReceiverParameterDescriptor().let {
IrValueParameterImpl(
startOffset, endOffset,
origin ?: parentAsClass.origin,
IrValueParameterSymbolImpl(it),
Name.special("<this>"),
0,
parentAsClass.defaultType,
null,
false,
false
).apply {
it.bind(this)
parent = this@createDispatchReceiverParameter
}
}
}
fun IrClass.addFakeOverrides() {
fun IrDeclaration.toList() = when (this) {
is IrSimpleFunction -> listOf(this)
is IrProperty -> listOfNotNull(getter, setter)
else -> emptyList()
}
val overriddenFunctions = declarations
.flatMap { it.toList() }
.flatMap { it.overriddenSymbols.map { it.owner } }
.toSet()
val unoverriddenSuperFunctions = superTypes
.map { it.getClass()!! }
.flatMap { irClass ->
irClass.declarations
.flatMap { it.toList() }
.filter { it !in overriddenFunctions }
} }
} .toMutableSet()
}.toMap()
val irClass = this // TODO: A dirty hack.
val groupedUnoverriddenSuperFunctions = unoverriddenSuperFunctions.groupBy { it.name.asString() + it.allParameters.size }
val overridingStrategy = object : OverridingStrategy() { fun createFakeOverride(overriddenFunctions: List<IrSimpleFunction>) =
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) { overriddenFunctions.first().let { irFunction ->
val overriddenDeclarations = val descriptor = WrappedSimpleFunctionDescriptor()
fakeOverride.overriddenDescriptors.map { unoverriddenSuperMembers[it]!! } IrFunctionImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
IrDeclarationOrigin.FAKE_OVERRIDE,
IrSimpleFunctionSymbolImpl(descriptor),
irFunction.name,
Visibilities.INHERITED,
Modality.OPEN,
irFunction.returnType,
irFunction.isInline,
irFunction.isExternal,
irFunction.isTailrec,
irFunction.isSuspend
).apply {
descriptor.bind(this)
parent = this@addFakeOverrides
overriddenSymbols += overriddenFunctions.map { it.symbol }
copyParameterDeclarationsFrom(irFunction)
}
}
assert(overriddenDeclarations.isNotEmpty()) val fakeOverriddenFunctions = groupedUnoverriddenSuperFunctions
.asSequence()
.associate { it.value.first() to createFakeOverride(it.value) }
.toMutableMap()
irClass.declarations.add(createFakeOverride(fakeOverride, overriddenDeclarations, irClass)) declarations += fakeOverriddenFunctions.values
}
override fun inheritanceConflict(first: CallableMemberDescriptor, second: CallableMemberDescriptor) {
error("inheritance conflict in synthesized class ${irClass.descriptor}:\n $first\n $second")
}
override fun overrideConflict(fromSuper: CallableMemberDescriptor, fromCurrent: CallableMemberDescriptor) {
error("override conflict in synthesized class ${irClass.descriptor}:\n $fromSuper\n $fromCurrent")
}
}
unoverriddenSuperMembers.keys.groupBy { it.name }.forEach { (name, members) ->
OverridingUtil.generateOverridesInFunctionGroup(
name,
members,
emptyList(),
this.descriptor,
overridingStrategy
)
}
this.setSuperSymbols(superTypes)
} }
private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int = private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int =
@@ -389,6 +311,11 @@ fun IrDeclarationContainer.addChild(declaration: IrDeclaration) {
declaration.accept(SetDeclarationsParentVisitor, this) declaration.accept(SetDeclarationsParentVisitor, this)
} }
fun <T: IrElement> T.setDeclarationsParent(parent: IrDeclarationParent): T {
accept(SetDeclarationsParentVisitor, parent)
return this
}
object SetDeclarationsParentVisitor : IrElementVisitor<Unit, IrDeclarationParent> { object SetDeclarationsParentVisitor : IrElementVisitor<Unit, IrDeclarationParent> {
override fun visitElement(element: IrElement, data: IrDeclarationParent) { override fun visitElement(element: IrElement, data: IrDeclarationParent) {
if (element !is IrDeclarationParent) { if (element !is IrDeclarationParent) {
@@ -612,25 +539,6 @@ fun IrMemberAccessExpression.getArgumentsWithIr(): List<Pair<IrValueParameter, I
return res 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 ReferenceSymbolTable.translateErased(type: KotlinType): IrSimpleType { fun ReferenceSymbolTable.translateErased(type: KotlinType): IrSimpleType {
val descriptor = TypeUtils.getClassDescriptor(type) val descriptor = TypeUtils.getClassDescriptor(type)
if (descriptor == null) return translateErased(type.immediateSupertypes().first()) if (descriptor == null) return translateErased(type.immediateSupertypes().first())
@@ -643,9 +551,9 @@ fun ReferenceSymbolTable.translateErased(type: KotlinType): IrSimpleType {
} }
fun CommonBackendContext.createArrayOfExpression( fun CommonBackendContext.createArrayOfExpression(
startOffset: Int, endOffset: Int,
arrayElementType: IrType, arrayElementType: IrType,
arrayElements: List<IrExpression>, arrayElements: List<IrExpression>
startOffset: Int, endOffset: Int
): IrExpression { ): IrExpression {
val arrayType = ir.symbols.array.typeWith(arrayElementType) val arrayType = ir.symbols.array.typeWith(arrayElementType)
@@ -659,34 +567,27 @@ fun CommonBackendContext.createArrayOfExpression(
fun createField( fun createField(
startOffset: Int, startOffset: Int,
endOffset: Int, endOffset: Int,
origin: IrDeclarationOrigin,
type: IrType, type: IrType,
name: Name, name: Name,
isMutable: Boolean, isMutable: Boolean,
origin: IrDeclarationOrigin, owner: IrClass
owner: ClassDescriptor ) = WrappedFieldDescriptor().let {
): IrField { IrFieldImpl(
val descriptor = PropertyDescriptorImpl.create( startOffset, endOffset,
/* containingDeclaration = */ owner, origin,
/* annotations = */ Annotations.EMPTY, IrFieldSymbolImpl(it),
/* modality = */ Modality.FINAL, name,
/* visibility = */ Visibilities.PRIVATE, type,
/* isVar = */ isMutable, Visibilities.PRIVATE,
/* name = */ name, !isMutable,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION, false,
/* source = */ SourceElement.NO_SOURCE, false
/* lateInit = */ false,
/* isConst = */ false,
/* isExpect = */ false,
/* isActual = */ false,
/* isExternal = */ false,
/* isDelegated = */ false
).apply { ).apply {
initialize(null, null) it.bind(this)
owner.declarations += this
setType(type.toKotlinType(), emptyList(), owner.thisAsReceiverParameter, null) parent = owner
} }
return IrFieldImpl(startOffset, endOffset, origin, descriptor, type)
} }
fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter { fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter {
@@ -710,16 +611,5 @@ val IrType.isSimpleTypeWithQuestionMark: Boolean
fun IrClass.defaultOrNullableType(hasQuestionMark: Boolean) = fun IrClass.defaultOrNullableType(hasQuestionMark: Boolean) =
if (hasQuestionMark) this.defaultType.makeNullable() else this.defaultType if (hasQuestionMark) this.defaultType.makeNullable() else this.defaultType
fun FunctionDescriptor.createOverriddenDescriptor(owner: ClassDescriptor, final: Boolean = true): FunctionDescriptor {
return this.newCopyBuilder()
.setOwner(owner)
.setCopyOverrides(true)
.setModality(if (final) Modality.FINAL else Modality.OPEN)
.setDispatchReceiverParameter(owner.thisAsReceiverParameter)
.build()!!.apply {
overriddenDescriptors = listOf(this@createOverriddenDescriptor)
}
}
fun IrFunction.isRestrictedSuspendFunction(languageVersionSettings: LanguageVersionSettings): Boolean = fun IrFunction.isRestrictedSuspendFunction(languageVersionSettings: LanguageVersionSettings): Boolean =
this.descriptor.extensionReceiverParameter?.type?.isRestrictsSuspensionReceiver(languageVersionSettings) == true this.descriptor.extensionReceiverParameter?.type?.isRestrictsSuspensionReceiver(languageVersionSettings) == true