[JS IR BE] Merge native fixes into Ir Serializer

This commit is contained in:
Roman Artemev
2019-02-07 14:56:31 +03:00
committed by romanart
parent 813fef6f26
commit 862ccd05df
19 changed files with 5241 additions and 4767 deletions
@@ -210,9 +210,8 @@ fun IrConstructor.callsSuper(irBuiltIns: IrBuiltIns): Boolean {
assert(++numberOfCalls == 1) { "More than one delegating constructor call: ${symbol.owner}" }
val delegatingClass = expression.symbol.owner.parent as IrClass
// TODO: figure out why Lazy IR multiplies Declarations for descriptors and fix it
if (delegatingClass.descriptor == superClass.classifierOrFail.descriptor || (
delegatingClass.defaultType.isAny() && superClass.isAny()
))
// It happens because of IrBuiltIns whose IrDeclarations are different for runtime and test
if (delegatingClass.descriptor == superClass.classifierOrFail.descriptor)
callsSuper = true
else if (delegatingClass.descriptor != constructedClass.descriptor)
throw AssertionError(
@@ -154,7 +154,7 @@ class JsIrBackendContext(
val coroutineSuspendOrReturn =
symbolTable.referenceSimpleFunction(getInternalFunctions(COROUTINE_SUSPEND_OR_RETURN_JS_NAME).single())
val intrinsics = JsIntrinsics(irBuiltIns, this)
val intrinsics by lazy { JsIntrinsics(irBuiltIns, this) }
private val operatorMap = referenceOperators()
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.ir.backend.js
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.common.CompilerPhaseManager
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.functionInterfacePackageFragmentProvider
@@ -85,7 +84,7 @@ fun compile(
TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext)
val symbolTable = SymbolTable()
// irDependencyModules.forEach { symbolTable.loadModule(it) }
if (!isKlibCompilation) irDependencyModules.forEach { symbolTable.loadModule(it) }
val psi2IrTranslator = Psi2IrTranslator(configuration.languageVersionSettings)
val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext, symbolTable)
@@ -105,6 +104,10 @@ fun compile(
if (isKlibCompilation) {
val logggg = object : LoggingContext {
override var inVerbosePhase: Boolean
get() = TODO("not implemented")
set(_) {}
override fun log(message: () -> String) {}
}
@@ -173,8 +176,7 @@ fun compile(
)
md.initialize(CompositePackageFragmentProvider(packageProviders))
md.setDependencies(listOf(md/*, builtIns.builtInsModule*/))
md.setDependencies(listOf(md))
val st = SymbolTable()
@@ -198,7 +200,7 @@ fun compile(
deserializedModuleFragment.replaceUnboundSymbols(context)
jsPhases.invokeToplevel(context.phaseConfig, context, moduleFragment)
jsPhases.invokeToplevel(context.phaseConfig, context, deserializedModuleFragment)
return Result(md, context.jsProgram.toString(), null)
} else {
@@ -55,9 +55,9 @@ fun ReferenceSymbolTable.translateErased(type: KotlinType): IrSimpleType {
internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
val typeArguments: Map<IrTypeParameterSymbol, IrType?>?,
val parent: IrDeclarationParent?) : IrCopierForInliner {
val parent: IrDeclarationParent?) {
override fun copy(irElement: IrElement): IrElement {
fun copy(irElement: IrElement): IrElement {
// Create new symbols.
irElement.acceptVoid(symbolRemapper)
@@ -205,8 +205,6 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
}
}
override fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) { }
private class SymbolRemapperImpl(descriptorsRemapper: DescriptorsRemapper)
: DeepCopySymbolRemapper(descriptorsRemapper) {
@@ -232,857 +230,4 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
InlinerTypeRemapper(symbolRemapper, typeArguments),
InlinerSymbolRenamer()
)
}
internal interface IrCopierForInliner {
fun copy(irElement: IrElement): IrElement
fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>)
}
internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
val parentDescriptor: DeclarationDescriptor,
val context: JsIrBackendContext,
val typeSubstitutor: TypeSubstitutor?) : IrCopierForInliner {
private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf()
private var nameIndex = 0
//-------------------------------------------------------------------------//
override fun copy(irElement: IrElement): IrElement {
// Create all class descriptors and all necessary descriptors in order to create KotlinTypes.
irElement.acceptVoid(DescriptorCollectorCreatePhase())
// Initialize all created descriptors possibly using previously created types.
irElement.acceptVoid(DescriptorCollectorInitPhase())
return irElement.accept(InlineCopyIr(), null)
}
inner class DescriptorCollectorCreatePhase : IrElementVisitorVoidWithContext() {
override fun visitElement(element: IrElement) {
element.acceptChildren(this, null)
}
//---------------------------------------------------------------------//
override fun visitClassNew(declaration: IrClass) {
val oldDescriptor = declaration.descriptor
val newDescriptor = copyClassDescriptor(oldDescriptor)
descriptorSubstituteMap[oldDescriptor] = newDescriptor
descriptorSubstituteMap[oldDescriptor.thisAsReceiverParameter] = newDescriptor.thisAsReceiverParameter
super.visitClassNew(declaration)
val constructors = oldDescriptor.constructors.map { oldConstructorDescriptor ->
descriptorSubstituteMap[oldConstructorDescriptor] as ClassConstructorDescriptor
}.toSet()
val oldPrimaryConstructor = oldDescriptor.unsubstitutedPrimaryConstructor
val primaryConstructor = oldPrimaryConstructor?.let { descriptorSubstituteMap[it] as ClassConstructorDescriptor }
val contributedDescriptors = oldDescriptor.unsubstitutedMemberScope
.getContributedDescriptors()
.map { descriptorSubstituteMap[it]!! }
newDescriptor.initialize(
SimpleMemberScope(contributedDescriptors),
constructors,
primaryConstructor
)
}
//---------------------------------------------------------------------//
override fun visitPropertyNew(declaration: IrProperty) {
copyPropertyOrField(declaration.descriptor)
super.visitPropertyNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitFieldNew(declaration: IrField) {
val oldDescriptor = declaration.descriptor
if (descriptorSubstituteMap[oldDescriptor] == null) {
copyPropertyOrField(oldDescriptor) // A field without a property or a field of a delegated property.
}
super.visitFieldNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitFunctionNew(declaration: IrFunction) {
val oldDescriptor = declaration.descriptor
if (oldDescriptor !is PropertyAccessorDescriptor) { // Property accessors are copied along with their property.
val oldContainingDeclaration =
if (oldDescriptor.visibility == Visibilities.LOCAL)
parentDescriptor
else
oldDescriptor.containingDeclaration
descriptorSubstituteMap[oldDescriptor] = copyFunctionDescriptor(oldDescriptor, oldContainingDeclaration)
}
super.visitFunctionNew(declaration)
}
//--- Copy descriptors ------------------------------------------------//
private fun generateCopyName(name: Name): Name {
val declarationName = name.toString() // Name of declaration
val indexStr = (nameIndex++).toString() // Unique for inline target index
return Name.identifier(declarationName + "_" + indexStr)
}
//---------------------------------------------------------------------//
private fun copyFunctionDescriptor(oldDescriptor: CallableDescriptor, oldContainingDeclaration: DeclarationDescriptor) =
when (oldDescriptor) {
is ConstructorDescriptor -> copyConstructorDescriptor(oldDescriptor)
is SimpleFunctionDescriptor -> copySimpleFunctionDescriptor(oldDescriptor, oldContainingDeclaration)
else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor")
}
//---------------------------------------------------------------------//
private fun copySimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor, oldContainingDeclaration: DeclarationDescriptor) : FunctionDescriptor {
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
return SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ newContainingDeclaration,
/* annotations = */ oldDescriptor.annotations,
/* name = */ generateCopyName(oldDescriptor.name),
/* kind = */ oldDescriptor.kind,
/* source = */ oldDescriptor.source
)
}
//---------------------------------------------------------------------//
private fun copyConstructorDescriptor(oldDescriptor: ConstructorDescriptor) : FunctionDescriptor {
val oldContainingDeclaration = oldDescriptor.containingDeclaration
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
return ClassConstructorDescriptorImpl.create(
/* containingDeclaration = */ newContainingDeclaration as ClassDescriptor,
/* annotations = */ oldDescriptor.annotations,
/* isPrimary = */ oldDescriptor.isPrimary,
/* source = */ oldDescriptor.source
)
}
//---------------------------------------------------------------------//
private fun copyPropertyOrField(oldDescriptor: PropertyDescriptor) {
val oldContainingDeclaration = oldDescriptor.containingDeclaration
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) as ClassDescriptor
@Suppress("DEPRECATION")
val newDescriptor = PropertyDescriptorImpl.create(
/* containingDeclaration = */ newContainingDeclaration,
/* annotations = */ oldDescriptor.annotations,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility,
/* isVar = */ oldDescriptor.isVar,
/* name = */ oldDescriptor.name,
/* kind = */ oldDescriptor.kind,
/* source = */ oldDescriptor.source,
/* lateInit = */ oldDescriptor.isLateInit,
/* isConst = */ oldDescriptor.isConst,
/* isExpect = */ oldDescriptor.isExpect,
/* isActual = */ oldDescriptor.isActual,
/* isExternal = */ oldDescriptor.isExternal,
/* isDelegated = */ oldDescriptor.isDelegated
)
descriptorSubstituteMap[oldDescriptor] = newDescriptor
}
//---------------------------------------------------------------------//
private fun copyClassDescriptor(oldDescriptor: ClassDescriptor): ClassDescriptorImpl {
val oldSuperClass = oldDescriptor.getSuperClassOrAny()
val newSuperClass = descriptorSubstituteMap.getOrDefault(oldSuperClass, oldSuperClass) as ClassDescriptor
val oldInterfaces = oldDescriptor.getSuperInterfaces()
val newInterfaces = oldInterfaces.map { descriptorSubstituteMap.getOrDefault(it, it) as ClassDescriptor }
val oldContainingDeclaration = oldDescriptor.containingDeclaration
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
val newName = if (DescriptorUtils.isAnonymousObject(oldDescriptor)) // Anonymous objects are identified by their name.
oldDescriptor.name // We need to preserve it for LocalDeclarationsLowering.
else
generateCopyName(oldDescriptor.name)
val visibility = oldDescriptor.visibility
return object : ClassDescriptorImpl(
/* containingDeclaration = */ newContainingDeclaration,
/* name = */ newName,
/* modality = */ oldDescriptor.modality,
/* kind = */ oldDescriptor.kind,
/* supertypes = */ listOf(newSuperClass.defaultType) + newInterfaces.map { it.defaultType },
/* source = */ oldDescriptor.source,
/* isExternal = */ oldDescriptor.isExternal,
/* storageManager = */ LockBasedStorageManager.NO_LOCKS
) {
override fun getVisibility() = visibility
override fun getDeclaredTypeParameters(): List<TypeParameterDescriptor> {
return oldDescriptor.declaredTypeParameters
}
}
}
}
//-------------------------------------------------------------------------//
inner class DescriptorCollectorInitPhase : IrElementVisitorVoidWithContext() {
private val initializedProperties = mutableSetOf<PropertyDescriptor>()
override fun visitElement(element: IrElement) {
element.acceptChildren(this, null)
}
//---------------------------------------------------------------------//
override fun visitPropertyNew(declaration: IrProperty) {
initPropertyOrField(declaration.descriptor)
super.visitPropertyNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitFieldNew(declaration: IrField) {
val oldDescriptor = declaration.descriptor
if (!initializedProperties.contains(oldDescriptor)) {
initPropertyOrField(oldDescriptor) // A field without a property or a field of a delegated property.
}
super.visitFieldNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitFunctionNew(declaration: IrFunction) {
val oldDescriptor = declaration.descriptor
if (oldDescriptor !is PropertyAccessorDescriptor) { // Property accessors are copied along with their property.
val newDescriptor = initFunctionDescriptor(oldDescriptor)
oldDescriptor.extensionReceiverParameter?.let {
descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!!
}
}
super.visitFunctionNew(declaration)
}
//---------------------------------------------------------------------//
override fun visitVariable(declaration: IrVariable) {
declaration.descriptor.let { descriptorSubstituteMap[it] = copyVariableDescriptor(it) }
super.visitVariable(declaration)
}
//---------------------------------------------------------------------//
override fun visitCatch(aCatch: IrCatch) {
aCatch.parameter.let { descriptorSubstituteMap[it] = copyVariableDescriptor(it) }
super.visitCatch(aCatch)
}
//--- Copy descriptors ------------------------------------------------//
private fun generateCopyName(name: Name): Name {
val declarationName = name.toString() // Name of declaration
val indexStr = (nameIndex++).toString() // Unique for inline target index
return Name.identifier(declarationName + "_" + indexStr)
}
//---------------------------------------------------------------------//
private fun copyVariableDescriptor(oldDescriptor: VariableDescriptor): VariableDescriptor {
val oldContainingDeclaration = oldDescriptor.containingDeclaration
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
return IrTemporaryVariableDescriptorImpl(
containingDeclaration = newContainingDeclaration,
name = generateCopyName(oldDescriptor.name),
outType = substituteType(oldDescriptor.type)!!,
isMutable = oldDescriptor.isVar
)
}
//---------------------------------------------------------------------//
private fun initFunctionDescriptor(oldDescriptor: CallableDescriptor): CallableDescriptor =
when (oldDescriptor) {
is ConstructorDescriptor -> initConstructorDescriptor(oldDescriptor)
is SimpleFunctionDescriptor -> initSimpleFunctionDescriptor(oldDescriptor)
else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor")
}
//---------------------------------------------------------------------//
private fun initSimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor): FunctionDescriptor =
(descriptorSubstituteMap[oldDescriptor] as SimpleFunctionDescriptorImpl).apply {
val oldDispatchReceiverParameter = oldDescriptor.dispatchReceiverParameter
val newDispatchReceiverParameter = oldDispatchReceiverParameter?.let { descriptorSubstituteMap.getOrDefault(it, it) as ReceiverParameterDescriptor }
val newTypeParameters = oldDescriptor.typeParameters // TODO substitute types
val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
val newReceiverParameterType = substituteType(oldDescriptor.extensionReceiverParameter?.type)
val newReturnType = substituteType(oldDescriptor.returnType)
initialize(
/* receiverParameterType = */ newReceiverParameterType.createExtensionReceiver(this),
/* dispatchReceiverParameter = */ newDispatchReceiverParameter,
/* typeParameters = */ newTypeParameters,
/* unsubstitutedValueParameters = */ newValueParameters,
/* unsubstitutedReturnType = */ newReturnType,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility
)
isTailrec = oldDescriptor.isTailrec
isSuspend = oldDescriptor.isSuspend
overriddenDescriptors += oldDescriptor.overriddenDescriptors
}
//---------------------------------------------------------------------//
private fun initConstructorDescriptor(oldDescriptor: ConstructorDescriptor): FunctionDescriptor =
(descriptorSubstituteMap[oldDescriptor] as ClassConstructorDescriptorImpl).apply {
val newTypeParameters = oldDescriptor.typeParameters
val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
val receiverParameterType = substituteType(oldDescriptor.dispatchReceiverParameter?.type)
val returnType = substituteType(oldDescriptor.returnType)
initialize(
/* receiverParameterType = */ receiverParameterType.createExtensionReceiver(this),
/* dispatchReceiverParameter = */ null, // For constructor there is no explicit dispatch receiver.
/* typeParameters = */ newTypeParameters,
/* unsubstitutedValueParameters = */ newValueParameters,
/* unsubstitutedReturnType = */ returnType,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility
)
}
//---------------------------------------------------------------------//
private fun initPropertyOrField(oldDescriptor: PropertyDescriptor) {
val newDescriptor = (descriptorSubstituteMap[oldDescriptor] as PropertyDescriptorImpl).apply {
setType(
/* outType = */ substituteType(oldDescriptor.type)!!,
/* typeParameters = */ oldDescriptor.typeParameters,
/* dispatchReceiverParameter = */ (containingDeclaration as ClassDescriptor).thisAsReceiverParameter,
/* extensionReceiverParamter = */ substituteType(oldDescriptor.extensionReceiverParameter?.type).createExtensionReceiver(this))
initialize(
/* getter = */ oldDescriptor.getter?.let { copyPropertyGetterDescriptor(it, this) },
/* setter = */ oldDescriptor.setter?.let { copyPropertySetterDescriptor(it, this) })
overriddenDescriptors += oldDescriptor.overriddenDescriptors
}
oldDescriptor.getter?.let { descriptorSubstituteMap[it] = newDescriptor.getter!! }
oldDescriptor.setter?.let { descriptorSubstituteMap[it] = newDescriptor.setter!! }
oldDescriptor.extensionReceiverParameter?.let {
descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!!
}
initializedProperties.add(oldDescriptor)
}
//---------------------------------------------------------------------//
private fun copyPropertyGetterDescriptor(oldDescriptor: PropertyGetterDescriptor, newPropertyDescriptor: PropertyDescriptor) =
PropertyGetterDescriptorImpl(
/* correspondingProperty = */ newPropertyDescriptor,
/* annotations = */ oldDescriptor.annotations,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility,
/* isDefault = */ oldDescriptor.isDefault,
/* isExternal = */ oldDescriptor.isExternal,
/* isInline = */ oldDescriptor.isInline,
/* kind = */ oldDescriptor.kind,
/* original = */ null,
/* source = */ oldDescriptor.source).apply {
initialize(substituteType(oldDescriptor.returnType))
}
//---------------------------------------------------------------------//
private fun copyPropertySetterDescriptor(oldDescriptor: PropertySetterDescriptor, newPropertyDescriptor: PropertyDescriptor) =
PropertySetterDescriptorImpl(
/* correspondingProperty = */ newPropertyDescriptor,
/* annotations = */ oldDescriptor.annotations,
/* modality = */ oldDescriptor.modality,
/* visibility = */ oldDescriptor.visibility,
/* isDefault = */ oldDescriptor.isDefault,
/* isExternal = */ oldDescriptor.isExternal,
/* isInline = */ oldDescriptor.isInline,
/* kind = */ oldDescriptor.kind,
/* original = */ null,
/* source = */ oldDescriptor.source).apply {
initialize(copyValueParameters(oldDescriptor.valueParameters, this).single())
}
//-------------------------------------------------------------------------//
private fun copyValueParameters(oldValueParameters: List <ValueParameterDescriptor>, containingDeclaration: CallableDescriptor) =
oldValueParameters.map { oldDescriptor ->
val newDescriptor = ValueParameterDescriptorImpl(
containingDeclaration = containingDeclaration,
original = oldDescriptor.original,
index = oldDescriptor.index,
annotations = oldDescriptor.annotations,
name = oldDescriptor.name,
outType = substituteType(oldDescriptor.type)!!,
declaresDefaultValue = oldDescriptor.declaresDefaultValue(),
isCrossinline = oldDescriptor.isCrossinline,
isNoinline = oldDescriptor.isNoinline,
varargElementType = substituteType(oldDescriptor.varargElementType),
source = oldDescriptor.source
)
descriptorSubstituteMap[oldDescriptor] = newDescriptor
newDescriptor
}
}
//-----------------------------------------------------------------------------//
@Suppress("DEPRECATION")
inner class InlineCopyIr : DeepCopyIrTree() {
override fun mapClassDeclaration (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
override fun mapTypeAliasDeclaration (descriptor: TypeAliasDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as TypeAliasDescriptor
override fun mapFunctionDeclaration (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
override fun mapConstructorDeclaration (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
override fun mapPropertyDeclaration (descriptor: PropertyDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as PropertyDescriptor
override fun mapLocalPropertyDeclaration (descriptor: VariableDescriptorWithAccessors) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptorWithAccessors
override fun mapEnumEntryDeclaration (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
override fun mapVariableDeclaration (descriptor: VariableDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptor
override fun mapErrorDeclaration (descriptor: DeclarationDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor)
override fun mapClassReference (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
override fun mapValueReference (descriptor: ValueDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ValueDescriptor
override fun mapVariableReference (descriptor: VariableDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptor
override fun mapPropertyReference (descriptor: PropertyDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as PropertyDescriptor
override fun mapCallee (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
override fun mapDelegatedConstructorCallee (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
override fun mapEnumConstructorCallee (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
override fun mapLocalPropertyReference (descriptor: VariableDescriptorWithAccessors) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptorWithAccessors
override fun mapClassifierReference (descriptor: ClassifierDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassifierDescriptor
override fun mapReturnTarget (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
//---------------------------------------------------------------------//
override fun mapSuperQualifier(qualifier: ClassDescriptor?): ClassDescriptor? {
if (qualifier == null) return null
return descriptorSubstituteMap.getOrDefault(qualifier, qualifier) as ClassDescriptor
}
//--- Visits ----------------------------------------------------------//
override fun visitCall(expression: IrCall): IrCall {
if (expression !is IrCallImpl) return super.visitCall(expression)
val newDescriptor = mapCallee(expression.descriptor)
return IrCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = context.symbolTable.translateErased(newDescriptor.returnType!!),
descriptor = newDescriptor,
typeArgumentsCount = expression.typeArgumentsCount,
origin = expression.origin,
superQualifierDescriptor = mapSuperQualifier(expression.superQualifier)
).apply {
transformValueArguments(expression)
substituteTypeArguments(expression)
}
}
override fun visitField(declaration: IrField): IrField {
val descriptor = mapPropertyDeclaration(declaration.descriptor)
return IrFieldImpl(
declaration.startOffset, declaration.endOffset,
mapDeclarationOrigin(declaration.origin),
descriptor,
context.symbolTable.translateErased(descriptor.type),
declaration.initializer?.transform(this@InlineCopyIr, null)
).apply {
transformAnnotations(declaration)
}
}
//---------------------------------------------------------------------//
override fun visitFunction(declaration: IrFunction) =
context.symbolTable.withScope(mapFunctionDeclaration(declaration.descriptor)) { descriptor ->
IrFunctionImpl(
startOffset = declaration.startOffset,
endOffset = declaration.endOffset,
origin = mapDeclarationOrigin(declaration.origin),
descriptor = descriptor,
returnType = declaration.returnType,
body = declaration.body?.transform(this@InlineCopyIr, null)
).also {
it.returnType = context.symbolTable.translateErased(descriptor.returnType!!)
it.setOverrides(context.symbolTable)
it.transformParameters(declaration)
}
}
// override fun visitSimpleFunction(declaration: IrSimpleFunction): IrFunction {
// val descriptor = mapFunctionDeclaration(declaration.descriptor)
// return IrFunctionImpl(
// startOffset = declaration.startOffset,
// endOffset = declaration.endOffset,
// origin = mapDeclarationOrigin(declaration.origin),
// descriptor = descriptor
// ).also {
// it.returnType = context.symbolTable.translateErased(descriptor.returnType!!)
// it.body = declaration.body?.transform(this, null)
//
// it.setOverrides(context.symbolTable)
// }.transformParameters1(declaration)
// }
// override fun visitConstructor(declaration: IrConstructor): IrConstructor {
// val descriptor = mapConstructorDeclaration(declaration.descriptor)
// return IrConstructorImpl(
// startOffset = declaration.startOffset,
// endOffset = declaration.endOffset,
// origin = mapDeclarationOrigin(declaration.origin),
// descriptor = descriptor
// ).also {
// it.returnType = context.symbolTable.translateErased(descriptor.returnType)
// it.body = declaration.body?.transform(this, null)
// }.transformParameters1(declaration)
// }
private fun FunctionDescriptor.getTypeParametersToTransform() =
when {
this is PropertyAccessorDescriptor -> correspondingProperty.typeParameters
else -> typeParameters
}
protected fun <T : IrFunction> T.transformParameters1(original: T): T =
apply {
transformTypeParameters(original, descriptor.getTypeParametersToTransform())
transformValueParameters1(original)
}
protected fun <T : IrFunction> T.transformValueParameters1(original: T) =
apply {
dispatchReceiverParameter =
original.dispatchReceiverParameter?.replaceDescriptor1(
descriptor.dispatchReceiverParameter ?: throw AssertionError("No dispatch receiver in $descriptor")
)
extensionReceiverParameter =
original.extensionReceiverParameter?.replaceDescriptor1(
descriptor.extensionReceiverParameter ?: throw AssertionError("No extension receiver in $descriptor")
)
original.valueParameters.mapIndexedTo(valueParameters) { i, originalValueParameter ->
originalValueParameter.replaceDescriptor1(descriptor.valueParameters[i])
}
}
protected fun IrValueParameter.replaceDescriptor1(newDescriptor: ParameterDescriptor) =
IrValueParameterImpl(
startOffset, endOffset,
mapDeclarationOrigin(origin),
newDescriptor,
context.symbolTable.translateErased(newDescriptor.type),
(newDescriptor as? ValueParameterDescriptor)?.varargElementType?.let { context.symbolTable.translateErased(it) },
defaultValue?.transform(this@InlineCopyIr, null)
).apply {
transformAnnotations(this)
}
//---------------------------------------------------------------------//
override fun visitGetValue(expression: IrGetValue): IrGetValue {
val descriptor = mapValueReference(expression.descriptor)
return IrGetValueImpl(
expression.startOffset, expression.endOffset,
context.symbolTable.translateErased(descriptor.type),
descriptor,
mapStatementOrigin(expression.origin)
)
}
override fun visitVariable(declaration: IrVariable): IrVariable {
val descriptor = mapVariableDeclaration(declaration.descriptor)
return IrVariableImpl(
declaration.startOffset, declaration.endOffset,
mapDeclarationOrigin(declaration.origin),
descriptor,
context.symbolTable.translateErased(descriptor.type),
declaration.initializer?.transform(this, null)
).apply {
transformAnnotations(declaration)
}
}
private fun <T : IrFunction> T.transformDefaults(original: T): T {
for (originalValueParameter in original.descriptor.valueParameters) {
val valueParameter = descriptor.valueParameters[originalValueParameter.index]
original.getDefault(originalValueParameter)?.let { irDefaultParameterValue ->
putDefault(valueParameter, irDefaultParameterValue.transform(this@InlineCopyIr, null))
}
}
return this
}
//---------------------------------------------------------------------//
fun getTypeOperatorReturnType(operator: IrTypeOperator, type: IrType) : IrType {
return when (operator) {
IrTypeOperator.CAST,
IrTypeOperator.IMPLICIT_CAST,
IrTypeOperator.IMPLICIT_NOTNULL,
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
IrTypeOperator.IMPLICIT_INTEGER_COERCION,
IrTypeOperator.SAM_CONVERSION -> type
IrTypeOperator.SAFE_CAST -> type.makeNullable()
IrTypeOperator.INSTANCEOF,
IrTypeOperator.NOT_INSTANCEOF -> context.irBuiltIns.booleanType
}
}
//---------------------------------------------------------------------//
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall {
val erasedTypeOperand = substituteAndEraseType(expression.typeOperand)!!
val typeOperand = substituteAndBreakType(expression.typeOperand)
val returnType = getTypeOperatorReturnType(expression.operator, erasedTypeOperand)
return IrTypeOperatorCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = returnType,
operator = expression.operator,
typeOperand = typeOperand,
argument = expression.argument.transform(this, null),
typeOperandClassifier = (typeOperand as IrSimpleType).classifier
)
}
//---------------------------------------------------------------------//
override fun visitReturn(expression: IrReturn): IrReturn =
IrReturnImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = substituteAndEraseType(expression.type)!!,
returnTargetDescriptor = mapReturnTarget(expression.returnTarget),
value = expression.value.transform(this, null)
)
//---------------------------------------------------------------------//
override fun visitBlock(expression: IrBlock): IrBlock {
return if (expression is IrReturnableBlock) {
IrReturnableBlockImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = expression.type,
descriptor = expression.descriptor,
origin = mapStatementOrigin(expression.origin),
statements = expression.statements.map { it.transform(this, null) },
sourceFileSymbol = expression.sourceFileSymbol
)
} else {
IrBlockImpl(
expression.startOffset, expression.endOffset,
substituteAndEraseType(expression.type)!!,
mapStatementOrigin(expression.origin),
expression.statements.map { it.transform(this, null) }
)
}
}
//-------------------------------------------------------------------------//
override fun visitClassReference(expression: IrClassReference): IrClassReference {
val newExpressionType = substituteAndEraseType(expression.type)!! // Substituted expression type.
val newDescriptorType = substituteType(expression.descriptor.defaultType)!! // Substituted type of referenced class.
val classDescriptor = newDescriptorType.constructor.declarationDescriptor!! // Get ClassifierDescriptor of the referenced class.
return IrClassReferenceImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = newExpressionType,
descriptor = classDescriptor,
classType = expression.classType
)
}
//-------------------------------------------------------------------------//
override fun visitGetClass(expression: IrGetClass): IrGetClass {
val type = substituteAndEraseType(expression.type)!!
return IrGetClassImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = type,
argument = expression.argument.transform(this, null)
)
}
//-------------------------------------------------------------------------//
override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
return irLoop
}
override fun visitClass(declaration: IrClass): IrClass {
val descriptor = this.mapClassDeclaration(declaration.descriptor)
return context.symbolTable.declareClass(
declaration.startOffset, declaration.endOffset, mapDeclarationOrigin(declaration.origin),
descriptor
).apply {
declaration.declarations.mapTo(this.declarations) {
it.transform(this@InlineCopyIr, null) as IrDeclaration
}
this.transformAnnotations(declaration)
this.thisReceiver = declaration.thisReceiver?.replaceDescriptor1(this.descriptor.thisAsReceiverParameter)
this.transformTypeParameters(declaration, this.descriptor.declaredTypeParameters)
descriptor.defaultType.constructor.supertypes.mapTo(this.superTypes) {
context.symbolTable.translateErased(it)
}
}
}
}
//-------------------------------------------------------------------------//
private fun substituteType(type: KotlinType?): KotlinType? {
val substitutedType = (type?.let { typeSubstitutor?.substitute(it, Variance.INVARIANT) } ?: type)
?: return null
val oldClassDescriptor = TypeUtils.getClassDescriptor(substitutedType) ?: return substitutedType
return descriptorSubstituteMap[oldClassDescriptor]?.let { (it as ClassDescriptor).defaultType } ?: substitutedType
}
private fun substituteAndEraseType(oldType: IrType?): IrType? {
oldType ?: return null
val substitutedKotlinType = substituteType(oldType.toKotlinType())
?: return oldType
return context.symbolTable.translateErased(substitutedKotlinType)
}
fun translateBroken(type: KotlinType): IrType {
val declarationDescriptor = type.constructor.declarationDescriptor
return when (declarationDescriptor) {
is ClassDescriptor -> {
val classifier = context.symbolTable.referenceClassifier(declarationDescriptor)
val typeArguments = type.arguments.map {
if (it.isStarProjection) {
IrStarProjectionImpl
} else {
makeTypeProjection(translateBroken(it.type), it.projectionKind)
}
}
IrSimpleTypeImpl(
classifier,
type.isMarkedNullable,
typeArguments,
emptyList()
)
}
is TypeParameterDescriptor -> IrSimpleTypeImpl(
context.symbolTable.referenceTypeParameter(declarationDescriptor),
type.isMarkedNullable,
emptyList(),
emptyList()
)
else -> error(declarationDescriptor ?: "null")
}
}
private fun substituteAndBreakType(oldType: IrType): IrType {
return translateBroken(substituteType(oldType.toKotlinType())!!)
}
//-------------------------------------------------------------------------//
private fun IrMemberAccessExpression.substituteTypeArguments(original: IrMemberAccessExpression) {
for (index in 0 until original.typeArgumentsCount) {
val originalTypeArgument = original.getTypeArgument(index)
val newTypeArgument = substituteAndBreakType(originalTypeArgument!!)
this.putTypeArgument(index, newTypeArgument)
}
}
//-------------------------------------------------------------------------//
override fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) {
descriptorSubstituteMap.forEach { t, u ->
globalSubstituteMap[t] = SubstitutedDescriptor(targetDescriptor, u)
}
}
}
class SubstitutedDescriptor(val inlinedFunction: FunctionDescriptor, val descriptor: DeclarationDescriptor)
internal class DescriptorSubstitutorForExternalScope(
val globalSubstituteMap: Map<DeclarationDescriptor, SubstitutedDescriptor>,
val context: Context
)
: IrElementTransformerVoidWithContext() {
fun run(element: IrElement) {
element.transformChildrenVoid(this)
}
override fun visitCall(expression: IrCall): IrExpression {
val oldExpression = super.visitCall(expression) as IrCall
val substitutedDescriptor = globalSubstituteMap[expression.descriptor.original]
?: return oldExpression
if (allScopes.any { it.scope.scopeOwner == substitutedDescriptor.inlinedFunction })
return oldExpression
return when (oldExpression) {
is IrCallImpl -> copyIrCallImpl(oldExpression, substitutedDescriptor)
is IrCallWithShallowCopy -> copyIrCallWithShallowCopy(oldExpression, substitutedDescriptor)
else -> oldExpression
}
}
//-------------------------------------------------------------------------//
private fun copyIrCallImpl(oldExpression: IrCallImpl, substitutedDescriptor: SubstitutedDescriptor): IrCallImpl {
val oldDescriptor = oldExpression.descriptor
val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
if (newDescriptor == oldDescriptor)
return oldExpression
return IrCallImpl(
startOffset = oldExpression.startOffset,
endOffset = oldExpression.endOffset,
type = context.symbolTable.translateErased(newDescriptor.returnType!!),
symbol = createFunctionSymbol(newDescriptor),
descriptor = newDescriptor,
typeArgumentsCount = oldExpression.typeArgumentsCount,
origin = oldExpression.origin,
superQualifierSymbol = createClassSymbolOrNull(oldExpression.superQualifier)
).apply {
copyTypeArgumentsFrom(oldExpression)
oldExpression.descriptor.valueParameters.forEach {
val valueArgument = oldExpression.getValueArgument(it)
putValueArgument(it.index, valueArgument)
}
extensionReceiver = oldExpression.extensionReceiver
dispatchReceiver = oldExpression.dispatchReceiver
}
}
//-------------------------------------------------------------------------//
private fun copyIrCallWithShallowCopy(oldExpression: IrCallWithShallowCopy, substitutedDescriptor: SubstitutedDescriptor): IrCall {
val oldDescriptor = oldExpression.descriptor
val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
if (newDescriptor == oldDescriptor)
return oldExpression
return oldExpression.shallowCopy(oldExpression.origin, createFunctionSymbol(newDescriptor), oldExpression.superQualifierSymbol)
}
}
}
@@ -7,433 +7,338 @@
package org.jetbrains.kotlin.ir.backend.js.lower.inline
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.ScopeWithIr
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.backend.common.reportWarning
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.fileEntry
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.types.irTypeKotlinBuiltIns
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.TypeProjection
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor
abstract class IrElementTransformerWithContext<D> : IrElementTransformer<D> {
private val scopeStack = mutableListOf<ScopeWithIr>()
final override fun visitFile(declaration: IrFile, data: D): IrFile {
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
val result = visitFileNew(declaration, data)
scopeStack.pop()
return result
}
final override fun visitClass(declaration: IrClass, data: D): IrStatement {
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
val result = visitClassNew(declaration, data)
scopeStack.pop()
return result
}
final override fun visitProperty(declaration: IrProperty, data: D): IrStatement {
scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
val result = visitPropertyNew(declaration, data)
scopeStack.pop()
return result
}
final override fun visitField(declaration: IrField, data: D): IrStatement {
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
val result = visitFieldNew(declaration, data)
scopeStack.pop()
return result
}
final override fun visitFunction(declaration: IrFunction, data: D): IrStatement {
scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
val result = visitFunctionNew(declaration, data)
scopeStack.pop()
return result
}
protected val currentFile get() = scopeStack.lastOrNull { it.irElement is IrFile }!!.irElement as IrFile
protected val currentClass get() = scopeStack.lastOrNull { it.scope.scopeOwner is ClassDescriptor }
protected val currentFunction get() = scopeStack.lastOrNull { it.scope.scopeOwner is FunctionDescriptor }
protected val currentProperty get() = scopeStack.lastOrNull { it.scope.scopeOwner is PropertyDescriptor }
protected val currentScope get() = scopeStack.peek()
protected val parentScope get() = if (scopeStack.size < 2) null else scopeStack[scopeStack.size - 2]
protected val allScopes get() = scopeStack
fun printScopeStack() {
scopeStack.forEach { println(it.scope.scopeOwner) }
}
open fun visitFileNew(declaration: IrFile, data: D): IrFile {
return super.visitFile(declaration, data)
}
open fun visitClassNew(declaration: IrClass, data: D): IrStatement {
return super.visitClass(declaration, data)
}
open fun visitFunctionNew(declaration: IrFunction, data: D): IrStatement {
return super.visitFunction(declaration, data)
}
open fun visitPropertyNew(declaration: IrProperty, data: D): IrStatement {
return super.visitProperty(declaration, data)
}
open fun visitFieldNew(declaration: IrField, data: D): IrStatement {
return super.visitField(declaration, data)
}
}
//-----------------------------------------------------------------------------//
typealias Context = JsIrBackendContext
internal class Ref<T>(var value: T)
// backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt
internal class FunctionInlining(val context: Context): IrElementTransformerWithContext<Ref<Boolean>>() {
// TODO private val deserializer = DeserializerDriver(context)
private val globalSubstituteMap = mutableMapOf<DeclarationDescriptor, SubstitutedDescriptor>()
private val inlineFunctions = mutableMapOf<FunctionDescriptor, Boolean>()
internal class FunctionInlining(val context: Context): IrElementTransformerVoidWithContext() {
//-------------------------------------------------------------------------//
fun inline(irModule: IrModuleFragment): IrElement {
irTypeKotlinBuiltIns = irModule.irBuiltins.builtIns
val transformedModule = irModule.accept(this, Ref(false))
DescriptorSubstitutorForExternalScope(globalSubstituteMap, context).run(transformedModule) // Transform calls to object that might be returned from inline function call.
return transformedModule
return irModule.accept(this, data = null)
}
override fun visitFunctionNew(declaration: IrFunction, data: Ref<Boolean>): IrStatement {
val descriptor = declaration.descriptor
val localData = Ref(inlineFunctions[descriptor] ?: false)
val result = super.visitFunctionNew(declaration, localData)
data.value = data.value or localData.value
if (descriptor.needsInlining)
inlineFunctions[descriptor] = localData.value
return result
}
override fun visitCall(expression: IrCall, data: Ref<Boolean>): IrExpression {
val argsAreBad = Ref(false)
val callSite = super.visitCall(expression, argsAreBad) as IrCall
data.value = data.value or argsAreBad.value
override fun visitCall(expression: IrCall): IrExpression {
val callSite = super.visitCall(expression) as IrCall
val functionDescriptor = callSite.descriptor
if (!functionDescriptor.needsInlining) return callSite // This call does not need inlining.
if (!functionDescriptor.needsInlining)
return callSite // This call does not need inlining.
val callee = getFunctionDeclaration(callSite) // Get declaration of the function to be inlined.
if (callee == null) { // We failed to get the declaration.
val message = "Inliner failed to obtain function declaration: " +
functionDescriptor.fqNameSafe.toString()
context.reportWarning(message, currentFile, callSite) // Report warning.
return callSite
}
data.value = data.value or callee.second
val callee = getFunctionDeclaration(callSite.symbol) // Get declaration of the function to be inlined.
callee.transformChildrenVoid(this) // Process recursive inline.
val childIsBad = Ref(inlineFunctions[functionDescriptor] ?: false)
callee.first.transformChildren(this, childIsBad) // Process recursive inline.
inlineFunctions[functionDescriptor] = childIsBad.value
data.value = data.value or childIsBad.value
val currentCalleeIsBad = argsAreBad.value or childIsBad.value or callee.second
val inliner = Inliner(globalSubstituteMap, callSite, callee.first, !currentCalleeIsBad, currentScope!!,
allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull(), context, this)
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull()
val inliner = Inliner(callSite, callee, currentScope!!, parent, context)
// Create inliner for this scope.
return inliner.inline() // Return newly created IrInlineBody instead of IrCall.
}
//-------------------------------------------------------------------------//
private fun getFunctionDeclaration(irCall: IrCall): Pair<IrFunction, Boolean>? {
private fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
val functionDescriptor = irCall.descriptor
val originalDescriptor = functionDescriptor.resolveFakeOverride().original
val descriptor = symbol.descriptor.original
// val originalDescriptor = functionDescriptor.resolveFakeOverride().original
val functionDeclaration =
context.originalModuleIndex.functions[originalDescriptor] ?: context.symbolTable.referenceDeclaredFunction(originalDescriptor).owner
// ?: // If function is declared in the current module.
// TODO deserializer.deserializeInlineBody(originalDescriptor) // Function is declared in another module.
return (functionDeclaration as IrFunction?)?.let { it to false }
val languageVersionSettings = context.configuration.languageVersionSettings
// TODO: Remove these hacks when coroutine intrinsics are fixed.
return when {
// descriptor.isBuiltInIntercepted(languageVersionSettings) ->
// error("Continuation.intercepted is not available with release coroutines")
//
// descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) ->
// context.ir.symbols.konanSuspendCoroutineUninterceptedOrReturn.owner
//
// descriptor == context.ir.symbols.coroutineContextGetter ->
// context.ir.symbols.konanCoroutineContextGetter.owner
else -> (symbol.owner as? IrSimpleFunction)?.resolveFakeOverride() ?: symbol.owner
}
}
}
// TODO: should we keep this at all?
private val inlineConstructor = FqName("kotlin.native.internal.InlineConstructor")
private val FunctionDescriptor.isInlineConstructor get() = annotations.hasAnnotation(inlineConstructor)
// TODO: should we keep this at all?
private val inlineConstructor = FqName("kotlin.native.internal.InlineConstructor")
private val FunctionDescriptor.isInlineConstructor get() = annotations.hasAnnotation(inlineConstructor)
//-----------------------------------------------------------------------------//
private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>,
val callSite: IrCall,
val callee: IrFunction,
val local: Boolean,
val currentScope: ScopeWithIr,
val parent: IrDeclarationParent?,
val context: Context,
val owner: FunctionInlining /*TODO: make inner*/) {
private inner class Inliner(
val callSite: IrCall,
val callee: IrFunction,
val currentScope: ScopeWithIr,
val parent: IrDeclarationParent?,
val context: Context
) {
val copyIrElement =
if (!local)
DeepCopyIrTreeWithDescriptors(callee.descriptor, currentScope.scope.scopeOwner,
context, createTypeSubstitutor(callSite))
else {
val typeParameters =
if (callee is IrConstructor)
callee.parentAsClass.typeParameters
else callee.typeParameters
val typeArguments =
(0 until callSite.typeArgumentsCount).map {
typeParameters[it].symbol to callSite.getTypeArgument(it)
}.associate { it }
DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent)
val copyIrElement = run {
val typeParameters =
if (callee is IrConstructor)
callee.parentAsClass.typeParameters
else callee.typeParameters
val typeArguments =
(0 until callSite.typeArgumentsCount).map {
typeParameters[it].symbol to callSite.getTypeArgument(it)
}.associate { it }
DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent)
}
val substituteMap = mutableMapOf<ValueDescriptor, IrExpression>()
fun inline() = inlineFunction(callSite, callee)
/**
* TODO: JVM inliner crashed on attempt inline this function from transform.kt with:
* j.l.IllegalStateException: Couldn't obtain compiled function body for
* public inline fun <reified T : org.jetbrains.kotlin.ir.IrElement> kotlin.collections.MutableList<T>.transform...
*/
private inline fun <reified T : IrElement> MutableList<T>.transform(transformation: (T) -> IrElement) {
forEachIndexed { i, item ->
set(i, transformation(item) as T)
}
}
val substituteMap = mutableMapOf<ValueDescriptor, IrExpression>()
private fun inlineFunction(callSite: IrCall, callee: IrFunction): IrReturnableBlockImpl {
val copiedCallee = copyIrElement.copy(callee) as IrFunction
fun inline() = inlineFunction(callSite, callee)
val evaluationStatements = evaluateArguments(callSite, copiedCallee)
val statements = (copiedCallee.body as IrBlockBody).statements
/**
* TODO: JVM inliner crashed on attempt inline this function from transform.kt with:
* j.l.IllegalStateException: Couldn't obtain compiled function body for
* public inline fun <reified T : org.jetbrains.kotlin.ir.IrElement> kotlin.collections.MutableList<T>.transform...
*/
private inline fun <reified T : IrElement> MutableList<T>.transform(transformation: (T) -> IrElement) {
forEachIndexed { i, item ->
set(i, transformation(item) as T)
}
}
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copiedCallee.descriptor.original)
val descriptor = callee.descriptor.original
val startOffset = callee.startOffset
val endOffset = callee.endOffset
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
private fun inlineFunction(callSite: IrCall, callee: IrFunction): IrReturnableBlockImpl {
val copiedCallee = copyIrElement.copy(callee) as IrFunction
val evaluationStatements = evaluateArguments(callSite, copiedCallee)
val statements = (copiedCallee.body as IrBlockBody).statements
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copiedCallee.descriptor.original)
val descriptor = callee.descriptor.original
val startOffset = callee.startOffset
val endOffset = callee.endOffset
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
if (descriptor.isInlineConstructor) {
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
irBuilder.run {
val constructorDescriptor = delegatingConstructorCall.descriptor.original
val constructorCall = irCall(delegatingConstructorCall.symbol, callSite.type,
constructorDescriptor.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply {
constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) }
}
val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter
val newThis = currentScope.scope.createTemporaryVariable(
if (descriptor.isInlineConstructor) {
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
irBuilder.run {
val constructorDescriptor = delegatingConstructorCall.descriptor.original
val constructorCall = irCall(delegatingConstructorCall.symbol, callSite.type,
constructorDescriptor.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply {
constructorDescriptor.valueParameters.forEach {
putValueArgument(
it,
delegatingConstructorCall.getValueArgument(it)
)
}
}
val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter
val newThis = currentScope.scope.createTemporaryVariable(
irExpression = constructorCall,
nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this"
)
statements[0] = newThis
substituteMap[oldThis] = irGet(newThis)
statements.add(irReturn(irGet(newThis)))
}
}
copyIrElement.addCurrentSubstituteMap(globalSubstituteMap)
val transformer = ParameterSubstitutor()
statements.transform { it.transform(transformer, data = null) }
statements.addAll(0, evaluationStatements)
return IrReturnableBlockImpl(
startOffset = startOffset,
endOffset = endOffset,
type = copiedCallee.returnType,
symbol = irReturnableBlockSymbol,
origin = null,
statements = statements,
sourceFileSymbol = callee.file.symbol
).apply {
transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid(this)
if (expression.returnTargetSymbol == copiedCallee.symbol)
return irBuilder.irReturn(expression.value)
return expression
nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this"
)
statements[0] = newThis
substituteMap[oldThis] = irGet(newThis)
statements.add(irReturn(irGet(newThis)))
}
})
}
}
//---------------------------------------------------------------------//
private inner class ParameterSubstitutor: IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
val newExpression = super.visitGetValue(expression) as IrGetValue
val descriptor = newExpression.descriptor
val argument = substituteMap[descriptor]
if (argument == null) return newExpression
argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution.
return copyIrElement.copy(argument) as IrExpression
}
//-----------------------------------------------------------------//
private val IrFunctionReference.isLambda: Boolean
get() {
return symbol.owner.visibility == Visibilities.LOCAL && origin == IrStatementOrigin.LAMBDA
}
override fun visitCall(expression: IrCall): IrExpression {
if (!isLambdaCall(expression))
return super.visitCall(expression)
val transformer = ParameterSubstitutor()
statements.transform { it.transform(transformer, data = null) }
statements.addAll(0, evaluationStatements)
val dispatchReceiver = expression.dispatchReceiver as IrGetValue
val functionArgument = substituteMap[dispatchReceiver.descriptor]
if (functionArgument == null)
return super.visitCall(expression)
val dispatchDescriptor = dispatchReceiver.descriptor
if (dispatchDescriptor is ValueParameterDescriptor &&
dispatchDescriptor.isNoinline) return super.visitCall(expression)
return IrReturnableBlockImpl(
startOffset = startOffset,
endOffset = endOffset,
type = copiedCallee.returnType,
symbol = irReturnableBlockSymbol,
origin = null,
statements = statements,
sourceFileSymbol = callee.file.symbol
).apply {
transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid(this)
if (functionArgument is IrFunctionReference) {
if (!functionArgument.isLambda) return super.visitCall(expression)
if (expression.returnTargetSymbol == copiedCallee.symbol)
return irBuilder.irReturn(expression.value)
return expression
}
})
}
}
val functionDescriptor = functionArgument.descriptor
val functionParameters = functionDescriptor.explicitParameters
val boundFunctionParameters = functionArgument.getArguments()
val unboundFunctionParameters = functionParameters - boundFunctionParameters.map { it.first }
val boundFunctionParametersMap = boundFunctionParameters.associate { it.first to it.second }
//---------------------------------------------------------------------//
var unboundIndex = 0
val unboundArgsSet = unboundFunctionParameters.toSet()
val valueParameters = expression.getArguments().drop(1) // Skip dispatch receiver.
private inner class ParameterSubstitutor : IrElementTransformerVoid() {
val immediateCall = IrCallImpl(
override fun visitGetValue(expression: IrGetValue): IrExpression {
val newExpression = super.visitGetValue(expression) as IrGetValue
val descriptor = newExpression.descriptor
val argument = substituteMap[descriptor] ?: return newExpression
argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution.
return copyIrElement.copy(argument) as IrExpression
}
//-----------------------------------------------------------------//
private val IrFunctionReference.isLambda: Boolean
get() {
return symbol.owner.visibility == Visibilities.LOCAL && origin == IrStatementOrigin.LAMBDA
}
override fun visitCall(expression: IrCall): IrExpression {
if (!isLambdaCall(expression))
return super.visitCall(expression)
val dispatchReceiver = expression.dispatchReceiver as IrGetValue
val functionArgument = substituteMap[dispatchReceiver.descriptor]
if (functionArgument == null)
return super.visitCall(expression)
val dispatchDescriptor = dispatchReceiver.descriptor
if (dispatchDescriptor is ValueParameterDescriptor &&
dispatchDescriptor.isNoinline
) return super.visitCall(expression)
if (functionArgument is IrFunctionReference) {
if (!functionArgument.isLambda) return super.visitCall(expression)
val functionDescriptor = functionArgument.descriptor
val functionParameters = functionDescriptor.explicitParameters
val boundFunctionParameters = functionArgument.getArguments()
val unboundFunctionParameters = functionParameters - boundFunctionParameters.map { it.first }
val boundFunctionParametersMap = boundFunctionParameters.associate { it.first to it.second }
var unboundIndex = 0
val unboundArgsSet = unboundFunctionParameters.toSet()
val valueParameters = expression.getArguments().drop(1) // Skip dispatch receiver.
val immediateCall = IrCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = expression.type,
symbol = functionArgument.symbol,
descriptor = functionArgument.descriptor).apply {
functionParameters.forEach {
val argument =
endOffset = expression.endOffset,
type = expression.type,
symbol = functionArgument.symbol,
descriptor = functionArgument.descriptor
).apply {
functionParameters.forEach {
val argument =
if (!unboundArgsSet.contains(it))
boundFunctionParametersMap[it]!!
else
valueParameters[unboundIndex++].second
when (it) {
functionDescriptor.dispatchReceiverParameter -> this.dispatchReceiver = argument
functionDescriptor.extensionReceiverParameter -> this.extensionReceiver = argument
else -> putValueArgument((it as ValueParameterDescriptor).index, argument)
when (it) {
functionDescriptor.dispatchReceiverParameter -> this.dispatchReceiver = argument
functionDescriptor.extensionReceiverParameter -> this.extensionReceiver = argument
else -> putValueArgument((it as ValueParameterDescriptor).index, argument)
}
}
assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" }
}
assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" }
return this@FunctionInlining.visitCall(super.visitCall(immediateCall) as IrCall)
}
return owner.visitCall(super.visitCall(immediateCall) as IrCall, Ref(false))
}
if (functionArgument !is IrBlock)
return super.visitCall(expression)
if (functionArgument !is IrBlock)
return super.visitCall(expression)
val functionDeclaration = functionArgument.statements[0] as IrFunction
val newExpression = inlineFunction(expression, functionDeclaration) // Inline the lambda. Lambda parameters will be substituted with lambda arguments.
return newExpression.transform(this, null) // Substitute lambda arguments with target function arguments.
val functionDeclaration = functionArgument.statements[0] as IrFunction
val newExpression = inlineFunction(
expression,
functionDeclaration
) // Inline the lambda. Lambda parameters will be substituted with lambda arguments.
return newExpression.transform(
this,
null
) // Substitute lambda arguments with target function arguments.
}
//-----------------------------------------------------------------//
override fun visitElement(element: IrElement) = element.accept(this, null)
}
//-----------------------------------------------------------------//
private fun isLambdaCall(irCall: IrCall) = irCall.symbol.owner.isFunctionInvoke && irCall.dispatchReceiver is IrGetValue
override fun visitElement(element: IrElement) = element.accept(this, null)
}
//-------------------------------------------------------------------------//
private fun isLambdaCall(irCall: IrCall) = irCall.symbol.owner.isFunctionInvoke && irCall.dispatchReceiver is IrGetValue
private inner class ParameterToArgument(
val parameter: IrValueParameter,
val argumentExpression: IrExpression
) {
private fun createTypeSubstitutor(irCall: IrCall): TypeSubstitutor? {
if (irCall.typeArgumentsCount == 0) return null
val descriptor = irCall.descriptor.resolveFakeOverride().original
val typeParameters = descriptor.propertyIfAccessor.typeParameters
val substitutionContext = mutableMapOf<TypeConstructor, TypeProjection>()
for (index in 0 until irCall.typeArgumentsCount) {
val typeArgument = irCall.getTypeArgument(index) ?: continue
substitutionContext[typeParameters[index].typeConstructor] = TypeProjectionImpl(typeArgument.toKotlinType())
val isInlinableLambdaArgument: Boolean
get() {
if (!InlineUtil.isInlineParameter(parameter.descriptor)) return false
if (argumentExpression is IrFunctionReference
&& !argumentExpression.descriptor.isSuspend
) return true // Skip suspend functions for now since it's not supported by FE anyway.
// Do pattern-matching on IR.
if (argumentExpression !is IrBlock) return false
if (argumentExpression.origin != IrStatementOrigin.LAMBDA &&
argumentExpression.origin != IrStatementOrigin.ANONYMOUS_FUNCTION
) return false
val statements = argumentExpression.statements
val irFunction = statements[0]
val irCallableReference = statements[1]
if (irFunction !is IrFunction) return false
if (irCallableReference !is IrCallableReference) return false
return true
}
val isImmutableVariableLoad: Boolean
get() = argumentExpression.let {
it is IrGetValue && !it.symbol.owner.let { v -> v is IrVariable && v.isVar }
}
}
return TypeSubstitutor.create(substitutionContext)
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
private class ParameterToArgument(val parameter: IrValueParameter,
val argumentExpression : IrExpression) {
private fun buildParameterToArgument(callSite: IrCall, callee: IrFunction): List<ParameterToArgument> {
val isInlinableLambdaArgument : Boolean
get() {
if (!InlineUtil.isInlineParameter(parameter.descriptor)) return false
if (argumentExpression is IrFunctionReference
&& !argumentExpression.descriptor.isSuspend) return true // Skip suspend functions for now since it's not supported by FE anyway.
val parameterToArgument = mutableListOf<ParameterToArgument>()
// Do pattern-matching on IR.
if (argumentExpression !is IrBlock) return false
if (argumentExpression.origin != IrStatementOrigin.LAMBDA &&
argumentExpression.origin != IrStatementOrigin.ANONYMOUS_FUNCTION) return false
val statements = argumentExpression.statements
val irFunction = statements[0]
val irCallableReference = statements[1]
if (irFunction !is IrFunction) return false
if (irCallableReference !is IrCallableReference) return false
return true
}
if (callSite.dispatchReceiver != null && // Only if there are non null dispatch receivers both
callee.dispatchReceiverParameter != null
) // on call site and in function declaration.
parameterToArgument += ParameterToArgument(
parameter = callee.dispatchReceiverParameter!!,
argumentExpression = callSite.dispatchReceiver!!
)
val isImmutableVariableLoad: Boolean
get() = argumentExpression.let {
it is IrGetValue && !it.descriptor.let { it is VariableDescriptor && it.isVar }
}
}
//-------------------------------------------------------------------------//
private fun buildParameterToArgument(callSite: IrCall, callee: IrFunction): List<ParameterToArgument> {
val parameterToArgument = mutableListOf<ParameterToArgument>()
if (callSite.dispatchReceiver != null && // Only if there are non null dispatch receivers both
callee.dispatchReceiverParameter != null) // on call site and in function declaration.
parameterToArgument += ParameterToArgument(
parameter = callee.dispatchReceiverParameter!!,
argumentExpression = callSite.dispatchReceiver!!
)
val valueArguments =
val valueArguments =
callSite.descriptor.valueParameters.map { callSite.getValueArgument(it) }.toMutableList()
if (callee.extensionReceiverParameter != null) {
parameterToArgument += ParameterToArgument(
if (callee.extensionReceiverParameter != null) {
parameterToArgument += ParameterToArgument(
parameter = callee.extensionReceiverParameter!!,
argumentExpression = if (callSite.extensionReceiver != null) {
callSite.extensionReceiver!!
@@ -441,95 +346,103 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
// Special case: lambda with receiver is called as usual lambda:
valueArguments.removeAt(0)!!
}
)
} else if (callSite.extensionReceiver != null) {
// Special case: usual lambda is called as lambda with receiver:
valueArguments.add(0, callSite.extensionReceiver!!)
}
)
} else if (callSite.extensionReceiver != null) {
// Special case: usual lambda is called as lambda with receiver:
valueArguments.add(0, callSite.extensionReceiver!!)
}
val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>()
for (parameter in callee.valueParameters) {
val argument = valueArguments[parameter.index]
when {
argument != null -> {
parameterToArgument += ParameterToArgument(
parameter = parameter,
val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>()
for (parameter in callee.valueParameters) {
val argument = valueArguments[parameter.index]
when {
argument != null -> {
parameterToArgument += ParameterToArgument(
parameter = parameter,
argumentExpression = argument
)
}
)
}
// After ExpectDeclarationsRemoving pass default values from expect declarations
// are represented correctly in IR.
parameter.defaultValue != null -> { // There is no argument - try default value.
parametersWithDefaultToArgument += ParameterToArgument(
parameter = parameter,
// After ExpectDeclarationsRemoving pass default values from expect declarations
// are represented correctly in IR.
parameter.defaultValue != null -> { // There is no argument - try default value.
parametersWithDefaultToArgument += ParameterToArgument(
parameter = parameter,
argumentExpression = parameter.defaultValue!!.expression
)
}
)
}
parameter.varargElementType != null -> {
val emptyArray = IrVarargImpl(
startOffset = callSite.startOffset,
endOffset = callSite.endOffset,
type = parameter.type,
parameter.varargElementType != null -> {
val emptyArray = IrVarargImpl(
startOffset = callSite.startOffset,
endOffset = callSite.endOffset,
type = parameter.type,
varargElementType = parameter.varargElementType!!
)
parameterToArgument += ParameterToArgument(
parameter = parameter,
)
parameterToArgument += ParameterToArgument(
parameter = parameter,
argumentExpression = emptyArray
)
}
)
}
else -> {
val message = "Incomplete expression: call to ${callee.descriptor} " +
"has no argument at index ${parameter.index}"
throw Error(message)
else -> {
val message = "Incomplete expression: call to ${callee.descriptor} " +
"has no argument at index ${parameter.index}"
throw Error(message)
}
}
}
return parameterToArgument + parametersWithDefaultToArgument // All arguments except default are evaluated at callsite,
// but default arguments are evaluated inside callee.
}
return parameterToArgument + parametersWithDefaultToArgument // All arguments except default are evaluated at callsite,
// but default arguments are evaluated inside callee.
}
//-------------------------------------------------------------------------//
//-------------------------------------------------------------------------//
private fun evaluateArguments(callSite: IrCall, callee: IrFunction): List<IrStatement> {
private fun evaluateArguments(callSite: IrCall, callee: IrFunction): List<IrStatement> {
val parameterToArgumentOld = buildParameterToArgument(callSite, callee)
val evaluationStatements = mutableListOf<IrStatement>()
val substitutor = ParameterSubstitutor()
parameterToArgumentOld.forEach {
val parameterDescriptor = it.parameter.descriptor
val parameterToArgumentOld = buildParameterToArgument(callSite, callee)
val evaluationStatements = mutableListOf<IrStatement>()
val substitutor = ParameterSubstitutor()
parameterToArgumentOld.forEach {
val parameterDescriptor = it.parameter.descriptor
/*
/*
* We need to create temporary variable for each argument except inlinable lambda arguments.
* For simplicity and to produce simpler IR we don't create temporaries for every immutable variable,
* not only for those referring to inlinable lambdas.
*/
if (it.isInlinableLambdaArgument) {
substituteMap[parameterDescriptor] = it.argumentExpression
return@forEach
if (it.isInlinableLambdaArgument) {
substituteMap[parameterDescriptor] = it.argumentExpression
return@forEach
}
if (it.isImmutableVariableLoad) {
substituteMap[parameterDescriptor] = it.argumentExpression.transform(
substitutor,
data = null
) // Arguments may reference the previous ones - substitute them.
return@forEach
}
val newVariable = currentScope.scope.createTemporaryVariable(
irExpression = it.argumentExpression.transform(
substitutor,
data = null
), // Arguments may reference the previous ones - substitute them.
nameHint = callee.descriptor.name.toString(),
isMutable = false
)
evaluationStatements.add(newVariable)
val getVal = IrGetValueImpl(
startOffset = currentScope.irElement.startOffset,
endOffset = currentScope.irElement.endOffset,
type = newVariable.type,
symbol = newVariable.symbol
)
substituteMap[parameterDescriptor] = getVal
}
if (it.isImmutableVariableLoad) {
substituteMap[parameterDescriptor] = it.argumentExpression.transform(substitutor, data = null) // Arguments may reference the previous ones - substitute them.
return@forEach
}
val newVariable = currentScope.scope.createTemporaryVariable(
irExpression = it.argumentExpression.transform(substitutor, data = null), // Arguments may reference the previous ones - substitute them.
nameHint = callee.descriptor.name.toString(),
isMutable = false)
evaluationStatements.add(newVariable)
val getVal = IrGetValueImpl(
startOffset = currentScope.irElement.startOffset,
endOffset = currentScope.irElement.endOffset,
type = newVariable.type,
symbol = newVariable.symbol
)
substituteMap[parameterDescriptor] = getVal
return evaluationStatements
}
return evaluationStatements
}
}
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.isFunctionOrKFunction
import org.jetbrains.kotlin.ir.util.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.ir.util.isKFunction
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.types.KotlinType
@@ -54,7 +55,7 @@ internal val FunctionDescriptor.isFunctionInvoke: Boolean
internal val IrFunction.isFunctionInvoke: Boolean
get() {
val dispatchReceiver = dispatchReceiverParameter ?: return false
assert(!dispatchReceiver.type.isFunctionTypeOrSubtype())
assert(!dispatchReceiver.type.isKFunction())
return dispatchReceiver.type.isFunctionTypeOrSubtype() &&
/*this.isOperator &&*/ this.name == OperatorNameConventions.INVOKE
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.expressions.IrCall
@@ -199,4 +200,14 @@ val IrDeclaration.isGetter get() = this is IrSimpleFunction && this == this.corr
val IrDeclaration.isSetter get() = this is IrSimpleFunction && this == this.correspondingProperty?.setter
val IrDeclaration.isAccessor get() = this.isGetter || this.isSetter
val IrDeclaration.isAccessor get() = this.isGetter || this.isSetter
val IrDeclaration.fileEntry: SourceManager.FileEntry
get() = parent.let {
when (it) {
is IrFile -> it.fileEntry
is IrPackageFragment -> TODO("Unknown file")
is IrDeclaration -> it.fileEntry
else -> TODO("Unexpected declaration parent")
}
}
@@ -36,34 +36,31 @@ internal val IrField.isDelegate
internal const val SYNTHETIC_OFFSET = -2
class NaiveSourceBasedFileEntryImpl(override val name: String) : SourceManager.FileEntry {
private val lineStartOffsets: IntArray
//-------------------------------------------------------------------------//
init {
val file = File(name)
if (file.isFile) {
// TODO: could be incorrect, if file is not in system's line terminator format.
// Maybe use (0..document.lineCount - 1)
// .map { document.getLineStartOffset(it) }
// .toIntArray()
// as in PSI.
val separatorLength = System.lineSeparator().length
val buffer = mutableListOf<Int>()
var currentOffset = 0
file.forEachLine { line ->
buffer.add(currentOffset)
currentOffset += line.length + separatorLength
}
val File.lineStartOffsets: IntArray
get() {
// TODO: could be incorrect, if file is not in system's line terminator format.
// Maybe use (0..document.lineCount - 1)
// .map { document.getLineStartOffset(it) }
// .toIntArray()
// as in PSI.
val separatorLength = System.lineSeparator().length
val buffer = mutableListOf<Int>()
var currentOffset = 0
this.forEachLine { line ->
buffer.add(currentOffset)
lineStartOffsets = buffer.toIntArray()
} else {
lineStartOffsets = IntArray(0)
currentOffset += line.length + separatorLength
}
buffer.add(currentOffset)
return buffer.toIntArray()
}
val SourceManager.FileEntry.lineStartOffsets
get() = File(name).let {
if (it.exists() && it.isFile) it.lineStartOffsets else IntArray(0)
}
class NaiveSourceBasedFileEntryImpl(override val name: String, val lineStartOffsets: IntArray = IntArray(0)) : SourceManager.FileEntry {
//-------------------------------------------------------------------------//
override fun getLineNumber(offset: Int): Int {
@@ -19,17 +19,10 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.modules.KOTLIN_STDLIB_MODULE_NAME
import java.util.regex.Pattern
fun <K, V> MutableMap<K, V>.putOnce(k:K, v: V): Unit {
assert(!this.containsKey(k) || this[k] == v) {
"adding $v for $k, but it is already ${this[k]} for $k"
}
this.put(k, v)
}
class DescriptorTable {
private val descriptors = mutableMapOf<DeclarationDescriptor, Long>()
fun put(descriptor: DeclarationDescriptor, uniqId: UniqId) {
descriptors.putOnce(descriptor, uniqId.index)
descriptors.getOrPut(descriptor) { uniqId.index }
}
fun get(descriptor: DeclarationDescriptor) = descriptors[descriptor]
}
@@ -54,35 +47,27 @@ class DeclarationTable(val builtIns: IrBuiltIns, val descriptorTable: Descriptor
currentIndex += BUILT_IN_UNIQ_ID_GAP
}
fun uniqIdByDeclaration(value: IrDeclaration): UniqId {
val index = table.getOrPut(value) {
if (isBuiltInFunction(value)) {
UniqId(FUNCTION_INDEX_START + builtInFunctionId(value), false)
} else if (value.origin == IrDeclarationOrigin.FAKE_OVERRIDE ||
!value.isExported()
|| value is IrVariable
|| value is IrTypeParameter
|| value is IrValueParameter
|| value is IrAnonymousInitializerImpl
) {
val desc = value.descriptor
if (desc is CallableDescriptor) {
if (desc.visibility == Visibilities.PUBLIC || value.origin != IrDeclarationOrigin.FAKE_OVERRIDE) {
fun foo(){}
foo()
}
}
UniqId(currentIndex++, true)
} else {
UniqId(value.uniqIdIndex, false)
}
fun uniqIdByDeclaration(value: IrDeclaration) = table.getOrPut(value) {
val index = if (isBuiltInFunction(value)) {
UniqId(FUNCTION_INDEX_START + builtInFunctionId(value), false)
} else if (value.origin == IrDeclarationOrigin.FAKE_OVERRIDE ||
!value.isExported()
|| value is IrVariable
|| value is IrTypeParameter
|| value is IrValueParameter
|| value is IrAnonymousInitializerImpl
) {
UniqId(currentIndex++, true)
} else {
UniqId(value.uniqIdIndex, false)
}
debugIndex.put(index, "${if (index.isLocal) "" else value.uniqSymbolName()} descriptor = ${value.descriptor}")
// It can grow as large as 1/3 of ir/* size.
// debugIndex.put(index) {
// "${if (index.isLocal) "" else value.uniqSymbolName()} descriptor = ${value.descriptor}"
//}.also {it == null}
return index
index
}
}
@@ -13,29 +13,42 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
class DescriptorReferenceDeserializer(val currentModule: ModuleDescriptor, val resolvedForwardDeclarations: MutableMap<UniqIdKey, UniqIdKey>) {
class DescriptorReferenceDeserializer(
val currentModule: ModuleDescriptor, val resolvedForwardDeclarations: MutableMap<UniqIdKey, UniqIdKey>,
val checkerDesc: (DeclarationDescriptor) -> Long?,
val checkerID: (Long) -> Boolean,
val descriptorResolver: (FqName) -> DeclarationDescriptor
) {
fun deserializeDescriptorReference(
proto: IrKlibProtoBuf.DescriptorReference,
checkerDesc: (DeclarationDescriptor) -> Long?,
checkerID: (Long) -> Boolean,
descriptorResolver: (FqName) -> DeclarationDescriptor
packageFqNameString: String,
classFqNameString: String,
name: String,
index: Long?,
isEnumEntry: Boolean = false,
isEnumSpecial: Boolean = false,
isDefaultConstructor: Boolean = false,
isFakeOverride: Boolean = false,
isGetter: Boolean = false,
isSetter: Boolean = false
): DeclarationDescriptor {
val packageFqName =
if (proto.packageFqName == "<root>") FqName.ROOT else FqName(proto.packageFqName) // TODO: whould we store an empty string in the protobuf?
val classFqName = FqName(proto.classFqName)
val protoIndex = if (proto.hasUniqId()) proto.uniqId.index else null
val packageFqName = packageFqNameString.let {
if (it == "<root>") FqName.ROOT else FqName(it)
}// TODO: whould we store an empty string in the protobuf?
val (clazz, members) = if (proto.classFqName == "") {
val classFqName = FqName(classFqNameString)
val protoIndex = index
val (clazz, members) = if (classFqNameString == "") {
Pair(null, currentModule.getPackage(packageFqName).memberScope.getContributedDescriptors())
} else {
val clazz = currentModule.findClassAcrossModuleDependencies(ClassId(packageFqName, classFqName, false))!!
Pair(clazz, clazz.unsubstitutedMemberScope.getContributedDescriptors() + clazz.getConstructors())
}
if (proto.packageFqName.startsWith("cnames.") || proto.packageFqName.startsWith("objcnames.")) {
if (packageFqNameString.startsWith("cnames.") || packageFqNameString.startsWith("objcnames.")) {
val descriptor =
currentModule.findClassAcrossModuleDependencies(ClassId(packageFqName, FqName(proto.name), false))!!
currentModule.findClassAcrossModuleDependencies(ClassId(packageFqName, FqName(name), false))!!
if (!descriptor.fqNameUnsafe.asString().startsWith("cnames") && !descriptor.fqNameUnsafe.asString().startsWith(
"objcnames"
)
@@ -53,27 +66,25 @@ class DescriptorReferenceDeserializer(val currentModule: ModuleDescriptor, val r
return descriptor
}
if (proto.isEnumEntry) {
val name = proto.name
if (isEnumEntry) {
val memberScope = (clazz as DeserializedClassDescriptor).getUnsubstitutedMemberScope()
return memberScope.getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BACKEND)!!
}
if (proto.isEnumSpecial) {
val name = proto.name
if (isEnumSpecial) {
return clazz!!.getStaticScope()
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single()
}
if (protoIndex?.let { checkerID(it) } == true) {
return descriptorResolver(packageFqName.child(Name.identifier(proto.name)))
return descriptorResolver(packageFqName.child(Name.identifier(name)))
}
members.forEach { member ->
if (proto.isDefaultConstructor && member is ClassConstructorDescriptor) return member
if (isDefaultConstructor && member is ClassConstructorDescriptor) return member
val realMembers =
if (proto.isFakeOverride && member is CallableMemberDescriptor && member.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE)
if (isFakeOverride && member is CallableMemberDescriptor && member.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE)
member.resolveFakeOverrideMaybeAbstract().map { it.original }
else
setOf(member)
@@ -82,13 +93,13 @@ class DescriptorReferenceDeserializer(val currentModule: ModuleDescriptor, val r
if (memberIndices.contains(protoIndex)) {
return when {
member is PropertyDescriptor && proto.isSetter -> member.setter!!
member is PropertyDescriptor && proto.isGetter -> member.getter!!
member is PropertyDescriptor && isSetter -> member.setter!!
member is PropertyDescriptor && isGetter -> member.getter!!
else -> member
}
}
}
error("Could not find serialized descriptor for index: ${proto.uniqId.index} ${proto.packageFqName},${proto.classFqName},${proto.name}")
error("Could not find serialized descriptor for index: $index $packageFqName,$classFqName,$name")
}
}
@@ -9,9 +9,9 @@ import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataSerializerProtocol
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
@@ -44,10 +43,15 @@ class IrKlibProtoBufModuleDeserializer(
var deserializedModuleDescriptor: ModuleDescriptor? = null
var deserializedModuleProtoSymbolTables = mutableMapOf<ModuleDescriptor, IrKlibProtoBuf.IrSymbolTable>()
var deserializedModuleProtoStringTables = mutableMapOf<ModuleDescriptor, IrKlibProtoBuf.StringTable>()
var deserializedModuleProtoTypeTables = mutableMapOf<ModuleDescriptor, IrKlibProtoBuf.IrTypeTable>()
val resolvedForwardDeclarations = mutableMapOf<UniqIdKey, UniqIdKey>()
val descriptorReferenceDeserializer = DescriptorReferenceDeserializer(currentModule, resolvedForwardDeclarations)
val descriptorReferenceDeserializer = DescriptorReferenceDeserializer(currentModule, resolvedForwardDeclarations, {
knownBuiltInsDescriptors[it]?.index ?: if (isBuiltInFunction(it)) FUNCTION_INDEX_START + builtInFunctionId(it) else null
}, { (FUNCTION_INDEX_START + BUILT_IN_UNIQ_ID_CLASS_OFFSET) <= it && it < (FUNCTION_INDEX_START + BUILT_IN_UNIQ_ID_GAP) }, {
builtIns.builtIns.getBuiltInClassByFqName(it)
})
val moduleRoot = libraryDir
val irDirectory = File(libraryDir, "ir/")
@@ -94,7 +98,7 @@ class IrKlibProtoBufModuleDeserializer(
?: WrappedEnumEntryDescriptor()
)
IrKlibProtoBuf.IrSymbolKind.STANDALONE_FIELD_SYMBOL ->
IrFieldSymbolImpl(WrappedFieldDescriptor())
symbolTable.referenceField(WrappedFieldDescriptor())
IrKlibProtoBuf.IrSymbolKind.FIELD_SYMBOL ->
symbolTable.referenceField(
@@ -135,6 +139,9 @@ class IrKlibProtoBufModuleDeserializer(
return deserializeIrTypeData(typeData)
}
override fun deserializeString(proto: IrKlibProtoBuf.String) =
deserializedModuleProtoStringTables[deserializedModuleDescriptor]!!.getStrings(proto.index)
fun deserializeIrSymbolData(proto: IrKlibProtoBuf.IrSymbolData): IrSymbol {
val key = proto.uniqId.uniqIdKey(deserializedModuleDescriptor!!)
val topLevelKey = proto.topLevelUniqId.uniqIdKey(deserializedModuleDescriptor!!)
@@ -166,11 +173,18 @@ class IrKlibProtoBufModuleDeserializer(
}
override fun deserializeDescriptorReference(proto: IrKlibProtoBuf.DescriptorReference) =
descriptorReferenceDeserializer.deserializeDescriptorReference(proto, {
knownBuiltInsDescriptors[it]?.index ?: if (isBuiltInFunction(it)) FUNCTION_INDEX_START + builtInFunctionId(it) else null
}, { (FUNCTION_INDEX_START + BUILT_IN_UNIQ_ID_CLASS_OFFSET) <= it && it < (FUNCTION_INDEX_START + BUILT_IN_UNIQ_ID_GAP) }, {
builtIns.builtIns.getBuiltInClassByFqName(it)
})
descriptorReferenceDeserializer.deserializeDescriptorReference(
deserializeString(proto.packageFqName),
deserializeString(proto.classFqName),
deserializeString(proto.name),
if (proto.hasUniqId()) proto.uniqId.index else null,
isEnumEntry = proto.isEnumEntry,
isEnumSpecial = proto.isEnumSpecial,
isDefaultConstructor = proto.isDefaultConstructor,
isFakeOverride = proto.isFakeOverride,
isGetter = proto.isGetter,
isSetter = proto.isSetter
)
private val ByteArray.codedInputStream: org.jetbrains.kotlin.protobuf.CodedInputStream
get() {
@@ -282,6 +296,9 @@ class IrKlibProtoBufModuleDeserializer(
classDescriptor,
classDescriptor.modality
) { symbol: IrClassSymbol -> IrClassImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, symbol) }
.also {
it.parent = file
}
declaration
}
@@ -290,10 +307,13 @@ class IrKlibProtoBufModuleDeserializer(
}
fun deserializeIrFile(fileProto: IrKlibProtoBuf.IrFile, moduleDescriptor: ModuleDescriptor, deserializeAllDeclarations: Boolean): IrFile {
val fileEntry = NaiveSourceBasedFileEntryImpl(fileProto.fileEntry.name)
val fileEntry = NaiveSourceBasedFileEntryImpl(
deserializeString(fileProto.fileEntry.name),
fileProto.fileEntry.lineStartOffsetsList.toIntArray()
)
// TODO: we need to store "" in protobuf, I suppose. Or better yet, reuse fqname storage from metadata.
val fqName = if (fileProto.fqName == "<root>") FqName.ROOT else FqName(fileProto.fqName)
val fqName = deserializeString(fileProto.fqName).let { if (it == "<root>") FqName.ROOT else FqName(it) }
val packageFragmentDescriptor = EmptyPackageFragmentDescriptor(moduleDescriptor, fqName)
@@ -316,18 +336,17 @@ class IrKlibProtoBufModuleDeserializer(
deserializedModuleDescriptor = moduleDescriptor
deserializedModuleProtoSymbolTables.put(moduleDescriptor, proto.symbolTable)
deserializedModuleProtoStringTables.put(moduleDescriptor, proto.stringTable)
deserializedModuleProtoTypeTables.put(moduleDescriptor, proto.typeTable)
var i = 0
val files = proto.fileList.map {
i++
// if (i >= 41)
// descriptorReferenceDeserializer.doCrash = true
deserializeIrFile(it, moduleDescriptor, deserializeAllDeclarations)
}
val module = IrModuleFragmentImpl(moduleDescriptor, builtIns, files)
module.patchDeclarationParents(null)
return module
return module.also {
it.files.removeAll { f -> f.name == Namer.DYNAMIC_FILE_NAME }
}
}
fun deserializeIrModule(moduleDescriptor: ModuleDescriptor, byteArray: ByteArray, deserializeAllDeclarations: Boolean = false): IrModuleFragment {
@@ -49,6 +49,7 @@ abstract class IrModuleDeserializer(
abstract fun deserializeIrSymbol(proto: IrKlibProtoBuf.IrSymbol): IrSymbol
abstract fun deserializeIrType(proto: IrKlibProtoBuf.IrTypeIndex): IrType
abstract fun deserializeDescriptorReference(proto: IrKlibProtoBuf.DescriptorReference): DeclarationDescriptor
abstract fun deserializeString(proto: IrKlibProtoBuf.String): String
private fun deserializeTypeArguments(proto: IrKlibProtoBuf.TypeArguments): List<IrType> {
logger.log { "### deserializeTypeArguments" }
@@ -378,6 +379,8 @@ abstract class IrModuleDeserializer(
return IrInstanceInitializerCallImpl(start, end, symbol, builtIns.unitType)
}
private val getterToPropertyDescriptorMap = mutableMapOf<IrSimpleFunctionSymbol, WrappedPropertyDescriptor>()
private fun deserializePropertyReference(
proto: IrKlibProtoBuf.IrPropertyReference,
start: Int, end: Int, type: IrType
@@ -386,7 +389,12 @@ abstract class IrModuleDeserializer(
val field = if (proto.hasField()) deserializeIrSymbol(proto.field) as IrFieldSymbol else null
val getter = if (proto.hasGetter()) deserializeIrSymbol(proto.getter) as IrSimpleFunctionSymbol else null
val setter = if (proto.hasSetter()) deserializeIrSymbol(proto.setter) as IrSimpleFunctionSymbol else null
val descriptor = WrappedPropertyDescriptor()
val descriptor =
if (proto.hasDescriptor())
deserializeDescriptorReference(proto.descriptor) as PropertyDescriptor
else
field?.descriptor as? WrappedPropertyDescriptor // If field's descriptor coincides with property's.
?: getterToPropertyDescriptorMap.getOrPut(getter!!) { WrappedPropertyDescriptor() }
val callable = IrPropertyReferenceImpl(
start, end, type,
@@ -531,7 +539,7 @@ abstract class IrModuleDeserializer(
val loopId = proto.loopId
loopIndex.getOrPut(loopId) { loop }
val label = if (proto.hasLabel()) proto.label else null
val label = if (proto.hasLabel()) deserializeString(proto.label) else null
val body = if (proto.hasBody()) deserializeExpression(proto.body) else null
val condition = deserializeExpression(proto.condition)
@@ -559,7 +567,7 @@ abstract class IrModuleDeserializer(
}
private fun deserializeBreak(proto: IrKlibProtoBuf.IrBreak, start: Int, end: Int, type: IrType): IrBreak {
val label = if (proto.hasLabel()) proto.label else null
val label = if (proto.hasLabel()) deserializeString(proto.label) else null
val loopId = proto.loopId
val loop = loopIndex[loopId]!!
val irBreak = IrBreakImpl(start, end, type, loop)
@@ -569,7 +577,7 @@ abstract class IrModuleDeserializer(
}
private fun deserializeContinue(proto: IrKlibProtoBuf.IrContinue, start: Int, end: Int, type: IrType): IrContinue {
val label = if (proto.hasLabel()) proto.label else null
val label = if (proto.hasLabel()) deserializeString(proto.label) else null
val loopId = proto.loopId
val loop = loopIndex[loopId]!!
val irContinue = IrContinueImpl(start, end, type, loop)
@@ -595,7 +603,7 @@ abstract class IrModuleDeserializer(
LONG
-> IrConstImpl.long(start, end, type, proto.long)
STRING
-> IrConstImpl.string(start, end, type, proto.string)
-> IrConstImpl.string(start, end, type, deserializeString(proto.string))
FLOAT
-> IrConstImpl.float(start, end, type, proto.float)
DOUBLE
@@ -684,7 +692,7 @@ abstract class IrModuleDeserializer(
origin: IrDeclarationOrigin
): IrTypeParameter {
val symbol = deserializeIrSymbol(proto.symbol) as IrTypeParameterSymbol
val name = Name.identifier(proto.name)
val name = Name.identifier(deserializeString(proto.name))
val variance = deserializeIrTypeVariance(proto.variance)
val parameter = symbolTable.declareGlobalTypeParameter(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
@@ -733,7 +741,7 @@ abstract class IrModuleDeserializer(
IrValueParameterImpl(
start, end, origin,
paramSymbol,
proto.name.let { if (paramSymbol.descriptor is ReceiverParameterDescriptor) Name.special(it) else Name.identifier(it) },
deserializeString(proto.name).let { if (paramSymbol.descriptor is ReceiverParameterDescriptor) Name.special(it) else Name.identifier(it) },
proto.index,
deserializeIrType(proto.type),
varargElementType,
@@ -755,11 +763,11 @@ abstract class IrModuleDeserializer(
val modality = deserializeModality(proto.modality)
val clazz = symbolTable.declareClass(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
symbol.descriptor, modality) { symbol ->
symbol.descriptor, modality) {
IrClassImpl(
start, end, origin,
symbol,
proto.name.let { if (it.startsWith('<')) Name.special(it) else Name.identifier(it) },
it,
deserializeString(proto.name).let { if (it.startsWith('<')) Name.special(it) else Name.identifier(it) },
deserializeClassKind(proto.kind),
deserializeVisibility(proto.visibility),
modality,
@@ -814,7 +822,7 @@ abstract class IrModuleDeserializer(
private fun deserializeIrFunction(
proto: IrKlibProtoBuf.IrFunction,
start: Int, end: Int, origin: IrDeclarationOrigin, correspondingProperty: IrProperty? = null
start: Int, end: Int, origin: IrDeclarationOrigin, isAccessor: Boolean
): IrSimpleFunction {
logger.log { "### deserializing IrFunction ${proto.base.name}" }
@@ -824,7 +832,7 @@ abstract class IrModuleDeserializer(
symbol.descriptor, {
IrFunctionImpl(
start, end, origin, it,
proto.base.name.let { if (correspondingProperty != null) Name.special(it) else Name.identifier(it) },
deserializeString(proto.base.name).let { if (isAccessor) Name.special(it) else Name.identifier(it) },
deserializeVisibility(proto.base.visibility),
deserializeModality(proto.modality),
deserializeIrType(proto.base.returnType),
@@ -839,7 +847,7 @@ abstract class IrModuleDeserializer(
val overridden = proto.overriddenList.map { deserializeIrSymbol(it) as IrSimpleFunctionSymbol }
function.overriddenSymbols.addAll(overridden)
function.correspondingProperty = correspondingProperty
// function.correspondingProperty = correspondingProperty
return function
}
@@ -861,7 +869,7 @@ abstract class IrModuleDeserializer(
end,
origin,
symbol,
Name.identifier(proto.name),
Name.identifier(deserializeString(proto.name)),
type,
proto.isVar,
proto.isConst,
@@ -883,7 +891,7 @@ abstract class IrModuleDeserializer(
irrelevantOrigin,
symbol.descriptor
) {
IrEnumEntryImpl(start, end, origin, it, Name.identifier(proto.name))
IrEnumEntryImpl(start, end, origin, it, Name.identifier(deserializeString(proto.name)))
}
if (proto.hasCorrespondingClass()) {
@@ -908,8 +916,8 @@ abstract class IrModuleDeserializer(
return initializer
}
private fun deserializeVisibility(value: String): Visibility { // TODO: switch to enum
return when (value) {
private fun deserializeVisibility(value: IrKlibProtoBuf.Visibility): Visibility { // TODO: switch to enum
return when (deserializeString(value.name)) {
"public" -> Visibilities.PUBLIC
"private" -> Visibilities.PRIVATE
"private_to_this" -> Visibilities.PRIVATE_TO_THIS
@@ -934,7 +942,7 @@ abstract class IrModuleDeserializer(
IrConstructorImpl(
start, end, origin,
it,
Name.special(proto.base.name),
Name.special(deserializeString(proto.base.name)),
deserializeVisibility(proto.base.visibility),
deserializeIrType(proto.base.returnType),
proto.base.isInline,
@@ -960,7 +968,7 @@ abstract class IrModuleDeserializer(
{ IrFieldImpl(
start, end, origin,
it,
Name.identifier(proto.name),
Name.identifier(deserializeString(proto.name)),
type,
deserializeVisibility(proto.visibility),
proto.isFinal,
@@ -990,18 +998,25 @@ abstract class IrModuleDeserializer(
origin: IrDeclarationOrigin
): IrProperty {
val backingField = if (proto.hasBackingField()) {
deserializeIrField(proto.backingField, start, end, origin)
} else null
val backingField = if (proto.hasBackingField()) deserializeIrField(proto.backingField, start, end, origin) else null
val getter = if (proto.hasGetter()) deserializeIrFunction(proto.getter, start, end, origin, true) else null
val setter = if (proto.hasSetter()) deserializeIrFunction(proto.setter, start, end, origin, true) else null
backingField?.let { (it.descriptor as? WrappedFieldDescriptor)?.bind(it) }
getter?.let { (it.descriptor as? WrappedSimpleFunctionDescriptor)?.bind(it) }
setter?.let { (it.descriptor as? WrappedSimpleFunctionDescriptor)?.bind(it) }
val descriptor =
if (proto.hasDescriptor()) deserializeDescriptorReference(proto.descriptor) as PropertyDescriptor else null
?: WrappedPropertyDescriptor()
if (proto.hasDescriptor())
deserializeDescriptorReference(proto.descriptor) as PropertyDescriptor
else
backingField?.descriptor as? WrappedPropertyDescriptor // If field's descriptor coincides with property's.
?: getterToPropertyDescriptorMap.getOrPut(getter!!.symbol) { WrappedPropertyDescriptor() }
val property = IrPropertyImpl(
start, end, origin,
descriptor,
Name.identifier(proto.name),
Name.identifier(deserializeString(proto.name)),
deserializeVisibility(proto.visibility),
deserializeModality(proto.modality),
proto.isVar,
@@ -1023,29 +1038,34 @@ abstract class IrModuleDeserializer(
}
*/
property.backingField = backingField
property.getter = getter
property.setter = setter
backingField?.let { it.correspondingProperty = property }
getter?.let { it.correspondingProperty = property }
setter?.let { it.correspondingProperty = property }
property.getter =
if (proto.hasGetter()) deserializeIrFunction(proto.getter, start, end, origin, property) else null
property.setter =
if (proto.hasSetter()) deserializeIrFunction(proto.setter, start, end, origin, property) else null
// property.getter?.let { (it.descriptor as? WrappedSimpleFunctionDescriptor)?.bind(it) }
// property.setter?.let { (it.descriptor as? WrappedSimpleFunctionDescriptor)?.bind(it) }
property.getter?.let {
val descriptor = it.descriptor
if (descriptor is WrappedSimpleFunctionDescriptor) descriptor.bind(it)
symbolTable.declareSimpleFunction(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
descriptor, { symbol -> it })
}
property.setter?.let {
val descriptor = it.descriptor
if (descriptor is WrappedSimpleFunctionDescriptor) descriptor.bind(it)
symbolTable.declareSimpleFunction(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
descriptor, { symbol -> it })
}
// property.getter =
// if (proto.hasGetter()) deserializeIrFunction(proto.getter, start, end, origin, property) else null
// property.setter =
// if (proto.hasSetter()) deserializeIrFunction(proto.setter, start, end, origin, property) else null
//
//// property.getter?.let { (it.descriptor as? WrappedSimpleFunctionDescriptor)?.bind(it) }
//// property.setter?.let { (it.descriptor as? WrappedSimpleFunctionDescriptor)?.bind(it) }
//
// property.getter?.let {
// val descriptor = it.descriptor
// if (descriptor is WrappedSimpleFunctionDescriptor) descriptor.bind(it)
// symbolTable.declareSimpleFunction(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
// descriptor, { symbol -> it })
//
// }
// property.setter?.let {
// val descriptor = it.descriptor
// if (descriptor is WrappedSimpleFunctionDescriptor) descriptor.bind(it)
// symbolTable.declareSimpleFunction(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
// descriptor, { symbol -> it })
// }
return property
}
@@ -1063,12 +1083,13 @@ abstract class IrModuleDeserializer(
IrDeclarationOrigin::class.nestedClasses.toList() + DeclarationFactory.FIELD_FOR_OUTER_THIS::class
val originIndex = allKnownOrigins.map { it.objectInstance as IrDeclarationOriginImpl }.associateBy { it.name }
val irrelevantOrigin = object : IrDeclarationOriginImpl("irrelevant") {}
fun deserializeIrDeclarationOrigin(proto: IrKlibProtoBuf.IrDeclarationOrigin) = originIndex[deserializeString(proto.custom)]!!
protected fun deserializeDeclaration(proto: IrKlibProtoBuf.IrDeclaration, parent: IrDeclarationParent?): IrDeclaration {
val start = proto.coordinates.startOffset
val end = proto.coordinates.endOffset
val origin = originIndex[proto.origin.name]!!
val origin = deserializeIrDeclarationOrigin(proto.origin)
val declarator = proto.declarator
@@ -1082,7 +1103,7 @@ abstract class IrModuleDeserializer(
IR_CLASS
-> deserializeIrClass(declarator.irClass, start, end, origin)
IR_FUNCTION
-> deserializeIrFunction(declarator.irFunction, start, end, origin)
-> deserializeIrFunction(declarator.irFunction, start, end, origin, false)
IR_PROPERTY
-> deserializeIrProperty(declarator.irProperty, start, end, origin)
IR_TYPE_ALIAS
@@ -1104,8 +1125,6 @@ abstract class IrModuleDeserializer(
parent?.let { declaration.parent = it }
val sourceFileName = proto.fileName
val descriptor = declaration.descriptor
if (descriptor is WrappedDeclarationDescriptor<*>) {
@@ -389,9 +389,20 @@ internal class IrModuleSerializer(
private fun serializeCall(call: IrCall): IrKlibProtoBuf.IrCall {
val proto = IrKlibProtoBuf.IrCall.newBuilder()
if (call.dispatchReceiver?.type is IrDynamicType) {
val declaration = call.symbol.owner
dynamicFile.run {
if (!declarations.contains(declaration)) {
declaration.parent = dynamicFile
declarations += declaration
}
}
}
proto.kind = irCallToPrimitiveKind(call)
proto.symbol = serializeIrSymbol(call.symbol)
call.superQualifierSymbol?.let {
proto.`super` = serializeIrSymbol(it)
}
@@ -657,68 +668,6 @@ internal class IrModuleSerializer(
return proto.build()
}
private fun serializeDynamicMemberExpression(expression: IrDynamicMemberExpression): IrKlibProtoBuf.IrDynamicMemberExpression {
val proto = IrKlibProtoBuf.IrDynamicMemberExpression.newBuilder()
.setMemberName(serializeString(expression.memberName))
.setReceiver(serializeExpression(expression.receiver))
return proto.build()
}
private fun serializeDynamicOperatorExpression(expression: IrDynamicOperatorExpression): IrKlibProtoBuf.IrDynamicOperatorExpression {
val proto = IrKlibProtoBuf.IrDynamicOperatorExpression.newBuilder()
.setOperator(serializeDynamicOperator(expression.operator))
.setReceiver(serializeExpression(expression.receiver))
expression.arguments.forEach { proto.addArgument(serializeExpression(it)) }
return proto.build()
}
private fun serializeDynamicOperator(operator: IrDynamicOperator) = when (operator) {
IrDynamicOperator.UNARY_PLUS -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.UNARY_PLUS
IrDynamicOperator.UNARY_MINUS -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.UNARY_MINUS
IrDynamicOperator.EXCL -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.EXCL
IrDynamicOperator.PREFIX_INCREMENT -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.PREFIX_INCREMENT
IrDynamicOperator.PREFIX_DECREMENT -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.PREFIX_DECREMENT
IrDynamicOperator.POSTFIX_INCREMENT -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.POSTFIX_INCREMENT
IrDynamicOperator.POSTFIX_DECREMENT -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.POSTFIX_DECREMENT
IrDynamicOperator.BINARY_PLUS -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.BINARY_PLUS
IrDynamicOperator.BINARY_MINUS -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.BINARY_MINUS
IrDynamicOperator.MUL -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.MUL
IrDynamicOperator.DIV -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.DIV
IrDynamicOperator.MOD -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.MOD
IrDynamicOperator.GT -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.GT
IrDynamicOperator.LT -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.LT
IrDynamicOperator.GE -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.GE
IrDynamicOperator.LE -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.LE
IrDynamicOperator.EQEQ -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.EQEQ
IrDynamicOperator.EXCLEQ -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.EXCLEQ
IrDynamicOperator.EQEQEQ -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.EQEQEQ
IrDynamicOperator.EXCLEQEQ -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.EXCLEQEQ
IrDynamicOperator.ANDAND -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.ANDAND
IrDynamicOperator.OROR -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.OROR
IrDynamicOperator.EQ -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.EQ
IrDynamicOperator.PLUSEQ -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.PLUSEQ
IrDynamicOperator.MINUSEQ -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.MINUSEQ
IrDynamicOperator.MULEQ -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.MULEQ
IrDynamicOperator.DIVEQ -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.DIVEQ
IrDynamicOperator.MODEQ -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.MODEQ
IrDynamicOperator.ARRAY_ACCESS -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.ARRAY_ACCESS
IrDynamicOperator.INVOKE -> IrKlibProtoBuf.IrDynamicOperatorExpression.IrDynamicOperator.INVOKE
}
private fun serializeBreak(expression: IrBreak): IrKlibProtoBuf.IrBreak {
val proto = IrKlibProtoBuf.IrBreak.newBuilder()
val label = expression.label?.let { serializeString(it) }
@@ -794,8 +743,6 @@ internal class IrModuleSerializer(
is IrVararg -> operationProto.vararg = serializeVararg(expression)
is IrWhen -> operationProto.`when` = serializeWhen(expression)
is IrWhileLoop -> operationProto.`while` = serializeWhile(expression)
is IrDynamicMemberExpression -> operationProto.dynamicMember = serializeDynamicMemberExpression(expression)
is IrDynamicOperatorExpression -> operationProto.dynamicOperator = serializeDynamicOperatorExpression(expression)
else -> {
TODO("Expression serialization not implemented yet: ${ir2string(expression)}.")
}
@@ -1127,7 +1074,7 @@ internal class IrModuleSerializer(
fun serializeModule(module: IrModuleFragment): IrKlibProtoBuf.IrModule {
val proto = IrKlibProtoBuf.IrModule.newBuilder()
.setName(serializeString(module.name.toString()))
module.addSyntheticDynamicFile()
module.files.forEach {
proto.addFile(serializeIrFile(it))
}
@@ -1146,6 +1093,31 @@ internal class IrModuleSerializer(
return proto.build()
}
private val dynamicPackage = KnownPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.dynamic"))
private lateinit var dynamicFile: IrFile
private fun IrModuleFragment.addSyntheticDynamicFile() {
dynamicFile = IrFileImpl(object : SourceManager.FileEntry {
override val name = Namer.DYNAMIC_FILE_NAME
override val maxOffset = UNDEFINED_OFFSET
override fun getSourceRangeInfo(beginOffset: Int, endOffset: Int) =
SourceRangeInfo(
"",
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
UNDEFINED_OFFSET
)
override fun getLineNumber(offset: Int) = UNDEFINED_OFFSET
override fun getColumnNumber(offset: Int) = UNDEFINED_OFFSET
}, dynamicPackage)
files += dynamicFile
}
fun serializedIrModule(module: IrModuleFragment): SerializedIr {
val moduleHeader = serializeModule(module).toByteArray()
return SerializedIr(moduleHeader, topLevelDeclarations, declarationTable.debugIndex)
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
class DescriptorReferenceSerializer(val declarationTable: DeclarationTable) {
class DescriptorReferenceSerializer(val declarationTable: DeclarationTable, val serializeString: (String) -> IrKlibProtoBuf.String) {
// Not all exported descriptors are deserialized, some a synthesized anew during metadata deserialization.
// Those created descriptors can't carry the uniqIdIndex, since it is available only for deserialized descriptors.
@@ -72,9 +72,9 @@ class DescriptorReferenceSerializer(val declarationTable: DeclarationTable) {
uniqId?.let { declarationTable.descriptors.put(discoverableDescriptorsDeclaration.descriptor, it) }
val proto = IrKlibProtoBuf.DescriptorReference.newBuilder()
.setPackageFqName(packageFqName)
.setClassFqName(classFqName)
.setName(descriptor.name.toString())
.setPackageFqName(serializeString(packageFqName))
.setClassFqName(serializeString(classFqName))
.setName(serializeString(descriptor.name.toString()))
if (uniqId != null) proto.setUniqId(protoUniqId(uniqId))
@@ -5,9 +5,9 @@ option java_outer_classname = "IrKlibProtoBuf";
option optimize_for = LITE_RUNTIME;
message DescriptorReference {
required string package_fq_name = 1;
required string class_fq_name = 2;
required string name = 3;
required String package_fq_name = 1;
required String class_fq_name = 2;
required String name = 3;
optional UniqId uniq_id = 4;
optional bool is_getter = 5 [default = false];
optional bool is_setter = 6 [default = false];
@@ -28,28 +28,85 @@ message Coordinates {
required int32 end_offset = 2;
}
message Visibility {
required String name = 1;
}
message IrStatementOrigin {
required String name = 1;
}
enum KnownOrigin {
CUSTOM = 1;
DEFINED = 2;
FAKE_OVERRIDE = 3;
FOR_LOOP_ITERATOR = 4;
FOR_LOOP_VARIABLE = 5;
FOR_LOOP_IMPLICIT_VARIABLE = 6;
PROPERTY_BACKING_FIELD = 7;
DEFAULT_PROPERTY_ACCESSOR = 8;
DELEGATE = 9;
DELEGATED_PROPERTY_ACCESSOR = 10;
DELEGATED_MEMBER = 11;
ENUM_CLASS_SPECIAL_MEMBER = 12;
FUNCTION_FOR_DEFAULT_PARAMETER = 13;
FILE_CLASS = 14;
GENERATED_DATA_CLASS_MEMBER = 15;
GENERATED_INLINE_CLASS_MEMBER = 16;
LOCAL_FUNCTION_FOR_LAMBDA = 17;
CATCH_PARAMETER = 19;
INSTANCE_RECEIVER = 20;
PRIMARY_CONSTRUCTOR_PARAMETER = 21;
IR_TEMPORARY_VARIABLE = 22;
IR_EXTERNAL_DECLARATION_STUB = 23;
IR_EXTERNAL_JAVA_DECLARATION_STUB = 24;
IR_BUILTINS_STUB = 25;
BRIDGE = 26;
FIELD_FOR_ENUM_ENTRY = 27;
FIELD_FOR_ENUM_VALUES = 28;
FIELD_FOR_OBJECT_INSTANCE = 29;
}
message IrDeclarationOrigin {
oneof either {
KnownOrigin origin = 1;
String custom = 2;
}
}
/* ------ Top Level---------------------------------------------- */
message IrDeclarationContainer {
repeated IrDeclaration declaration = 1;
}
message FileEntry { // TODO: extend me.
required string name = 1;
message FileEntry {
required String name = 1;
repeated int32 line_start_offsets = 2;
}
message IrFile {
repeated UniqId declaration_id = 1;
required FileEntry file_entry = 2;
// TODO: we need a better string management. See metadata serialization as an example.
required string fq_name = 3;
required String fq_name = 3;
}
message IrModule {
required string name = 1;
required String name = 1;
repeated IrFile file = 2;
required IrSymbolTable symbol_table = 3;
required IrTypeTable type_table = 4;
required StringTable string_table = 5;
}
/* ------ String Table ------------------------------------------ */
message String {
required int32 index = 1;
}
message StringTable {
repeated string strings = 1;
}
/* ------ IrSymbols --------------------------------------------- */
@@ -74,7 +131,7 @@ message IrSymbolData {
required IrSymbolKind kind = 1;
required UniqId uniq_id = 2;
required UniqId top_level_uniq_id = 3;
optional string fqname = 4;
optional String fqname = 4;
optional DescriptorReference descriptor_reference = 5;
}
@@ -153,7 +210,7 @@ message IrTypeIndex {
message IrBreak {
required int32 loop_id = 1;
optional string label = 2;
optional String label = 2;
}
message IrBlock {
@@ -183,7 +240,7 @@ message IrCall {
message IrFunctionReference {
required IrSymbol symbol = 1;
optional string origin = 2;
optional IrStatementOrigin origin = 2;
required MemberAccessCommon member_access = 3;
}
@@ -192,8 +249,9 @@ message IrPropertyReference {
optional IrSymbol field = 1;
optional IrSymbol getter = 2;
optional IrSymbol setter = 3;
optional string origin = 4;
optional IrStatementOrigin origin = 4;
required MemberAccessCommon member_access = 5;
optional DescriptorReference descriptor = 6; // IrProperty doesn't have a symbol at all. Preserve this rudiment for now.
}
message IrComposite {
@@ -216,13 +274,13 @@ message IrConst {
int64 long = 7;
float float = 8;
double double = 9;
string string = 10;
String string = 10;
}
}
message IrContinue {
required int32 loop_id = 1;
optional string label = 2;
optional String label = 2;
}
message IrDelegatingConstructorCall {
@@ -272,7 +330,7 @@ message IrInstanceInitializerCall {
message Loop {
required int32 loop_id = 1;
required IrExpression condition = 2;
optional string label = 3;
optional String label = 3;
optional IrExpression body = 4;
}
@@ -411,8 +469,8 @@ message IrFunction {
}
message IrFunctionBase {
required string name = 1;
required string visibility = 2;
required String name = 1;
required Visibility visibility = 2;
required bool is_inline = 3;
required bool is_external = 4;
required IrTypeParameterContainer type_parameters = 5;
@@ -433,8 +491,8 @@ message IrConstructor {
message IrField {
required IrSymbol symbol = 1;
optional IrExpression initializer = 2;
required string name = 3;
required string visibility = 4;
required String name = 3;
required Visibility visibility = 4;
required bool is_final = 5;
required bool is_external = 6;
required bool is_static = 7;
@@ -443,8 +501,8 @@ message IrField {
message IrProperty {
optional DescriptorReference descriptor = 1; // IrProperty doesn't have a symbol at all. Preserve this rudiment for now.
required string name = 2;
required string visibility = 3;
required String name = 2;
required Visibility visibility = 3;
required ModalityKind modality = 4;
required bool is_var = 5;
required bool is_const = 6;
@@ -457,7 +515,7 @@ message IrProperty {
}
message IrVariable {
required string name = 1;
required String name = 1;
required IrSymbol symbol = 2;
required IrTypeIndex type = 3;
required bool is_var = 4;
@@ -484,7 +542,7 @@ enum ModalityKind { // It is ModalityKind to not clash with Modality in descript
message IrValueParameter {
required IrSymbol symbol = 1;
required string name = 2;
required String name = 2;
required int32 index = 3;
required IrTypeIndex type = 4;
optional IrTypeIndex vararg_element_type = 5;
@@ -495,7 +553,7 @@ message IrValueParameter {
message IrTypeParameter {
required IrSymbol symbol = 1;
required string name = 2;
required String name = 2;
required int32 index = 3;
required IrTypeVariance variance = 4;
repeated IrTypeIndex super_type = 5;
@@ -508,9 +566,9 @@ message IrTypeParameterContainer {
message IrClass {
required IrSymbol symbol = 1;
required string name = 2;
required String name = 2;
required ClassKind kind = 3;
required string visibility = 4;
required Visibility visibility = 4;
required ModalityKind modality = 5;
// TODO: consider using flags for the booleans.
required bool is_companion = 6;
@@ -528,7 +586,7 @@ message IrEnumEntry {
required IrSymbol symbol = 1;
optional IrExpression initializer = 2;
optional IrDeclaration corresponding_class = 3;
required string name = 4;
required String name = 4;
}
message IrAnonymousInit {
@@ -554,17 +612,11 @@ message IrDeclarator {
}
}
message IrDeclarationOrigin {
required string name = 1;
}
message IrDeclaration {
required IrDeclarationOrigin origin = 1;
required Coordinates coordinates = 2;
required Annotations annotations = 3;
required IrDeclarator declarator = 4;
//repeated IrDeclaration nested = 5;
required string file_name = 5; // TODO: files should be communicated some other way, I suppose.
}
/* ------- IrStatements --------------------------------------------- */
@@ -58,6 +58,7 @@ abstract class IrLazyDeclarationBase(
val containingDeclaration =
((currentDescriptor as? PropertyAccessorDescriptor)?.correspondingProperty ?: currentDescriptor).containingDeclaration
return when (containingDeclaration) {
is PackageFragmentDescriptor -> stubGenerator.generateOrGetEmptyExternalPackageFragmentStub(containingDeclaration).also {
it.declarations.add(this)
@@ -15,9 +15,7 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.toIrType
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
@@ -98,8 +96,8 @@ class IrBuiltIns(
builtIns.nothing to IrTypeMapper({ nothingType }, { nothingNType }),
builtIns.unit to IrTypeMapper({ unitType }, { buildNullableType(unitType) }),
builtIns.string to IrTypeMapper({ stringType }, { buildNullableType(stringType) }),
builtIns.throwable to IrTypeMapper({ throwableType }, { buildNullableType(throwableType) })
// builtIns.array to { arrayClass.owner.defaultType }
builtIns.throwable to IrTypeMapper({ throwableType }, { buildNullableType(throwableType) }),
builtIns.array to IrTypeMapper({ arrayType }, { buildNullableType(arrayType) })
)
fun getPrimitiveTypeOrNullByDescriptor(descriptor: ClassifierDescriptor, isNullable: Boolean) =
@@ -165,6 +163,7 @@ class IrBuiltIns(
val collectionClass by lazy { builtIns.collection.toIrSymbol() }
val arrayType by lazy { builtIns.array.toIrType(symbolTable = symbolTable) }
val arrayClass by lazy { builtIns.array.toIrSymbol() }
val throwableType by lazy { builtIns.throwable.defaultType.toIrType() }
@@ -70,6 +70,7 @@ fun IrType.makeNullable(addKotlinType:Boolean = true) =
else
this
// TODO: get rid of this
var irTypeKotlinBuiltIns: KotlinBuiltIns? = null
fun IrType.toKotlinType(): KotlinType {