[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}" } assert(++numberOfCalls == 1) { "More than one delegating constructor call: ${symbol.owner}" }
val delegatingClass = expression.symbol.owner.parent as IrClass val delegatingClass = expression.symbol.owner.parent as IrClass
// TODO: figure out why Lazy IR multiplies Declarations for descriptors and fix it // TODO: figure out why Lazy IR multiplies Declarations for descriptors and fix it
if (delegatingClass.descriptor == superClass.classifierOrFail.descriptor || ( // It happens because of IrBuiltIns whose IrDeclarations are different for runtime and test
delegatingClass.defaultType.isAny() && superClass.isAny() if (delegatingClass.descriptor == superClass.classifierOrFail.descriptor)
))
callsSuper = true callsSuper = true
else if (delegatingClass.descriptor != constructedClass.descriptor) else if (delegatingClass.descriptor != constructedClass.descriptor)
throw AssertionError( throw AssertionError(
@@ -154,7 +154,7 @@ class JsIrBackendContext(
val coroutineSuspendOrReturn = val coroutineSuspendOrReturn =
symbolTable.referenceSimpleFunction(getInternalFunctions(COROUTINE_SUSPEND_OR_RETURN_JS_NAME).single()) 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() private val operatorMap = referenceOperators()
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.ir.backend.js package org.jetbrains.kotlin.ir.backend.js
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.common.CompilerPhaseManager
import org.jetbrains.kotlin.backend.common.LoggingContext import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.functionInterfacePackageFragmentProvider import org.jetbrains.kotlin.builtins.functions.functionInterfacePackageFragmentProvider
@@ -85,7 +84,7 @@ fun compile(
TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext) TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext)
val symbolTable = SymbolTable() val symbolTable = SymbolTable()
// irDependencyModules.forEach { symbolTable.loadModule(it) } if (!isKlibCompilation) irDependencyModules.forEach { symbolTable.loadModule(it) }
val psi2IrTranslator = Psi2IrTranslator(configuration.languageVersionSettings) val psi2IrTranslator = Psi2IrTranslator(configuration.languageVersionSettings)
val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext, symbolTable) val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext, symbolTable)
@@ -105,6 +104,10 @@ fun compile(
if (isKlibCompilation) { if (isKlibCompilation) {
val logggg = object : LoggingContext { val logggg = object : LoggingContext {
override var inVerbosePhase: Boolean
get() = TODO("not implemented")
set(_) {}
override fun log(message: () -> String) {} override fun log(message: () -> String) {}
} }
@@ -173,8 +176,7 @@ fun compile(
) )
md.initialize(CompositePackageFragmentProvider(packageProviders)) md.initialize(CompositePackageFragmentProvider(packageProviders))
md.setDependencies(listOf(md/*, builtIns.builtInsModule*/)) md.setDependencies(listOf(md))
val st = SymbolTable() val st = SymbolTable()
@@ -198,7 +200,7 @@ fun compile(
deserializedModuleFragment.replaceUnboundSymbols(context) deserializedModuleFragment.replaceUnboundSymbols(context)
jsPhases.invokeToplevel(context.phaseConfig, context, moduleFragment) jsPhases.invokeToplevel(context.phaseConfig, context, deserializedModuleFragment)
return Result(md, context.jsProgram.toString(), null) return Result(md, context.jsProgram.toString(), null)
} else { } else {
@@ -55,9 +55,9 @@ fun ReferenceSymbolTable.translateErased(type: KotlinType): IrSimpleType {
internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context, internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
val typeArguments: Map<IrTypeParameterSymbol, IrType?>?, 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. // Create new symbols.
irElement.acceptVoid(symbolRemapper) 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) private class SymbolRemapperImpl(descriptorsRemapper: DescriptorsRemapper)
: DeepCopySymbolRemapper(descriptorsRemapper) { : DeepCopySymbolRemapper(descriptorsRemapper) {
@@ -232,857 +230,4 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
InlinerTypeRemapper(symbolRemapper, typeArguments), InlinerTypeRemapper(symbolRemapper, typeArguments),
InlinerSymbolRenamer() 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 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.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder 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.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext 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.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.types.irTypeKotlinBuiltIns import org.jetbrains.kotlin.ir.types.irTypeKotlinBuiltIns
import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.file import org.jetbrains.kotlin.ir.util.file
import org.jetbrains.kotlin.ir.util.getArguments import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.parentAsClass 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.name.FqName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.inline.InlineUtil 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 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 // backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt
internal class FunctionInlining(val context: Context): IrElementTransformerWithContext<Ref<Boolean>>() { internal class FunctionInlining(val context: Context): IrElementTransformerVoidWithContext() {
// TODO private val deserializer = DeserializerDriver(context)
private val globalSubstituteMap = mutableMapOf<DeclarationDescriptor, SubstitutedDescriptor>()
private val inlineFunctions = mutableMapOf<FunctionDescriptor, Boolean>()
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun inline(irModule: IrModuleFragment): IrElement { fun inline(irModule: IrModuleFragment): IrElement {
irTypeKotlinBuiltIns = irModule.irBuiltins.builtIns irTypeKotlinBuiltIns = irModule.irBuiltins.builtIns
val transformedModule = irModule.accept(this, Ref(false)) return irModule.accept(this, data = null)
DescriptorSubstitutorForExternalScope(globalSubstituteMap, context).run(transformedModule) // Transform calls to object that might be returned from inline function call.
return transformedModule
} }
override fun visitFunctionNew(declaration: IrFunction, data: Ref<Boolean>): IrStatement { override fun visitCall(expression: IrCall): IrExpression {
val descriptor = declaration.descriptor val callSite = super.visitCall(expression) as IrCall
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
val functionDescriptor = callSite.descriptor 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. val callee = getFunctionDeclaration(callSite.symbol) // Get declaration of the function to be inlined.
if (callee == null) { // We failed to get the declaration. callee.transformChildrenVoid(this) // Process recursive inline.
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 childIsBad = Ref(inlineFunctions[functionDescriptor] ?: false) val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull()
callee.first.transformChildren(this, childIsBad) // Process recursive inline. val inliner = Inliner(callSite, callee, currentScope!!, parent, context)
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)
// Create inliner for this scope. // Create inliner for this scope.
return inliner.inline() // Return newly created IrInlineBody instead of IrCall. 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 descriptor = symbol.descriptor.original
val originalDescriptor = functionDescriptor.resolveFakeOverride().original // val originalDescriptor = functionDescriptor.resolveFakeOverride().original
val functionDeclaration = val languageVersionSettings = context.configuration.languageVersionSettings
context.originalModuleIndex.functions[originalDescriptor] ?: context.symbolTable.referenceDeclaredFunction(originalDescriptor).owner
// ?: // If function is declared in the current module. // TODO: Remove these hacks when coroutine intrinsics are fixed.
// TODO deserializer.deserializeInlineBody(originalDescriptor) // Function is declared in another module. return when {
return (functionDeclaration as IrFunction?)?.let { it to false } // 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") // TODO: should we keep this at all?
private val FunctionDescriptor.isInlineConstructor get() = annotations.hasAnnotation(inlineConstructor) private val inlineConstructor = FqName("kotlin.native.internal.InlineConstructor")
private val FunctionDescriptor.isInlineConstructor get() = annotations.hasAnnotation(inlineConstructor)
//-----------------------------------------------------------------------------// //-----------------------------------------------------------------------------//
private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>, private inner class Inliner(
val callSite: IrCall, val callSite: IrCall,
val callee: IrFunction, val callee: IrFunction,
val local: Boolean, val currentScope: ScopeWithIr,
val currentScope: ScopeWithIr, val parent: IrDeclarationParent?,
val parent: IrDeclarationParent?, val context: Context
val context: Context, ) {
val owner: FunctionInlining /*TODO: make inner*/) {
val copyIrElement = val copyIrElement = run {
if (!local) val typeParameters =
DeepCopyIrTreeWithDescriptors(callee.descriptor, currentScope.scope.scopeOwner, if (callee is IrConstructor)
context, createTypeSubstitutor(callSite)) callee.parentAsClass.typeParameters
else { else callee.typeParameters
val typeParameters = val typeArguments =
if (callee is IrConstructor) (0 until callSite.typeArgumentsCount).map {
callee.parentAsClass.typeParameters typeParameters[it].symbol to callSite.getTypeArgument(it)
else callee.typeParameters }.associate { it }
val typeArguments = DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent)
(0 until callSite.typeArgumentsCount).map { }
typeParameters[it].symbol to callSite.getTypeArgument(it)
}.associate { it } val substituteMap = mutableMapOf<ValueDescriptor, IrExpression>()
DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent)
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
/** val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copiedCallee.descriptor.original)
* TODO: JVM inliner crashed on attempt inline this function from transform.kt with: val descriptor = callee.descriptor.original
* j.l.IllegalStateException: Couldn't obtain compiled function body for val startOffset = callee.startOffset
* public inline fun <reified T : org.jetbrains.kotlin.ir.IrElement> kotlin.collections.MutableList<T>.transform... val endOffset = callee.endOffset
*/ val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
private inline fun <reified T : IrElement> MutableList<T>.transform(transformation: (T) -> IrElement) {
forEachIndexed { i, item ->
set(i, transformation(item) as T)
}
}
private fun inlineFunction(callSite: IrCall, callee: IrFunction): IrReturnableBlockImpl { if (descriptor.isInlineConstructor) {
val copiedCallee = copyIrElement.copy(callee) as IrFunction val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
irBuilder.run {
val evaluationStatements = evaluateArguments(callSite, copiedCallee) val constructorDescriptor = delegatingConstructorCall.descriptor.original
val statements = (copiedCallee.body as IrBlockBody).statements val constructorCall = irCall(delegatingConstructorCall.symbol, callSite.type,
constructorDescriptor.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply {
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copiedCallee.descriptor.original) constructorDescriptor.valueParameters.forEach {
val descriptor = callee.descriptor.original putValueArgument(
val startOffset = callee.startOffset it,
val endOffset = callee.endOffset delegatingConstructorCall.getValueArgument(it)
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset) )
}
if (descriptor.isInlineConstructor) { }
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter
irBuilder.run { val newThis = currentScope.scope.createTemporaryVariable(
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, irExpression = constructorCall,
nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this" nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this"
) )
statements[0] = newThis statements[0] = newThis
substituteMap[oldThis] = irGet(newThis) substituteMap[oldThis] = irGet(newThis)
statements.add(irReturn(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
} }
})
}
}
//---------------------------------------------------------------------//
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 { val transformer = ParameterSubstitutor()
if (!isLambdaCall(expression)) statements.transform { it.transform(transformer, data = null) }
return super.visitCall(expression) statements.addAll(0, evaluationStatements)
val dispatchReceiver = expression.dispatchReceiver as IrGetValue return IrReturnableBlockImpl(
val functionArgument = substituteMap[dispatchReceiver.descriptor] startOffset = startOffset,
if (functionArgument == null) endOffset = endOffset,
return super.visitCall(expression) type = copiedCallee.returnType,
val dispatchDescriptor = dispatchReceiver.descriptor symbol = irReturnableBlockSymbol,
if (dispatchDescriptor is ValueParameterDescriptor && origin = null,
dispatchDescriptor.isNoinline) return super.visitCall(expression) statements = statements,
sourceFileSymbol = callee.file.symbol
).apply {
transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid(this)
if (functionArgument is IrFunctionReference) { if (expression.returnTargetSymbol == copiedCallee.symbol)
if (!functionArgument.isLambda) return super.visitCall(expression) 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 private inner class ParameterSubstitutor : IrElementTransformerVoid() {
val unboundArgsSet = unboundFunctionParameters.toSet()
val valueParameters = expression.getArguments().drop(1) // Skip dispatch receiver.
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, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
type = expression.type, type = expression.type,
symbol = functionArgument.symbol, symbol = functionArgument.symbol,
descriptor = functionArgument.descriptor).apply { descriptor = functionArgument.descriptor
functionParameters.forEach { ).apply {
val argument = functionParameters.forEach {
val argument =
if (!unboundArgsSet.contains(it)) if (!unboundArgsSet.contains(it))
boundFunctionParametersMap[it]!! boundFunctionParametersMap[it]!!
else else
valueParameters[unboundIndex++].second valueParameters[unboundIndex++].second
when (it) { when (it) {
functionDescriptor.dispatchReceiverParameter -> this.dispatchReceiver = argument functionDescriptor.dispatchReceiverParameter -> this.dispatchReceiver = argument
functionDescriptor.extensionReceiverParameter -> this.extensionReceiver = argument functionDescriptor.extensionReceiverParameter -> this.extensionReceiver = argument
else -> putValueArgument((it as ValueParameterDescriptor).index, 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 functionDeclaration = functionArgument.statements[0] as IrFunction
val newExpression = inlineFunction(expression, functionDeclaration) // Inline the lambda. Lambda parameters will be substituted with lambda arguments. val newExpression = inlineFunction(
return newExpression.transform(this, null) // Substitute lambda arguments with target function arguments. 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? { val isInlinableLambdaArgument: Boolean
if (irCall.typeArgumentsCount == 0) return null get() {
val descriptor = irCall.descriptor.resolveFakeOverride().original if (!InlineUtil.isInlineParameter(parameter.descriptor)) return false
val typeParameters = descriptor.propertyIfAccessor.typeParameters if (argumentExpression is IrFunctionReference
val substitutionContext = mutableMapOf<TypeConstructor, TypeProjection>() && !argumentExpression.descriptor.isSuspend
for (index in 0 until irCall.typeArgumentsCount) { ) return true // Skip suspend functions for now since it's not supported by FE anyway.
val typeArgument = irCall.getTypeArgument(index) ?: continue
substitutionContext[typeParameters[index].typeConstructor] = TypeProjectionImpl(typeArgument.toKotlinType()) // 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, private fun buildParameterToArgument(callSite: IrCall, callee: IrFunction): List<ParameterToArgument> {
val argumentExpression : IrExpression) {
val isInlinableLambdaArgument : Boolean val parameterToArgument = mutableListOf<ParameterToArgument>()
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 (callSite.dispatchReceiver != null && // Only if there are non null dispatch receivers both
if (argumentExpression !is IrBlock) return false callee.dispatchReceiverParameter != null
if (argumentExpression.origin != IrStatementOrigin.LAMBDA && ) // on call site and in function declaration.
argumentExpression.origin != IrStatementOrigin.ANONYMOUS_FUNCTION) return false parameterToArgument += ParameterToArgument(
val statements = argumentExpression.statements parameter = callee.dispatchReceiverParameter!!,
val irFunction = statements[0] argumentExpression = callSite.dispatchReceiver!!
val irCallableReference = statements[1] )
if (irFunction !is IrFunction) return false
if (irCallableReference !is IrCallableReference) return false
return true
}
val isImmutableVariableLoad: Boolean val valueArguments =
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 =
callSite.descriptor.valueParameters.map { callSite.getValueArgument(it) }.toMutableList() callSite.descriptor.valueParameters.map { callSite.getValueArgument(it) }.toMutableList()
if (callee.extensionReceiverParameter != null) { if (callee.extensionReceiverParameter != null) {
parameterToArgument += ParameterToArgument( parameterToArgument += ParameterToArgument(
parameter = callee.extensionReceiverParameter!!, parameter = callee.extensionReceiverParameter!!,
argumentExpression = if (callSite.extensionReceiver != null) { argumentExpression = if (callSite.extensionReceiver != null) {
callSite.extensionReceiver!! callSite.extensionReceiver!!
@@ -441,95 +346,103 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
// Special case: lambda with receiver is called as usual lambda: // Special case: lambda with receiver is called as usual lambda:
valueArguments.removeAt(0)!! valueArguments.removeAt(0)!!
} }
) )
} else if (callSite.extensionReceiver != null) { } else if (callSite.extensionReceiver != null) {
// Special case: usual lambda is called as lambda with receiver: // Special case: usual lambda is called as lambda with receiver:
valueArguments.add(0, callSite.extensionReceiver!!) valueArguments.add(0, callSite.extensionReceiver!!)
} }
val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>() val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>()
for (parameter in callee.valueParameters) { for (parameter in callee.valueParameters) {
val argument = valueArguments[parameter.index] val argument = valueArguments[parameter.index]
when { when {
argument != null -> { argument != null -> {
parameterToArgument += ParameterToArgument( parameterToArgument += ParameterToArgument(
parameter = parameter, parameter = parameter,
argumentExpression = argument argumentExpression = argument
) )
} }
// After ExpectDeclarationsRemoving pass default values from expect declarations // After ExpectDeclarationsRemoving pass default values from expect declarations
// are represented correctly in IR. // are represented correctly in IR.
parameter.defaultValue != null -> { // There is no argument - try default value. parameter.defaultValue != null -> { // There is no argument - try default value.
parametersWithDefaultToArgument += ParameterToArgument( parametersWithDefaultToArgument += ParameterToArgument(
parameter = parameter, parameter = parameter,
argumentExpression = parameter.defaultValue!!.expression argumentExpression = parameter.defaultValue!!.expression
) )
} }
parameter.varargElementType != null -> { parameter.varargElementType != null -> {
val emptyArray = IrVarargImpl( val emptyArray = IrVarargImpl(
startOffset = callSite.startOffset, startOffset = callSite.startOffset,
endOffset = callSite.endOffset, endOffset = callSite.endOffset,
type = parameter.type, type = parameter.type,
varargElementType = parameter.varargElementType!! varargElementType = parameter.varargElementType!!
) )
parameterToArgument += ParameterToArgument( parameterToArgument += ParameterToArgument(
parameter = parameter, parameter = parameter,
argumentExpression = emptyArray argumentExpression = emptyArray
) )
} }
else -> { else -> {
val message = "Incomplete expression: call to ${callee.descriptor} " + val message = "Incomplete expression: call to ${callee.descriptor} " +
"has no argument at index ${parameter.index}" "has no argument at index ${parameter.index}"
throw Error(message) 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 parameterToArgumentOld = buildParameterToArgument(callSite, callee)
val evaluationStatements = mutableListOf<IrStatement>() val evaluationStatements = mutableListOf<IrStatement>()
val substitutor = ParameterSubstitutor() val substitutor = ParameterSubstitutor()
parameterToArgumentOld.forEach { parameterToArgumentOld.forEach {
val parameterDescriptor = it.parameter.descriptor val parameterDescriptor = it.parameter.descriptor
/* /*
* We need to create temporary variable for each argument except inlinable lambda arguments. * 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, * For simplicity and to produce simpler IR we don't create temporaries for every immutable variable,
* not only for those referring to inlinable lambdas. * not only for those referring to inlinable lambdas.
*/ */
if (it.isInlinableLambdaArgument) { if (it.isInlinableLambdaArgument) {
substituteMap[parameterDescriptor] = it.argumentExpression substituteMap[parameterDescriptor] = it.argumentExpression
return@forEach 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
} }
return evaluationStatements
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
} }
} }
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.isFunctionOrKFunction import org.jetbrains.kotlin.ir.util.isFunctionOrKFunction
import org.jetbrains.kotlin.ir.util.isFunctionTypeOrSubtype import org.jetbrains.kotlin.ir.util.isFunctionTypeOrSubtype
import org.jetbrains.kotlin.ir.util.isKFunction
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.OverridingUtil import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -54,7 +55,7 @@ internal val FunctionDescriptor.isFunctionInvoke: Boolean
internal val IrFunction.isFunctionInvoke: Boolean internal val IrFunction.isFunctionInvoke: Boolean
get() { get() {
val dispatchReceiver = dispatchReceiverParameter ?: return false val dispatchReceiver = dispatchReceiverParameter ?: return false
assert(!dispatchReceiver.type.isFunctionTypeOrSubtype()) assert(!dispatchReceiver.type.isKFunction())
return dispatchReceiver.type.isFunctionTypeOrSubtype() && return dispatchReceiver.type.isFunctionTypeOrSubtype() &&
/*this.isOperator &&*/ this.name == OperatorNameConventions.INVOKE /*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.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.SourceManager
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.expressions.IrCall 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.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 internal const val SYNTHETIC_OFFSET = -2
class NaiveSourceBasedFileEntryImpl(override val name: String) : SourceManager.FileEntry { val File.lineStartOffsets: IntArray
get() {
private val lineStartOffsets: IntArray // 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()
init { // as in PSI.
val file = File(name) val separatorLength = System.lineSeparator().length
if (file.isFile) { val buffer = mutableListOf<Int>()
// TODO: could be incorrect, if file is not in system's line terminator format. var currentOffset = 0
// Maybe use (0..document.lineCount - 1) this.forEachLine { line ->
// .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
}
buffer.add(currentOffset) buffer.add(currentOffset)
lineStartOffsets = buffer.toIntArray() currentOffset += line.length + separatorLength
} else {
lineStartOffsets = IntArray(0)
} }
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 { 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 org.jetbrains.kotlin.resolve.jvm.modules.KOTLIN_STDLIB_MODULE_NAME
import java.util.regex.Pattern 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 { class DescriptorTable {
private val descriptors = mutableMapOf<DeclarationDescriptor, Long>() private val descriptors = mutableMapOf<DeclarationDescriptor, Long>()
fun put(descriptor: DeclarationDescriptor, uniqId: UniqId) { fun put(descriptor: DeclarationDescriptor, uniqId: UniqId) {
descriptors.putOnce(descriptor, uniqId.index) descriptors.getOrPut(descriptor) { uniqId.index }
} }
fun get(descriptor: DeclarationDescriptor) = descriptors[descriptor] fun get(descriptor: DeclarationDescriptor) = descriptors[descriptor]
} }
@@ -54,35 +47,27 @@ class DeclarationTable(val builtIns: IrBuiltIns, val descriptorTable: Descriptor
currentIndex += BUILT_IN_UNIQ_ID_GAP currentIndex += BUILT_IN_UNIQ_ID_GAP
} }
fun uniqIdByDeclaration(value: IrDeclaration): UniqId { fun uniqIdByDeclaration(value: IrDeclaration) = table.getOrPut(value) {
val index = table.getOrPut(value) { val index = if (isBuiltInFunction(value)) {
UniqId(FUNCTION_INDEX_START + builtInFunctionId(value), false)
if (isBuiltInFunction(value)) { } else if (value.origin == IrDeclarationOrigin.FAKE_OVERRIDE ||
UniqId(FUNCTION_INDEX_START + builtInFunctionId(value), false) !value.isExported()
} else if (value.origin == IrDeclarationOrigin.FAKE_OVERRIDE || || value is IrVariable
!value.isExported() || value is IrTypeParameter
|| value is IrVariable || value is IrValueParameter
|| value is IrTypeParameter || value is IrAnonymousInitializerImpl
|| value is IrValueParameter ) {
|| value is IrAnonymousInitializerImpl UniqId(currentIndex++, true)
) { } else {
UniqId(value.uniqIdIndex, false)
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)
}
} }
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.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor 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( fun deserializeDescriptorReference(
proto: IrKlibProtoBuf.DescriptorReference, packageFqNameString: String,
checkerDesc: (DeclarationDescriptor) -> Long?, classFqNameString: String,
checkerID: (Long) -> Boolean, name: String,
descriptorResolver: (FqName) -> DeclarationDescriptor index: Long?,
isEnumEntry: Boolean = false,
isEnumSpecial: Boolean = false,
isDefaultConstructor: Boolean = false,
isFakeOverride: Boolean = false,
isGetter: Boolean = false,
isSetter: Boolean = false
): DeclarationDescriptor { ): DeclarationDescriptor {
val packageFqName = val packageFqName = packageFqNameString.let {
if (proto.packageFqName == "<root>") FqName.ROOT else FqName(proto.packageFqName) // TODO: whould we store an empty string in the protobuf? if (it == "<root>") FqName.ROOT else FqName(it)
val classFqName = FqName(proto.classFqName) }// TODO: whould we store an empty string in the protobuf?
val protoIndex = if (proto.hasUniqId()) proto.uniqId.index else null
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()) Pair(null, currentModule.getPackage(packageFqName).memberScope.getContributedDescriptors())
} else { } else {
val clazz = currentModule.findClassAcrossModuleDependencies(ClassId(packageFqName, classFqName, false))!! val clazz = currentModule.findClassAcrossModuleDependencies(ClassId(packageFqName, classFqName, false))!!
Pair(clazz, clazz.unsubstitutedMemberScope.getContributedDescriptors() + clazz.getConstructors()) 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 = 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( if (!descriptor.fqNameUnsafe.asString().startsWith("cnames") && !descriptor.fqNameUnsafe.asString().startsWith(
"objcnames" "objcnames"
) )
@@ -53,27 +66,25 @@ class DescriptorReferenceDeserializer(val currentModule: ModuleDescriptor, val r
return descriptor return descriptor
} }
if (proto.isEnumEntry) { if (isEnumEntry) {
val name = proto.name
val memberScope = (clazz as DeserializedClassDescriptor).getUnsubstitutedMemberScope() val memberScope = (clazz as DeserializedClassDescriptor).getUnsubstitutedMemberScope()
return memberScope.getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BACKEND)!! return memberScope.getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BACKEND)!!
} }
if (proto.isEnumSpecial) { if (isEnumSpecial) {
val name = proto.name
return clazz!!.getStaticScope() return clazz!!.getStaticScope()
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single() .getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single()
} }
if (protoIndex?.let { checkerID(it) } == true) { if (protoIndex?.let { checkerID(it) } == true) {
return descriptorResolver(packageFqName.child(Name.identifier(proto.name))) return descriptorResolver(packageFqName.child(Name.identifier(name)))
} }
members.forEach { member -> members.forEach { member ->
if (proto.isDefaultConstructor && member is ClassConstructorDescriptor) return member if (isDefaultConstructor && member is ClassConstructorDescriptor) return member
val realMembers = 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 } member.resolveFakeOverrideMaybeAbstract().map { it.original }
else else
setOf(member) setOf(member)
@@ -82,13 +93,13 @@ class DescriptorReferenceDeserializer(val currentModule: ModuleDescriptor, val r
if (memberIndices.contains(protoIndex)) { if (memberIndices.contains(protoIndex)) {
return when { return when {
member is PropertyDescriptor && proto.isSetter -> member.setter!! member is PropertyDescriptor && isSetter -> member.setter!!
member is PropertyDescriptor && proto.isGetter -> member.getter!! member is PropertyDescriptor && isGetter -> member.getter!!
else -> member 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.backend.common.descriptors.*
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor 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.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.metadata.JsKlibMetadataSerializerProtocol 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.*
import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns 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.SymbolTable
import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
@@ -44,10 +43,15 @@ class IrKlibProtoBufModuleDeserializer(
var deserializedModuleDescriptor: ModuleDescriptor? = null var deserializedModuleDescriptor: ModuleDescriptor? = null
var deserializedModuleProtoSymbolTables = mutableMapOf<ModuleDescriptor, IrKlibProtoBuf.IrSymbolTable>() var deserializedModuleProtoSymbolTables = mutableMapOf<ModuleDescriptor, IrKlibProtoBuf.IrSymbolTable>()
var deserializedModuleProtoStringTables = mutableMapOf<ModuleDescriptor, IrKlibProtoBuf.StringTable>()
var deserializedModuleProtoTypeTables = mutableMapOf<ModuleDescriptor, IrKlibProtoBuf.IrTypeTable>() var deserializedModuleProtoTypeTables = mutableMapOf<ModuleDescriptor, IrKlibProtoBuf.IrTypeTable>()
val resolvedForwardDeclarations = mutableMapOf<UniqIdKey, UniqIdKey>() 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 moduleRoot = libraryDir
val irDirectory = File(libraryDir, "ir/") val irDirectory = File(libraryDir, "ir/")
@@ -94,7 +98,7 @@ class IrKlibProtoBufModuleDeserializer(
?: WrappedEnumEntryDescriptor() ?: WrappedEnumEntryDescriptor()
) )
IrKlibProtoBuf.IrSymbolKind.STANDALONE_FIELD_SYMBOL -> IrKlibProtoBuf.IrSymbolKind.STANDALONE_FIELD_SYMBOL ->
IrFieldSymbolImpl(WrappedFieldDescriptor()) symbolTable.referenceField(WrappedFieldDescriptor())
IrKlibProtoBuf.IrSymbolKind.FIELD_SYMBOL -> IrKlibProtoBuf.IrSymbolKind.FIELD_SYMBOL ->
symbolTable.referenceField( symbolTable.referenceField(
@@ -135,6 +139,9 @@ class IrKlibProtoBufModuleDeserializer(
return deserializeIrTypeData(typeData) return deserializeIrTypeData(typeData)
} }
override fun deserializeString(proto: IrKlibProtoBuf.String) =
deserializedModuleProtoStringTables[deserializedModuleDescriptor]!!.getStrings(proto.index)
fun deserializeIrSymbolData(proto: IrKlibProtoBuf.IrSymbolData): IrSymbol { fun deserializeIrSymbolData(proto: IrKlibProtoBuf.IrSymbolData): IrSymbol {
val key = proto.uniqId.uniqIdKey(deserializedModuleDescriptor!!) val key = proto.uniqId.uniqIdKey(deserializedModuleDescriptor!!)
val topLevelKey = proto.topLevelUniqId.uniqIdKey(deserializedModuleDescriptor!!) val topLevelKey = proto.topLevelUniqId.uniqIdKey(deserializedModuleDescriptor!!)
@@ -166,11 +173,18 @@ class IrKlibProtoBufModuleDeserializer(
} }
override fun deserializeDescriptorReference(proto: IrKlibProtoBuf.DescriptorReference) = override fun deserializeDescriptorReference(proto: IrKlibProtoBuf.DescriptorReference) =
descriptorReferenceDeserializer.deserializeDescriptorReference(proto, { descriptorReferenceDeserializer.deserializeDescriptorReference(
knownBuiltInsDescriptors[it]?.index ?: if (isBuiltInFunction(it)) FUNCTION_INDEX_START + builtInFunctionId(it) else null deserializeString(proto.packageFqName),
}, { (FUNCTION_INDEX_START + BUILT_IN_UNIQ_ID_CLASS_OFFSET) <= it && it < (FUNCTION_INDEX_START + BUILT_IN_UNIQ_ID_GAP) }, { deserializeString(proto.classFqName),
builtIns.builtIns.getBuiltInClassByFqName(it) 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 private val ByteArray.codedInputStream: org.jetbrains.kotlin.protobuf.CodedInputStream
get() { get() {
@@ -282,6 +296,9 @@ class IrKlibProtoBufModuleDeserializer(
classDescriptor, classDescriptor,
classDescriptor.modality classDescriptor.modality
) { symbol: IrClassSymbol -> IrClassImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, symbol) } ) { symbol: IrClassSymbol -> IrClassImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, symbol) }
.also {
it.parent = file
}
declaration declaration
} }
@@ -290,10 +307,13 @@ class IrKlibProtoBufModuleDeserializer(
} }
fun deserializeIrFile(fileProto: IrKlibProtoBuf.IrFile, moduleDescriptor: ModuleDescriptor, deserializeAllDeclarations: Boolean): IrFile { 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. // 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) val packageFragmentDescriptor = EmptyPackageFragmentDescriptor(moduleDescriptor, fqName)
@@ -316,18 +336,17 @@ class IrKlibProtoBufModuleDeserializer(
deserializedModuleDescriptor = moduleDescriptor deserializedModuleDescriptor = moduleDescriptor
deserializedModuleProtoSymbolTables.put(moduleDescriptor, proto.symbolTable) deserializedModuleProtoSymbolTables.put(moduleDescriptor, proto.symbolTable)
deserializedModuleProtoStringTables.put(moduleDescriptor, proto.stringTable)
deserializedModuleProtoTypeTables.put(moduleDescriptor, proto.typeTable) deserializedModuleProtoTypeTables.put(moduleDescriptor, proto.typeTable)
var i = 0
val files = proto.fileList.map { val files = proto.fileList.map {
i++
// if (i >= 41)
// descriptorReferenceDeserializer.doCrash = true
deserializeIrFile(it, moduleDescriptor, deserializeAllDeclarations) deserializeIrFile(it, moduleDescriptor, deserializeAllDeclarations)
} }
val module = IrModuleFragmentImpl(moduleDescriptor, builtIns, files) val module = IrModuleFragmentImpl(moduleDescriptor, builtIns, files)
module.patchDeclarationParents(null) 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 { 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 deserializeIrSymbol(proto: IrKlibProtoBuf.IrSymbol): IrSymbol
abstract fun deserializeIrType(proto: IrKlibProtoBuf.IrTypeIndex): IrType abstract fun deserializeIrType(proto: IrKlibProtoBuf.IrTypeIndex): IrType
abstract fun deserializeDescriptorReference(proto: IrKlibProtoBuf.DescriptorReference): DeclarationDescriptor abstract fun deserializeDescriptorReference(proto: IrKlibProtoBuf.DescriptorReference): DeclarationDescriptor
abstract fun deserializeString(proto: IrKlibProtoBuf.String): String
private fun deserializeTypeArguments(proto: IrKlibProtoBuf.TypeArguments): List<IrType> { private fun deserializeTypeArguments(proto: IrKlibProtoBuf.TypeArguments): List<IrType> {
logger.log { "### deserializeTypeArguments" } logger.log { "### deserializeTypeArguments" }
@@ -378,6 +379,8 @@ abstract class IrModuleDeserializer(
return IrInstanceInitializerCallImpl(start, end, symbol, builtIns.unitType) return IrInstanceInitializerCallImpl(start, end, symbol, builtIns.unitType)
} }
private val getterToPropertyDescriptorMap = mutableMapOf<IrSimpleFunctionSymbol, WrappedPropertyDescriptor>()
private fun deserializePropertyReference( private fun deserializePropertyReference(
proto: IrKlibProtoBuf.IrPropertyReference, proto: IrKlibProtoBuf.IrPropertyReference,
start: Int, end: Int, type: IrType 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 field = if (proto.hasField()) deserializeIrSymbol(proto.field) as IrFieldSymbol else null
val getter = if (proto.hasGetter()) deserializeIrSymbol(proto.getter) as IrSimpleFunctionSymbol 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 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( val callable = IrPropertyReferenceImpl(
start, end, type, start, end, type,
@@ -531,7 +539,7 @@ abstract class IrModuleDeserializer(
val loopId = proto.loopId val loopId = proto.loopId
loopIndex.getOrPut(loopId) { loop } 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 body = if (proto.hasBody()) deserializeExpression(proto.body) else null
val condition = deserializeExpression(proto.condition) 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 { 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 loopId = proto.loopId
val loop = loopIndex[loopId]!! val loop = loopIndex[loopId]!!
val irBreak = IrBreakImpl(start, end, type, loop) 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 { 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 loopId = proto.loopId
val loop = loopIndex[loopId]!! val loop = loopIndex[loopId]!!
val irContinue = IrContinueImpl(start, end, type, loop) val irContinue = IrContinueImpl(start, end, type, loop)
@@ -595,7 +603,7 @@ abstract class IrModuleDeserializer(
LONG LONG
-> IrConstImpl.long(start, end, type, proto.long) -> IrConstImpl.long(start, end, type, proto.long)
STRING STRING
-> IrConstImpl.string(start, end, type, proto.string) -> IrConstImpl.string(start, end, type, deserializeString(proto.string))
FLOAT FLOAT
-> IrConstImpl.float(start, end, type, proto.float) -> IrConstImpl.float(start, end, type, proto.float)
DOUBLE DOUBLE
@@ -684,7 +692,7 @@ abstract class IrModuleDeserializer(
origin: IrDeclarationOrigin origin: IrDeclarationOrigin
): IrTypeParameter { ): IrTypeParameter {
val symbol = deserializeIrSymbol(proto.symbol) as IrTypeParameterSymbol 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 variance = deserializeIrTypeVariance(proto.variance)
val parameter = symbolTable.declareGlobalTypeParameter(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, val parameter = symbolTable.declareGlobalTypeParameter(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
@@ -733,7 +741,7 @@ abstract class IrModuleDeserializer(
IrValueParameterImpl( IrValueParameterImpl(
start, end, origin, start, end, origin,
paramSymbol, 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, proto.index,
deserializeIrType(proto.type), deserializeIrType(proto.type),
varargElementType, varargElementType,
@@ -755,11 +763,11 @@ abstract class IrModuleDeserializer(
val modality = deserializeModality(proto.modality) val modality = deserializeModality(proto.modality)
val clazz = symbolTable.declareClass(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, val clazz = symbolTable.declareClass(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
symbol.descriptor, modality) { symbol -> symbol.descriptor, modality) {
IrClassImpl( IrClassImpl(
start, end, origin, start, end, origin,
symbol, it,
proto.name.let { if (it.startsWith('<')) Name.special(it) else Name.identifier(it) }, deserializeString(proto.name).let { if (it.startsWith('<')) Name.special(it) else Name.identifier(it) },
deserializeClassKind(proto.kind), deserializeClassKind(proto.kind),
deserializeVisibility(proto.visibility), deserializeVisibility(proto.visibility),
modality, modality,
@@ -814,7 +822,7 @@ abstract class IrModuleDeserializer(
private fun deserializeIrFunction( private fun deserializeIrFunction(
proto: IrKlibProtoBuf.IrFunction, proto: IrKlibProtoBuf.IrFunction,
start: Int, end: Int, origin: IrDeclarationOrigin, correspondingProperty: IrProperty? = null start: Int, end: Int, origin: IrDeclarationOrigin, isAccessor: Boolean
): IrSimpleFunction { ): IrSimpleFunction {
logger.log { "### deserializing IrFunction ${proto.base.name}" } logger.log { "### deserializing IrFunction ${proto.base.name}" }
@@ -824,7 +832,7 @@ abstract class IrModuleDeserializer(
symbol.descriptor, { symbol.descriptor, {
IrFunctionImpl( IrFunctionImpl(
start, end, origin, it, 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), deserializeVisibility(proto.base.visibility),
deserializeModality(proto.modality), deserializeModality(proto.modality),
deserializeIrType(proto.base.returnType), deserializeIrType(proto.base.returnType),
@@ -839,7 +847,7 @@ abstract class IrModuleDeserializer(
val overridden = proto.overriddenList.map { deserializeIrSymbol(it) as IrSimpleFunctionSymbol } val overridden = proto.overriddenList.map { deserializeIrSymbol(it) as IrSimpleFunctionSymbol }
function.overriddenSymbols.addAll(overridden) function.overriddenSymbols.addAll(overridden)
function.correspondingProperty = correspondingProperty // function.correspondingProperty = correspondingProperty
return function return function
} }
@@ -861,7 +869,7 @@ abstract class IrModuleDeserializer(
end, end,
origin, origin,
symbol, symbol,
Name.identifier(proto.name), Name.identifier(deserializeString(proto.name)),
type, type,
proto.isVar, proto.isVar,
proto.isConst, proto.isConst,
@@ -883,7 +891,7 @@ abstract class IrModuleDeserializer(
irrelevantOrigin, irrelevantOrigin,
symbol.descriptor symbol.descriptor
) { ) {
IrEnumEntryImpl(start, end, origin, it, Name.identifier(proto.name)) IrEnumEntryImpl(start, end, origin, it, Name.identifier(deserializeString(proto.name)))
} }
if (proto.hasCorrespondingClass()) { if (proto.hasCorrespondingClass()) {
@@ -908,8 +916,8 @@ abstract class IrModuleDeserializer(
return initializer return initializer
} }
private fun deserializeVisibility(value: String): Visibility { // TODO: switch to enum private fun deserializeVisibility(value: IrKlibProtoBuf.Visibility): Visibility { // TODO: switch to enum
return when (value) { return when (deserializeString(value.name)) {
"public" -> Visibilities.PUBLIC "public" -> Visibilities.PUBLIC
"private" -> Visibilities.PRIVATE "private" -> Visibilities.PRIVATE
"private_to_this" -> Visibilities.PRIVATE_TO_THIS "private_to_this" -> Visibilities.PRIVATE_TO_THIS
@@ -934,7 +942,7 @@ abstract class IrModuleDeserializer(
IrConstructorImpl( IrConstructorImpl(
start, end, origin, start, end, origin,
it, it,
Name.special(proto.base.name), Name.special(deserializeString(proto.base.name)),
deserializeVisibility(proto.base.visibility), deserializeVisibility(proto.base.visibility),
deserializeIrType(proto.base.returnType), deserializeIrType(proto.base.returnType),
proto.base.isInline, proto.base.isInline,
@@ -960,7 +968,7 @@ abstract class IrModuleDeserializer(
{ IrFieldImpl( { IrFieldImpl(
start, end, origin, start, end, origin,
it, it,
Name.identifier(proto.name), Name.identifier(deserializeString(proto.name)),
type, type,
deserializeVisibility(proto.visibility), deserializeVisibility(proto.visibility),
proto.isFinal, proto.isFinal,
@@ -990,18 +998,25 @@ abstract class IrModuleDeserializer(
origin: IrDeclarationOrigin origin: IrDeclarationOrigin
): IrProperty { ): IrProperty {
val backingField = if (proto.hasBackingField()) { val backingField = if (proto.hasBackingField()) deserializeIrField(proto.backingField, start, end, origin) else null
deserializeIrField(proto.backingField, start, end, origin) val getter = if (proto.hasGetter()) deserializeIrFunction(proto.getter, start, end, origin, true) else null
} 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 = val descriptor =
if (proto.hasDescriptor()) deserializeDescriptorReference(proto.descriptor) as PropertyDescriptor else null if (proto.hasDescriptor())
?: WrappedPropertyDescriptor() 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( val property = IrPropertyImpl(
start, end, origin, start, end, origin,
descriptor, descriptor,
Name.identifier(proto.name), Name.identifier(deserializeString(proto.name)),
deserializeVisibility(proto.visibility), deserializeVisibility(proto.visibility),
deserializeModality(proto.modality), deserializeModality(proto.modality),
proto.isVar, proto.isVar,
@@ -1023,29 +1038,34 @@ abstract class IrModuleDeserializer(
} }
*/ */
property.backingField = backingField property.backingField = backingField
property.getter = getter
property.setter = setter
backingField?.let { it.correspondingProperty = property } backingField?.let { it.correspondingProperty = property }
getter?.let { it.correspondingProperty = property }
setter?.let { it.correspondingProperty = property }
property.getter = // property.getter =
if (proto.hasGetter()) deserializeIrFunction(proto.getter, start, end, origin, property) else null // if (proto.hasGetter()) deserializeIrFunction(proto.getter, start, end, origin, property) else null
property.setter = // property.setter =
if (proto.hasSetter()) deserializeIrFunction(proto.setter, start, end, origin, property) else null // if (proto.hasSetter()) deserializeIrFunction(proto.setter, start, end, origin, property) else null
//
// property.getter?.let { (it.descriptor as? WrappedSimpleFunctionDescriptor)?.bind(it) } //// property.getter?.let { (it.descriptor as? WrappedSimpleFunctionDescriptor)?.bind(it) }
// property.setter?.let { (it.descriptor as? WrappedSimpleFunctionDescriptor)?.bind(it) } //// property.setter?.let { (it.descriptor as? WrappedSimpleFunctionDescriptor)?.bind(it) }
//
property.getter?.let { // property.getter?.let {
val descriptor = it.descriptor // val descriptor = it.descriptor
if (descriptor is WrappedSimpleFunctionDescriptor) descriptor.bind(it) // if (descriptor is WrappedSimpleFunctionDescriptor) descriptor.bind(it)
symbolTable.declareSimpleFunction(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, // symbolTable.declareSimpleFunction(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
descriptor, { symbol -> it }) // descriptor, { symbol -> it })
//
} // }
property.setter?.let { // property.setter?.let {
val descriptor = it.descriptor // val descriptor = it.descriptor
if (descriptor is WrappedSimpleFunctionDescriptor) descriptor.bind(it) // if (descriptor is WrappedSimpleFunctionDescriptor) descriptor.bind(it)
symbolTable.declareSimpleFunction(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin, // symbolTable.declareSimpleFunction(UNDEFINED_OFFSET, UNDEFINED_OFFSET, irrelevantOrigin,
descriptor, { symbol -> it }) // descriptor, { symbol -> it })
} // }
return property return property
} }
@@ -1063,12 +1083,13 @@ abstract class IrModuleDeserializer(
IrDeclarationOrigin::class.nestedClasses.toList() + DeclarationFactory.FIELD_FOR_OUTER_THIS::class IrDeclarationOrigin::class.nestedClasses.toList() + DeclarationFactory.FIELD_FOR_OUTER_THIS::class
val originIndex = allKnownOrigins.map { it.objectInstance as IrDeclarationOriginImpl }.associateBy { it.name } val originIndex = allKnownOrigins.map { it.objectInstance as IrDeclarationOriginImpl }.associateBy { it.name }
val irrelevantOrigin = object : IrDeclarationOriginImpl("irrelevant") {} val irrelevantOrigin = object : IrDeclarationOriginImpl("irrelevant") {}
fun deserializeIrDeclarationOrigin(proto: IrKlibProtoBuf.IrDeclarationOrigin) = originIndex[deserializeString(proto.custom)]!!
protected fun deserializeDeclaration(proto: IrKlibProtoBuf.IrDeclaration, parent: IrDeclarationParent?): IrDeclaration { protected fun deserializeDeclaration(proto: IrKlibProtoBuf.IrDeclaration, parent: IrDeclarationParent?): IrDeclaration {
val start = proto.coordinates.startOffset val start = proto.coordinates.startOffset
val end = proto.coordinates.endOffset val end = proto.coordinates.endOffset
val origin = originIndex[proto.origin.name]!! val origin = deserializeIrDeclarationOrigin(proto.origin)
val declarator = proto.declarator val declarator = proto.declarator
@@ -1082,7 +1103,7 @@ abstract class IrModuleDeserializer(
IR_CLASS IR_CLASS
-> deserializeIrClass(declarator.irClass, start, end, origin) -> deserializeIrClass(declarator.irClass, start, end, origin)
IR_FUNCTION IR_FUNCTION
-> deserializeIrFunction(declarator.irFunction, start, end, origin) -> deserializeIrFunction(declarator.irFunction, start, end, origin, false)
IR_PROPERTY IR_PROPERTY
-> deserializeIrProperty(declarator.irProperty, start, end, origin) -> deserializeIrProperty(declarator.irProperty, start, end, origin)
IR_TYPE_ALIAS IR_TYPE_ALIAS
@@ -1104,8 +1125,6 @@ abstract class IrModuleDeserializer(
parent?.let { declaration.parent = it } parent?.let { declaration.parent = it }
val sourceFileName = proto.fileName
val descriptor = declaration.descriptor val descriptor = declaration.descriptor
if (descriptor is WrappedDeclarationDescriptor<*>) { if (descriptor is WrappedDeclarationDescriptor<*>) {
@@ -389,9 +389,20 @@ internal class IrModuleSerializer(
private fun serializeCall(call: IrCall): IrKlibProtoBuf.IrCall { private fun serializeCall(call: IrCall): IrKlibProtoBuf.IrCall {
val proto = IrKlibProtoBuf.IrCall.newBuilder() 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.kind = irCallToPrimitiveKind(call)
proto.symbol = serializeIrSymbol(call.symbol) proto.symbol = serializeIrSymbol(call.symbol)
call.superQualifierSymbol?.let { call.superQualifierSymbol?.let {
proto.`super` = serializeIrSymbol(it) proto.`super` = serializeIrSymbol(it)
} }
@@ -657,68 +668,6 @@ internal class IrModuleSerializer(
return proto.build() 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 { private fun serializeBreak(expression: IrBreak): IrKlibProtoBuf.IrBreak {
val proto = IrKlibProtoBuf.IrBreak.newBuilder() val proto = IrKlibProtoBuf.IrBreak.newBuilder()
val label = expression.label?.let { serializeString(it) } val label = expression.label?.let { serializeString(it) }
@@ -794,8 +743,6 @@ internal class IrModuleSerializer(
is IrVararg -> operationProto.vararg = serializeVararg(expression) is IrVararg -> operationProto.vararg = serializeVararg(expression)
is IrWhen -> operationProto.`when` = serializeWhen(expression) is IrWhen -> operationProto.`when` = serializeWhen(expression)
is IrWhileLoop -> operationProto.`while` = serializeWhile(expression) is IrWhileLoop -> operationProto.`while` = serializeWhile(expression)
is IrDynamicMemberExpression -> operationProto.dynamicMember = serializeDynamicMemberExpression(expression)
is IrDynamicOperatorExpression -> operationProto.dynamicOperator = serializeDynamicOperatorExpression(expression)
else -> { else -> {
TODO("Expression serialization not implemented yet: ${ir2string(expression)}.") TODO("Expression serialization not implemented yet: ${ir2string(expression)}.")
} }
@@ -1127,7 +1074,7 @@ internal class IrModuleSerializer(
fun serializeModule(module: IrModuleFragment): IrKlibProtoBuf.IrModule { fun serializeModule(module: IrModuleFragment): IrKlibProtoBuf.IrModule {
val proto = IrKlibProtoBuf.IrModule.newBuilder() val proto = IrKlibProtoBuf.IrModule.newBuilder()
.setName(serializeString(module.name.toString())) .setName(serializeString(module.name.toString()))
module.addSyntheticDynamicFile()
module.files.forEach { module.files.forEach {
proto.addFile(serializeIrFile(it)) proto.addFile(serializeIrFile(it))
} }
@@ -1146,6 +1093,31 @@ internal class IrModuleSerializer(
return proto.build() 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 { fun serializedIrModule(module: IrModuleFragment): SerializedIr {
val moduleHeader = serializeModule(module).toByteArray() val moduleHeader = serializeModule(module).toByteArray()
return SerializedIr(moduleHeader, topLevelDeclarations, declarationTable.debugIndex) return SerializedIr(moduleHeader, topLevelDeclarations, declarationTable.debugIndex)
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.resolve.descriptorUtil.classId 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. // 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. // 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) } uniqId?.let { declarationTable.descriptors.put(discoverableDescriptorsDeclaration.descriptor, it) }
val proto = IrKlibProtoBuf.DescriptorReference.newBuilder() val proto = IrKlibProtoBuf.DescriptorReference.newBuilder()
.setPackageFqName(packageFqName) .setPackageFqName(serializeString(packageFqName))
.setClassFqName(classFqName) .setClassFqName(serializeString(classFqName))
.setName(descriptor.name.toString()) .setName(serializeString(descriptor.name.toString()))
if (uniqId != null) proto.setUniqId(protoUniqId(uniqId)) if (uniqId != null) proto.setUniqId(protoUniqId(uniqId))
@@ -5,9 +5,9 @@ option java_outer_classname = "IrKlibProtoBuf";
option optimize_for = LITE_RUNTIME; option optimize_for = LITE_RUNTIME;
message DescriptorReference { message DescriptorReference {
required string package_fq_name = 1; required String package_fq_name = 1;
required string class_fq_name = 2; required String class_fq_name = 2;
required string name = 3; required String name = 3;
optional UniqId uniq_id = 4; optional UniqId uniq_id = 4;
optional bool is_getter = 5 [default = false]; optional bool is_getter = 5 [default = false];
optional bool is_setter = 6 [default = false]; optional bool is_setter = 6 [default = false];
@@ -28,28 +28,85 @@ message Coordinates {
required int32 end_offset = 2; 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---------------------------------------------- */ /* ------ Top Level---------------------------------------------- */
message IrDeclarationContainer { message IrDeclarationContainer {
repeated IrDeclaration declaration = 1; repeated IrDeclaration declaration = 1;
} }
message FileEntry { // TODO: extend me. message FileEntry {
required string name = 1; required String name = 1;
repeated int32 line_start_offsets = 2;
} }
message IrFile { message IrFile {
repeated UniqId declaration_id = 1; repeated UniqId declaration_id = 1;
required FileEntry file_entry = 2; 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 { message IrModule {
required string name = 1; required String name = 1;
repeated IrFile file = 2; repeated IrFile file = 2;
required IrSymbolTable symbol_table = 3; required IrSymbolTable symbol_table = 3;
required IrTypeTable type_table = 4; 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 --------------------------------------------- */ /* ------ IrSymbols --------------------------------------------- */
@@ -74,7 +131,7 @@ message IrSymbolData {
required IrSymbolKind kind = 1; required IrSymbolKind kind = 1;
required UniqId uniq_id = 2; required UniqId uniq_id = 2;
required UniqId top_level_uniq_id = 3; required UniqId top_level_uniq_id = 3;
optional string fqname = 4; optional String fqname = 4;
optional DescriptorReference descriptor_reference = 5; optional DescriptorReference descriptor_reference = 5;
} }
@@ -153,7 +210,7 @@ message IrTypeIndex {
message IrBreak { message IrBreak {
required int32 loop_id = 1; required int32 loop_id = 1;
optional string label = 2; optional String label = 2;
} }
message IrBlock { message IrBlock {
@@ -183,7 +240,7 @@ message IrCall {
message IrFunctionReference { message IrFunctionReference {
required IrSymbol symbol = 1; required IrSymbol symbol = 1;
optional string origin = 2; optional IrStatementOrigin origin = 2;
required MemberAccessCommon member_access = 3; required MemberAccessCommon member_access = 3;
} }
@@ -192,8 +249,9 @@ message IrPropertyReference {
optional IrSymbol field = 1; optional IrSymbol field = 1;
optional IrSymbol getter = 2; optional IrSymbol getter = 2;
optional IrSymbol setter = 3; optional IrSymbol setter = 3;
optional string origin = 4; optional IrStatementOrigin origin = 4;
required MemberAccessCommon member_access = 5; required MemberAccessCommon member_access = 5;
optional DescriptorReference descriptor = 6; // IrProperty doesn't have a symbol at all. Preserve this rudiment for now.
} }
message IrComposite { message IrComposite {
@@ -216,13 +274,13 @@ message IrConst {
int64 long = 7; int64 long = 7;
float float = 8; float float = 8;
double double = 9; double double = 9;
string string = 10; String string = 10;
} }
} }
message IrContinue { message IrContinue {
required int32 loop_id = 1; required int32 loop_id = 1;
optional string label = 2; optional String label = 2;
} }
message IrDelegatingConstructorCall { message IrDelegatingConstructorCall {
@@ -272,7 +330,7 @@ message IrInstanceInitializerCall {
message Loop { message Loop {
required int32 loop_id = 1; required int32 loop_id = 1;
required IrExpression condition = 2; required IrExpression condition = 2;
optional string label = 3; optional String label = 3;
optional IrExpression body = 4; optional IrExpression body = 4;
} }
@@ -411,8 +469,8 @@ message IrFunction {
} }
message IrFunctionBase { message IrFunctionBase {
required string name = 1; required String name = 1;
required string visibility = 2; required Visibility visibility = 2;
required bool is_inline = 3; required bool is_inline = 3;
required bool is_external = 4; required bool is_external = 4;
required IrTypeParameterContainer type_parameters = 5; required IrTypeParameterContainer type_parameters = 5;
@@ -433,8 +491,8 @@ message IrConstructor {
message IrField { message IrField {
required IrSymbol symbol = 1; required IrSymbol symbol = 1;
optional IrExpression initializer = 2; optional IrExpression initializer = 2;
required string name = 3; required String name = 3;
required string visibility = 4; required Visibility visibility = 4;
required bool is_final = 5; required bool is_final = 5;
required bool is_external = 6; required bool is_external = 6;
required bool is_static = 7; required bool is_static = 7;
@@ -443,8 +501,8 @@ message IrField {
message IrProperty { message IrProperty {
optional DescriptorReference descriptor = 1; // IrProperty doesn't have a symbol at all. Preserve this rudiment for now. optional DescriptorReference descriptor = 1; // IrProperty doesn't have a symbol at all. Preserve this rudiment for now.
required string name = 2; required String name = 2;
required string visibility = 3; required Visibility visibility = 3;
required ModalityKind modality = 4; required ModalityKind modality = 4;
required bool is_var = 5; required bool is_var = 5;
required bool is_const = 6; required bool is_const = 6;
@@ -457,7 +515,7 @@ message IrProperty {
} }
message IrVariable { message IrVariable {
required string name = 1; required String name = 1;
required IrSymbol symbol = 2; required IrSymbol symbol = 2;
required IrTypeIndex type = 3; required IrTypeIndex type = 3;
required bool is_var = 4; required bool is_var = 4;
@@ -484,7 +542,7 @@ enum ModalityKind { // It is ModalityKind to not clash with Modality in descript
message IrValueParameter { message IrValueParameter {
required IrSymbol symbol = 1; required IrSymbol symbol = 1;
required string name = 2; required String name = 2;
required int32 index = 3; required int32 index = 3;
required IrTypeIndex type = 4; required IrTypeIndex type = 4;
optional IrTypeIndex vararg_element_type = 5; optional IrTypeIndex vararg_element_type = 5;
@@ -495,7 +553,7 @@ message IrValueParameter {
message IrTypeParameter { message IrTypeParameter {
required IrSymbol symbol = 1; required IrSymbol symbol = 1;
required string name = 2; required String name = 2;
required int32 index = 3; required int32 index = 3;
required IrTypeVariance variance = 4; required IrTypeVariance variance = 4;
repeated IrTypeIndex super_type = 5; repeated IrTypeIndex super_type = 5;
@@ -508,9 +566,9 @@ message IrTypeParameterContainer {
message IrClass { message IrClass {
required IrSymbol symbol = 1; required IrSymbol symbol = 1;
required string name = 2; required String name = 2;
required ClassKind kind = 3; required ClassKind kind = 3;
required string visibility = 4; required Visibility visibility = 4;
required ModalityKind modality = 5; required ModalityKind modality = 5;
// TODO: consider using flags for the booleans. // TODO: consider using flags for the booleans.
required bool is_companion = 6; required bool is_companion = 6;
@@ -528,7 +586,7 @@ message IrEnumEntry {
required IrSymbol symbol = 1; required IrSymbol symbol = 1;
optional IrExpression initializer = 2; optional IrExpression initializer = 2;
optional IrDeclaration corresponding_class = 3; optional IrDeclaration corresponding_class = 3;
required string name = 4; required String name = 4;
} }
message IrAnonymousInit { message IrAnonymousInit {
@@ -554,17 +612,11 @@ message IrDeclarator {
} }
} }
message IrDeclarationOrigin {
required string name = 1;
}
message IrDeclaration { message IrDeclaration {
required IrDeclarationOrigin origin = 1; required IrDeclarationOrigin origin = 1;
required Coordinates coordinates = 2; required Coordinates coordinates = 2;
required Annotations annotations = 3; required Annotations annotations = 3;
required IrDeclarator declarator = 4; required IrDeclarator declarator = 4;
//repeated IrDeclaration nested = 5;
required string file_name = 5; // TODO: files should be communicated some other way, I suppose.
} }
/* ------- IrStatements --------------------------------------------- */ /* ------- IrStatements --------------------------------------------- */
@@ -58,6 +58,7 @@ abstract class IrLazyDeclarationBase(
val containingDeclaration = val containingDeclaration =
((currentDescriptor as? PropertyAccessorDescriptor)?.correspondingProperty ?: currentDescriptor).containingDeclaration ((currentDescriptor as? PropertyAccessorDescriptor)?.correspondingProperty ?: currentDescriptor).containingDeclaration
return when (containingDeclaration) { return when (containingDeclaration) {
is PackageFragmentDescriptor -> stubGenerator.generateOrGetEmptyExternalPackageFragmentStub(containingDeclaration).also { is PackageFragmentDescriptor -> stubGenerator.generateOrGetEmptyExternalPackageFragmentStub(containingDeclaration).also {
it.declarations.add(this) 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.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.toIrType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
@@ -98,8 +96,8 @@ class IrBuiltIns(
builtIns.nothing to IrTypeMapper({ nothingType }, { nothingNType }), builtIns.nothing to IrTypeMapper({ nothingType }, { nothingNType }),
builtIns.unit to IrTypeMapper({ unitType }, { buildNullableType(unitType) }), builtIns.unit to IrTypeMapper({ unitType }, { buildNullableType(unitType) }),
builtIns.string to IrTypeMapper({ stringType }, { buildNullableType(stringType) }), builtIns.string to IrTypeMapper({ stringType }, { buildNullableType(stringType) }),
builtIns.throwable to IrTypeMapper({ throwableType }, { buildNullableType(throwableType) }) builtIns.throwable to IrTypeMapper({ throwableType }, { buildNullableType(throwableType) }),
// builtIns.array to { arrayClass.owner.defaultType } builtIns.array to IrTypeMapper({ arrayType }, { buildNullableType(arrayType) })
) )
fun getPrimitiveTypeOrNullByDescriptor(descriptor: ClassifierDescriptor, isNullable: Boolean) = fun getPrimitiveTypeOrNullByDescriptor(descriptor: ClassifierDescriptor, isNullable: Boolean) =
@@ -165,6 +163,7 @@ class IrBuiltIns(
val collectionClass by lazy { builtIns.collection.toIrSymbol() } val collectionClass by lazy { builtIns.collection.toIrSymbol() }
val arrayType by lazy { builtIns.array.toIrType(symbolTable = symbolTable) }
val arrayClass by lazy { builtIns.array.toIrSymbol() } val arrayClass by lazy { builtIns.array.toIrSymbol() }
val throwableType by lazy { builtIns.throwable.defaultType.toIrType() } val throwableType by lazy { builtIns.throwable.defaultType.toIrType() }
@@ -70,6 +70,7 @@ fun IrType.makeNullable(addKotlinType:Boolean = true) =
else else
this this
// TODO: get rid of this
var irTypeKotlinBuiltIns: KotlinBuiltIns? = null var irTypeKotlinBuiltIns: KotlinBuiltIns? = null
fun IrType.toKotlinType(): KotlinType { fun IrType.toKotlinType(): KotlinType {