[JS IR BE] New Inliner from native

This commit is contained in:
Roman Artemev
2018-11-16 20:43:26 +03:00
committed by romanart
parent 7b08f6f8f1
commit ce70e5850f
8 changed files with 930 additions and 468 deletions
@@ -37,7 +37,6 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.NameUtils import org.jetbrains.kotlin.name.NameUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.parents
import java.util.* import java.util.*
interface LocalNameProvider { interface LocalNameProvider {
@@ -73,13 +72,9 @@ class LocalDeclarationsLowering(
override fun lower(irDeclarationContainer: IrDeclarationContainer) { override fun lower(irDeclarationContainer: IrDeclarationContainer) {
if (irDeclarationContainer is IrDeclaration) { if (irDeclarationContainer is IrDeclaration) {
val parents = irDeclarationContainer.parents
// TODO: in case of `crossinline` lambda the @containingDeclaration and @parent points to completely different locations if (parents.any { it is IrFunction || it is IrField }) {
// val parentsDecl = irDeclarationContainer.parents
val parentsDesc = irDeclarationContainer.descriptor.parents
if (parentsDesc.any { it is CallableDescriptor }) {
// Lowering of non-local declarations handles all local declarations inside. // Lowering of non-local declarations handles all local declarations inside.
// This declaration is local and shouldn't be considered. // This declaration is local and shouldn't be considered.
return return
@@ -180,9 +175,9 @@ class LocalDeclarationsLowering(
val oldParameterToNew: MutableMap<IrValueParameter, IrValueParameter> = mutableMapOf() val oldParameterToNew: MutableMap<IrValueParameter, IrValueParameter> = mutableMapOf()
val newParameterToCaptured: MutableMap<IrValueParameter, IrValueSymbol> = mutableMapOf() val newParameterToCaptured: MutableMap<IrValueParameter, IrValueSymbol> = mutableMapOf()
fun lowerLocalDeclarations(): List<IrDeclaration>? { fun lowerLocalDeclarations(): List<IrDeclaration> {
collectLocalDeclarations() collectLocalDeclarations()
if (localFunctions.isEmpty() && localClasses.isEmpty()) return null if (localFunctions.isEmpty() && localClasses.isEmpty()) return listOf(memberDeclaration)
collectClosures() collectClosures()
@@ -208,9 +208,10 @@ fun IrConstructor.callsSuper(irBuiltIns: IrBuiltIns): Boolean {
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) { override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
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
if (delegatingClass == superClass.classifierOrFail.owner) // TODO: figure out why Lazy IR multiplies Declarations for descriptors and fix it
if (delegatingClass.descriptor == superClass.classifierOrFail.descriptor)
callsSuper = true callsSuper = true
else if (delegatingClass != constructedClass) else if (delegatingClass.descriptor != constructedClass.descriptor)
throw AssertionError( throw AssertionError(
"Expected either call to another constructor of the class being constructed or" + "Expected either call to another constructor of the class being constructed or" +
" call to super class constructor. But was: $delegatingClass" " call to super class constructor. But was: $delegatingClass"
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
@@ -29,16 +30,23 @@ fun compile(
irDependencyModules: List<IrModuleFragment> = listOf() irDependencyModules: List<IrModuleFragment> = listOf()
): Result { ): Result {
val analysisResult = val analysisResult =
TopDownAnalyzerFacadeForJS.analyzeFiles(files, project, configuration, dependencies.mapNotNull { it as? ModuleDescriptorImpl }, emptyList()) TopDownAnalyzerFacadeForJS.analyzeFiles(
files,
project,
configuration,
dependencies.mapNotNull { it as? ModuleDescriptorImpl },
emptyList()
)
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext) TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext)
val psi2IrTranslator = Psi2IrTranslator(configuration.languageVersionSettings) val symbolTable = SymbolTable()
val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext) irDependencyModules.forEach { symbolTable.loadModule(it)}
irDependencyModules.forEach { psi2IrContext.symbolTable.loadModule(it)} val psi2IrTranslator = Psi2IrTranslator(configuration.languageVersionSettings)
val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext, symbolTable)
val moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files) val moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files)
@@ -68,7 +68,7 @@ class ClassReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass
override fun visitClassReference(expression: IrClassReference) = override fun visitClassReference(expression: IrClassReference) =
callGetKClass( callGetKClass(
returnType = expression.type, returnType = expression.type,
typeArgument = expression.classType typeArgument = expression.classType.makeNotNull()
) )
}) })
} }
@@ -5,57 +5,255 @@
package org.jetbrains.kotlin.ir.backend.js.lower.inline package org.jetbrains.kotlin.ir.backend.js.lower.inline
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext
import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.createClassSymbolOrNull import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.createValueSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.DeepCopyIrTree import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.util.withScope import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.Variance
internal fun KotlinType?.createExtensionReceiver(owner: CallableDescriptor): ReceiverParameterDescriptor? =
DescriptorFactory.createExtensionReceiverParameterForCallable(
owner,
this,
Annotations.EMPTY
)
fun ReferenceSymbolTable.translateErased(type: KotlinType): IrSimpleType {
val descriptor = TypeUtils.getClassDescriptor(type) ?: return translateErased(type.immediateSupertypes().first())
val classSymbol = this.referenceClass(descriptor)
val nullable = type.isMarkedNullable
val arguments = type.arguments.map { IrStarProjectionImpl }
return classSymbol.createType(nullable, arguments)
}
internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
val typeArguments: Map<IrTypeParameterSymbol, IrType?>?,
val parent: IrDeclarationParent?) : IrCopierForInliner {
override fun copy(irElement: IrElement): IrElement {
// Create new symbols.
irElement.acceptVoid(symbolRemapper)
// Make symbol remapper aware of the callsite's type arguments.
symbolRemapper.typeArguments = typeArguments
// Copy IR.
val result = irElement.transform(copier, data = null)
// Bind newly created IR with wrapped descriptors.
result.acceptVoid(object: IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitClass(declaration: IrClass) {
(declaration.descriptor as WrappedClassDescriptor).bind(declaration)
declaration.acceptChildrenVoid(this)
}
override fun visitConstructor(declaration: IrConstructor) {
(declaration.descriptor as WrappedClassConstructorDescriptor).bind(declaration)
declaration.acceptChildrenVoid(this)
}
override fun visitEnumEntry(declaration: IrEnumEntry) {
(declaration.descriptor as WrappedClassDescriptor).bind(
declaration.correspondingClass ?: declaration.parentAsClass)
declaration.acceptChildrenVoid(this)
}
override fun visitField(declaration: IrField) {
(declaration.descriptor as WrappedPropertyDescriptor).bind(declaration)
declaration.acceptChildrenVoid(this)
}
override fun visitFunction(declaration: IrFunction) {
(declaration.descriptor as WrappedSimpleFunctionDescriptor).bind(declaration as IrSimpleFunction)
declaration.acceptChildrenVoid(this)
}
override fun visitValueParameter(declaration: IrValueParameter) {
(declaration.descriptor as? WrappedValueParameterDescriptor)?.bind(declaration)
(declaration.descriptor as? WrappedReceiverParameterDescriptor)?.bind(declaration)
declaration.acceptChildrenVoid(this)
}
override fun visitTypeParameter(declaration: IrTypeParameter) {
(declaration.descriptor as WrappedTypeParameterDescriptor).bind(declaration)
declaration.acceptChildrenVoid(this)
}
override fun visitVariable(declaration: IrVariable) {
(declaration.descriptor as WrappedVariableDescriptor).bind(declaration)
declaration.acceptChildrenVoid(this)
}
})
result.patchDeclarationParents(parent)
return result
}
private var nameIndex = 0
private fun generateCopyName(name: Name) = Name.identifier(name.toString() + "_" + (nameIndex++).toString())
private inner class InlinerSymbolRenamer : SymbolRenamer {
private val map = mutableMapOf<IrSymbol, Name>()
override fun getClassName(symbol: IrClassSymbol) = map.getOrPut(symbol) { generateCopyName(symbol.owner.name) }
override fun getFunctionName(symbol: IrSimpleFunctionSymbol) = map.getOrPut(symbol) { generateCopyName(symbol.owner.name) }
override fun getFieldName(symbol: IrFieldSymbol) = symbol.owner.name
override fun getFileName(symbol: IrFileSymbol) = symbol.owner.fqName
override fun getExternalPackageFragmentName(symbol: IrExternalPackageFragmentSymbol) = symbol.owner.fqName
override fun getEnumEntryName(symbol: IrEnumEntrySymbol) = symbol.owner.name
override fun getVariableName(symbol: IrVariableSymbol) = map.getOrPut(symbol) { generateCopyName(symbol.owner.name) }
override fun getTypeParameterName(symbol: IrTypeParameterSymbol) = symbol.owner.name
override fun getValueParameterName(symbol: IrValueParameterSymbol) = symbol.owner.name
}
private inner class DescriptorsToIrRemapper : DescriptorsRemapper {
override fun remapDeclaredClass(descriptor: ClassDescriptor) =
WrappedClassDescriptor(descriptor.annotations, descriptor.source)
override fun remapDeclaredConstructor(descriptor: ClassConstructorDescriptor) =
WrappedClassConstructorDescriptor(descriptor.annotations, descriptor.source)
override fun remapDeclaredEnumEntry(descriptor: ClassDescriptor) =
WrappedClassDescriptor(descriptor.annotations, descriptor.source)
override fun remapDeclaredField(descriptor: PropertyDescriptor) =
WrappedPropertyDescriptor(descriptor.annotations, descriptor.source)
override fun remapDeclaredSimpleFunction(descriptor: FunctionDescriptor) =
WrappedSimpleFunctionDescriptor(descriptor.annotations, descriptor.source)
override fun remapDeclaredTypeParameter(descriptor: TypeParameterDescriptor) =
WrappedTypeParameterDescriptor(descriptor.annotations, descriptor.source)
override fun remapDeclaredVariable(descriptor: VariableDescriptor) =
WrappedVariableDescriptor(descriptor.annotations, descriptor.source)
override fun remapDeclaredValueParameter(descriptor: ParameterDescriptor): ParameterDescriptor =
if (descriptor is ReceiverParameterDescriptor)
WrappedReceiverParameterDescriptor(descriptor.annotations, descriptor.source)
else
WrappedValueParameterDescriptor(descriptor.annotations, descriptor.source)
}
private inner class InlinerTypeRemapper(val symbolRemapper: SymbolRemapper,
val typeArguments: Map<IrTypeParameterSymbol, IrType?>?) : TypeRemapper {
override fun enterScope(irTypeParametersContainer: IrTypeParametersContainer) { }
override fun leaveScope() { }
private fun remapTypeArguments(arguments: List<IrTypeArgument>) =
arguments.map { argument ->
(argument as? IrTypeProjection)?.let { makeTypeProjection(remapType(it.type), it.variance) }
?: argument
}
override fun remapType(type: IrType): IrType {
if (type !is IrSimpleType) return type
val substitutedType = typeArguments?.get(type.classifier)
if (substitutedType != null) {
substitutedType as IrSimpleType
return IrSimpleTypeImpl(
kotlinType = null,
classifier = substitutedType.classifier,
hasQuestionMark = type.hasQuestionMark or substitutedType.isMarkedNullable(),
arguments = substitutedType.arguments,
annotations = substitutedType.annotations
)
}
return IrSimpleTypeImpl(
kotlinType = null,
classifier = symbolRemapper.getReferencedClassifier(type.classifier),
hasQuestionMark = type.hasQuestionMark,
arguments = remapTypeArguments(type.arguments),
annotations = type.annotations.map { it.transform(copier, null) as IrCall }
)
}
}
override fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) { }
private class SymbolRemapperImpl(descriptorsRemapper: DescriptorsRemapper)
: DeepCopySymbolRemapper(descriptorsRemapper) {
var typeArguments: Map<IrTypeParameterSymbol, IrType?>? = null
set(value) {
if (field != null) return
field = value?.asSequence()?.associate {
(getReferencedClassifier(it.key) as IrTypeParameterSymbol) to it.value
}
}
override fun getReferencedClassifier(symbol: IrClassifierSymbol): IrClassifierSymbol {
val result = super.getReferencedClassifier(symbol)
if (result !is IrTypeParameterSymbol)
return result
return typeArguments?.get(result)?.classifierOrNull ?: result
}
}
private val symbolRemapper = SymbolRemapperImpl(DescriptorsToIrRemapper())
private val copier = DeepCopyIrTreeWithSymbols(
symbolRemapper,
InlinerTypeRemapper(symbolRemapper, typeArguments),
InlinerSymbolRenamer()
)
}
internal interface IrCopierForInliner {
fun copy(irElement: IrElement): IrElement
fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>)
}
// backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt
internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor, internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
val parentDescriptor: DeclarationDescriptor, val parentDescriptor: DeclarationDescriptor,
val context: JsIrBackendContext) { val context: JsIrBackendContext,
val typeSubstitutor: TypeSubstitutor?) : IrCopierForInliner {
private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf() private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf()
private var typeSubstitutor: TypeSubstitutor? = null
private var nameIndex = 0 private var nameIndex = 0
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun copy(irElement: IrElement, typeSubstitutor: TypeSubstitutor?): IrElement { override fun copy(irElement: IrElement): IrElement {
this.typeSubstitutor = typeSubstitutor
// Create all class descriptors and all necessary descriptors in order to create KotlinTypes. // Create all class descriptors and all necessary descriptors in order to create KotlinTypes.
irElement.acceptChildrenVoid(DescriptorCollectorCreatePhase()) irElement.acceptVoid(DescriptorCollectorCreatePhase())
// Initialize all created descriptors possibly using previously created types. // Initialize all created descriptors possibly using previously created types.
irElement.acceptChildrenVoid(DescriptorCollectorInitPhase()) irElement.acceptVoid(DescriptorCollectorInitPhase())
return irElement.accept(InlineCopyIr(), null) return irElement.accept(InlineCopyIr(), null)
} }
@@ -129,7 +327,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
private fun generateCopyName(name: Name): Name { private fun generateCopyName(name: Name): Name {
val declarationName = name.toString() // Name of declaration val declarationName = name.toString() // Name of declaration
val indexStr = (nameIndex++).toString() // Unique for inline target index val indexStr = (nameIndex++).toString() // Unique for inline target index
return Name.identifier(declarationName /*+ "_" + indexStr*/) return Name.identifier(declarationName + "_" + indexStr)
} }
//---------------------------------------------------------------------// //---------------------------------------------------------------------//
@@ -216,9 +414,13 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
/* supertypes = */ listOf(newSuperClass.defaultType) + newInterfaces.map { it.defaultType }, /* supertypes = */ listOf(newSuperClass.defaultType) + newInterfaces.map { it.defaultType },
/* source = */ oldDescriptor.source, /* source = */ oldDescriptor.source,
/* isExternal = */ oldDescriptor.isExternal, /* isExternal = */ oldDescriptor.isExternal,
LockBasedStorageManager.NO_LOCKS /* storageManager = */ LockBasedStorageManager.NO_LOCKS
) { ) {
override fun getVisibility() = visibility override fun getVisibility() = visibility
override fun getDeclaredTypeParameters(): List<TypeParameterDescriptor> {
return oldDescriptor.declaredTypeParameters
}
} }
} }
} }
@@ -284,7 +486,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
private fun generateCopyName(name: Name): Name { private fun generateCopyName(name: Name): Name {
val declarationName = name.toString() // Name of declaration val declarationName = name.toString() // Name of declaration
val indexStr = (nameIndex++).toString() // Unique for inline target index val indexStr = (nameIndex++).toString() // Unique for inline target index
return Name.identifier(declarationName /*+ "_" + indexStr*/) return Name.identifier(declarationName + "_" + indexStr)
} }
//---------------------------------------------------------------------// //---------------------------------------------------------------------//
@@ -295,7 +497,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
return IrTemporaryVariableDescriptorImpl( return IrTemporaryVariableDescriptorImpl(
containingDeclaration = newContainingDeclaration, containingDeclaration = newContainingDeclaration,
name = generateCopyName(oldDescriptor.name), name = generateCopyName(oldDescriptor.name),
outType = substituteTypeAndTryGetCopied(oldDescriptor.type)!!, outType = substituteType(oldDescriptor.type)!!,
isMutable = oldDescriptor.isVar isMutable = oldDescriptor.isVar
) )
} }
@@ -317,11 +519,11 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
val newDispatchReceiverParameter = oldDispatchReceiverParameter?.let { descriptorSubstituteMap.getOrDefault(it, it) as ReceiverParameterDescriptor } val newDispatchReceiverParameter = oldDispatchReceiverParameter?.let { descriptorSubstituteMap.getOrDefault(it, it) as ReceiverParameterDescriptor }
val newTypeParameters = oldDescriptor.typeParameters // TODO substitute types val newTypeParameters = oldDescriptor.typeParameters // TODO substitute types
val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this) val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
val newReceiverParameter = copyReceiverParameter(oldDescriptor.extensionReceiverParameter, this) val newReceiverParameterType = substituteType(oldDescriptor.extensionReceiverParameter?.type)
val newReturnType = substituteTypeAndTryGetCopied(oldDescriptor.returnType) val newReturnType = substituteType(oldDescriptor.returnType)
initialize( initialize(
/* extensionReceiverParameter = */ newReceiverParameter, /* receiverParameterType = */ newReceiverParameterType.createExtensionReceiver(this),
/* dispatchReceiverParameter = */ newDispatchReceiverParameter, /* dispatchReceiverParameter = */ newDispatchReceiverParameter,
/* typeParameters = */ newTypeParameters, /* typeParameters = */ newTypeParameters,
/* unsubstitutedValueParameters = */ newValueParameters, /* unsubstitutedValueParameters = */ newValueParameters,
@@ -340,11 +542,11 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
(descriptorSubstituteMap[oldDescriptor] as ClassConstructorDescriptorImpl).apply { (descriptorSubstituteMap[oldDescriptor] as ClassConstructorDescriptorImpl).apply {
val newTypeParameters = oldDescriptor.typeParameters val newTypeParameters = oldDescriptor.typeParameters
val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this) val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
val newReceiverParameter = copyReceiverParameter(oldDescriptor.dispatchReceiverParameter, this) val receiverParameterType = substituteType(oldDescriptor.dispatchReceiverParameter?.type)
val returnType = substituteTypeAndTryGetCopied(oldDescriptor.returnType) val returnType = substituteType(oldDescriptor.returnType)
initialize( initialize(
/* extensionReceiverParameter = */ newReceiverParameter, /* receiverParameterType = */ receiverParameterType.createExtensionReceiver(this),
/* dispatchReceiverParameter = */ null, // For constructor there is no explicit dispatch receiver. /* dispatchReceiverParameter = */ null, // For constructor there is no explicit dispatch receiver.
/* typeParameters = */ newTypeParameters, /* typeParameters = */ newTypeParameters,
/* unsubstitutedValueParameters = */ newValueParameters, /* unsubstitutedValueParameters = */ newValueParameters,
@@ -359,17 +561,14 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
private fun initPropertyOrField(oldDescriptor: PropertyDescriptor) { private fun initPropertyOrField(oldDescriptor: PropertyDescriptor) {
val newDescriptor = (descriptorSubstituteMap[oldDescriptor] as PropertyDescriptorImpl).apply { val newDescriptor = (descriptorSubstituteMap[oldDescriptor] as PropertyDescriptorImpl).apply {
setType( setType(
/* outType = */ substituteTypeAndTryGetCopied(oldDescriptor.type)!!, /* outType = */ substituteType(oldDescriptor.type)!!,
/* typeParameters = */ oldDescriptor.typeParameters, /* typeParameters = */ oldDescriptor.typeParameters,
/* dispatchReceiverParameter = */ (containingDeclaration as ClassDescriptor).thisAsReceiverParameter, /* dispatchReceiverParameter = */ (containingDeclaration as ClassDescriptor).thisAsReceiverParameter,
/* extensionReceiverParameter= */ copyReceiverParameter(oldDescriptor.extensionReceiverParameter, this) /* extensionReceiverParamter = */ substituteType(oldDescriptor.extensionReceiverParameter?.type).createExtensionReceiver(this))
)
initialize( initialize(
/* getter = */ oldDescriptor.getter?.let { copyPropertyGetterDescriptor(it, this) }, /* getter = */ oldDescriptor.getter?.let { copyPropertyGetterDescriptor(it, this) },
/* setter = */ oldDescriptor.setter?.let { copyPropertySetterDescriptor(it, this) }, /* setter = */ oldDescriptor.setter?.let { copyPropertySetterDescriptor(it, this) })
oldDescriptor.backingField, oldDescriptor.delegateField
)
overriddenDescriptors += oldDescriptor.overriddenDescriptors overriddenDescriptors += oldDescriptor.overriddenDescriptors
} }
@@ -395,7 +594,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
/* kind = */ oldDescriptor.kind, /* kind = */ oldDescriptor.kind,
/* original = */ null, /* original = */ null,
/* source = */ oldDescriptor.source).apply { /* source = */ oldDescriptor.source).apply {
initialize(substituteTypeAndTryGetCopied(oldDescriptor.returnType)) initialize(substituteType(oldDescriptor.returnType))
} }
//---------------------------------------------------------------------// //---------------------------------------------------------------------//
@@ -425,34 +624,17 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
index = oldDescriptor.index, index = oldDescriptor.index,
annotations = oldDescriptor.annotations, annotations = oldDescriptor.annotations,
name = oldDescriptor.name, name = oldDescriptor.name,
outType = substituteTypeAndTryGetCopied(oldDescriptor.type)!!, outType = substituteType(oldDescriptor.type)!!,
declaresDefaultValue = oldDescriptor.declaresDefaultValue(), declaresDefaultValue = oldDescriptor.declaresDefaultValue(),
isCrossinline = oldDescriptor.isCrossinline, isCrossinline = oldDescriptor.isCrossinline,
isNoinline = oldDescriptor.isNoinline, isNoinline = oldDescriptor.isNoinline,
varargElementType = substituteTypeAndTryGetCopied(oldDescriptor.varargElementType), varargElementType = substituteType(oldDescriptor.varargElementType),
source = oldDescriptor.source source = oldDescriptor.source
) )
descriptorSubstituteMap[oldDescriptor] = newDescriptor descriptorSubstituteMap[oldDescriptor] = newDescriptor
newDescriptor newDescriptor
} }
private fun copyReceiverParameter(
oldReceiverParameter: ReceiverParameterDescriptor?, containingDeclaration: CallableDescriptor
): ReceiverParameterDescriptor? {
if (oldReceiverParameter == null) return null
val substituteTypeAndTryGetCopied = substituteTypeAndTryGetCopied(oldReceiverParameter.type) ?: return null
return ReceiverParameterDescriptorImpl(
containingDeclaration,
ExtensionReceiver(containingDeclaration, substituteTypeAndTryGetCopied, oldReceiverParameter.value),
oldReceiverParameter.annotations
)
}
private fun substituteTypeAndTryGetCopied(type: KotlinType?): KotlinType? {
val substitutedType = substituteType(type) ?: return null
val oldClassDescriptor = TypeUtils.getClassDescriptor(substitutedType) ?: return substitutedType
return descriptorSubstituteMap[oldClassDescriptor]?.let { (it as ClassDescriptor).defaultType } ?: substitutedType
}
} }
//-----------------------------------------------------------------------------// //-----------------------------------------------------------------------------//
@@ -496,7 +678,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
return IrCallImpl( return IrCallImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
type = newDescriptor.returnType?.toIrType(context.symbolTable)!!, type = context.symbolTable.translateErased(newDescriptor.returnType!!),
descriptor = newDescriptor, descriptor = newDescriptor,
typeArgumentsCount = expression.typeArgumentsCount, typeArgumentsCount = expression.typeArgumentsCount,
origin = expression.origin, origin = expression.origin,
@@ -507,6 +689,19 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
} }
} }
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) = override fun visitFunction(declaration: IrFunction) =
@@ -519,13 +714,106 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
returnType = declaration.returnType, returnType = declaration.returnType,
body = declaration.body?.transform(this@InlineCopyIr, null) body = declaration.body?.transform(this@InlineCopyIr, null)
).also { ).also {
it.returnType = context.symbolTable.translateErased(descriptor.returnType!!)
it.setOverrides(context.symbolTable) it.setOverrides(context.symbolTable)
it.transformParameters(declaration) 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 { private fun <T : IrFunction> T.transformDefaults(original: T): T {
for (originalValueParameter in original.descriptor.valueParameters) { for (originalValueParameter in original.descriptor.valueParameters) {
val valueParameter = descriptor.valueParameters[originalValueParameter.index] val valueParameter = descriptor.valueParameters[originalValueParameter.index]
@@ -554,8 +842,9 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
//---------------------------------------------------------------------// //---------------------------------------------------------------------//
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall { override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall {
val typeOperand = substituteType(expression.typeOperand)!! val erasedTypeOperand = substituteAndEraseType(expression.typeOperand)!!
val returnType = getTypeOperatorReturnType(expression.operator, typeOperand) val typeOperand = substituteAndBreakType(expression.typeOperand)
val returnType = getTypeOperatorReturnType(expression.operator, erasedTypeOperand)
return IrTypeOperatorCallImpl( return IrTypeOperatorCallImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
@@ -563,7 +852,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
operator = expression.operator, operator = expression.operator,
typeOperand = typeOperand, typeOperand = typeOperand,
argument = expression.argument.transform(this, null), argument = expression.argument.transform(this, null),
typeOperandClassifier = typeOperand.classifierOrFail typeOperandClassifier = (typeOperand as IrSimpleType).classifier
) )
} }
@@ -573,7 +862,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
IrReturnImpl( IrReturnImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
type = substituteType(expression.type)!!, type = substituteAndEraseType(expression.type)!!,
returnTargetDescriptor = mapReturnTarget(expression.returnTarget), returnTargetDescriptor = mapReturnTarget(expression.returnTarget),
value = expression.value.transform(this, null) value = expression.value.transform(this, null)
) )
@@ -592,14 +881,19 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
sourceFileName = expression.sourceFileName sourceFileName = expression.sourceFileName
) )
} else { } else {
super.visitBlock(expression) IrBlockImpl(
expression.startOffset, expression.endOffset,
substituteAndEraseType(expression.type)!!,
mapStatementOrigin(expression.origin),
expression.statements.map { it.transform(this, null) }
)
} }
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
override fun visitClassReference(expression: IrClassReference): IrClassReference { override fun visitClassReference(expression: IrClassReference): IrClassReference {
val newExpressionType = substituteType(expression.type)!! // Substituted expression type. val newExpressionType = substituteAndEraseType(expression.type)!! // Substituted expression type.
val newDescriptorType = substituteType(expression.descriptor.defaultType)!! // Substituted type of referenced class. val newDescriptorType = substituteType(expression.descriptor.defaultType)!! // Substituted type of referenced class.
val classDescriptor = newDescriptorType.constructor.declarationDescriptor!! // Get ClassifierDescriptor of the referenced class. val classDescriptor = newDescriptorType.constructor.declarationDescriptor!! // Get ClassifierDescriptor of the referenced class.
return IrClassReferenceImpl( return IrClassReferenceImpl(
@@ -614,7 +908,7 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
override fun visitGetClass(expression: IrGetClass): IrGetClass { override fun visitGetClass(expression: IrGetClass): IrGetClass {
val type = substituteType(expression.type)!! val type = substituteAndEraseType(expression.type)!!
return IrGetClassImpl( return IrGetClassImpl(
startOffset = expression.startOffset, startOffset = expression.startOffset,
endOffset = expression.endOffset, endOffset = expression.endOffset,
@@ -628,16 +922,77 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop { override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
return irLoop return irLoop
} }
override fun visitClass(declaration: IrClass): IrClass {
val descriptor = this.mapClassDeclaration(declaration.descriptor)
return context.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(oldType: IrType?): IrType? = substituteType(oldType?.toKotlinType())?.toIrType(context.symbolTable) 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 substituteType(oldType: KotlinType?): KotlinType? { private fun substituteAndEraseType(oldType: IrType?): IrType? {
if (typeSubstitutor == null) return oldType oldType ?: return null
if (oldType == null) return oldType
return typeSubstitutor!!.substitute(oldType, Variance.INVARIANT) ?: oldType 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())!!)
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
@@ -645,16 +1000,16 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
private fun IrMemberAccessExpression.substituteTypeArguments(original: IrMemberAccessExpression) { private fun IrMemberAccessExpression.substituteTypeArguments(original: IrMemberAccessExpression) {
for (index in 0 until original.typeArgumentsCount) { for (index in 0 until original.typeArgumentsCount) {
val originalTypeArgument = original.getTypeArgument(index) val originalTypeArgument = original.getTypeArgument(index)
val newTypeArgument = substituteType(originalTypeArgument)!! val newTypeArgument = substituteAndBreakType(originalTypeArgument!!)
this.putTypeArgument(index, newTypeArgument) this.putTypeArgument(index, newTypeArgument)
} }
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) { override fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) {
descriptorSubstituteMap.forEach { t, u -> descriptorSubstituteMap.forEach { t, u ->
globalSubstituteMap.put(t, SubstitutedDescriptor(targetDescriptor, u)) globalSubstituteMap[t] = SubstitutedDescriptor(targetDescriptor, u)
} }
} }
@@ -662,40 +1017,16 @@ internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescr
class SubstitutedDescriptor(val inlinedFunction: FunctionDescriptor, val descriptor: DeclarationDescriptor) class SubstitutedDescriptor(val inlinedFunction: FunctionDescriptor, val descriptor: DeclarationDescriptor)
class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) internal class DescriptorSubstitutorForExternalScope(
val globalSubstituteMap: Map<DeclarationDescriptor, SubstitutedDescriptor>,
val context: Context
)
: IrElementTransformerVoidWithContext() { : IrElementTransformerVoidWithContext() {
private val variableSubstituteMap = mutableMapOf<VariableDescriptor, VariableDescriptor>()
fun run(element: IrElement) { fun run(element: IrElement) {
collectVariables(element)
element.transformChildrenVoid(this) element.transformChildrenVoid(this)
} }
private fun collectVariables(element: IrElement) {
element.acceptChildrenVoid(object: IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitVariable(declaration: IrVariable) {
declaration.acceptChildrenVoid(this)
val oldDescriptor = declaration.descriptor
val oldClassDescriptor = oldDescriptor.type.constructor.declarationDescriptor as? ClassDescriptor
val substitutedDescriptor = oldClassDescriptor?.let { globalSubstituteMap[it] }
if (substitutedDescriptor == null || allScopes.any { it.scope.scopeOwner == substitutedDescriptor.inlinedFunction })
return
val newDescriptor = IrTemporaryVariableDescriptorImpl(
containingDeclaration = oldDescriptor.containingDeclaration,
name = oldDescriptor.name,
outType = (substitutedDescriptor.descriptor as ClassDescriptor).defaultType,
isMutable = oldDescriptor.isVar)
variableSubstituteMap[oldDescriptor] = newDescriptor
}
})
}
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
val oldExpression = super.visitCall(expression) as IrCall val oldExpression = super.visitCall(expression) as IrCall
@@ -710,41 +1041,6 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<
} }
} }
//---------------------------------------------------------------------//
override fun visitVariable(declaration: IrVariable): IrDeclaration {
declaration.transformChildrenVoid(this)
val oldDescriptor = declaration.descriptor
val newDescriptor = variableSubstituteMap[oldDescriptor] ?: return declaration
return IrVariableImpl(
startOffset = declaration.startOffset,
endOffset = declaration.endOffset,
origin = declaration.origin,
descriptor = newDescriptor,
initializer = declaration.initializer,
type = declaration.type
)
}
//-------------------------------------------------------------------------//
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this)
val oldDescriptor = expression.descriptor
val newDescriptor = variableSubstituteMap[oldDescriptor] ?: return expression
return IrGetValueImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
origin = expression.origin,
symbol = createValueSymbol(newDescriptor),
type = expression.type
)
}
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun copyIrCallImpl(oldExpression: IrCallImpl, substitutedDescriptor: SubstitutedDescriptor): IrCallImpl { private fun copyIrCallImpl(oldExpression: IrCallImpl, substitutedDescriptor: SubstitutedDescriptor): IrCallImpl {
@@ -758,7 +1054,7 @@ class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<
return IrCallImpl( return IrCallImpl(
startOffset = oldExpression.startOffset, startOffset = oldExpression.startOffset,
endOffset = oldExpression.endOffset, endOffset = oldExpression.endOffset,
type = oldExpression.type, type = context.symbolTable.translateErased(newDescriptor.returnType!!),
symbol = createFunctionSymbol(newDescriptor), symbol = createFunctionSymbol(newDescriptor),
descriptor = newDescriptor, descriptor = newDescriptor,
typeArgumentsCount = oldExpression.typeArgumentsCount, typeArgumentsCount = oldExpression.typeArgumentsCount,
@@ -7,30 +7,31 @@
package org.jetbrains.kotlin.ir.backend.js.lower.inline package org.jetbrains.kotlin.ir.backend.js.lower.inline
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.ScopeWithIr import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.reportWarning
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
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.Scope
import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.getDefault
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.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.impl.IrReturnableBlockSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
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.TypeConstructor
@@ -38,54 +39,147 @@ import org.jetbrains.kotlin.types.TypeProjection
import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor 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): IrElementTransformerVoidWithContext() { internal class FunctionInlining(val context: Context): IrElementTransformerWithContext<Ref<Boolean>>() {
// TODO private val deserializer = DeserializerDriver(context) // TODO private val deserializer = DeserializerDriver(context)
private val globalSubstituteMap = mutableMapOf<DeclarationDescriptor, SubstitutedDescriptor>() private val globalSubstituteMap = mutableMapOf<DeclarationDescriptor, SubstitutedDescriptor>()
private val inlineFunctions = mutableMapOf<FunctionDescriptor, Boolean>()
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
fun inline(irModule: IrModuleFragment): IrElement { fun inline(irModule: IrModuleFragment): IrElement {
val transformedModule = irModule.accept(this, null) val transformedModule = irModule.accept(this, Ref(false))
DescriptorSubstitutorForExternalScope(globalSubstituteMap).run(transformedModule) // Transform calls to object that might be returned from inline function call. DescriptorSubstitutorForExternalScope(globalSubstituteMap, context).run(transformedModule) // Transform calls to object that might be returned from inline function call.
return transformedModule return transformedModule
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
override fun visitCall(expression: IrCall): IrExpression { override fun visitFunctionNew(declaration: IrFunction, data: Ref<Boolean>): IrStatement {
val descriptor = declaration.descriptor
val irCall = super.visitCall(expression) as IrCall val localData = Ref(inlineFunctions[descriptor] ?: false)
val functionDescriptor = irCall.descriptor val result = super.visitFunctionNew(declaration, localData)
if (!functionDescriptor.needsInlining) return irCall // This call does not need inlining. data.value = data.value or localData.value
val functionDeclaration = getFunctionDeclaration(irCall) // Get declaration of the function to be inlined. if (descriptor.needsInlining)
if (functionDeclaration == null) { // We failed to get the declaration. inlineFunctions[descriptor] = localData.value
val message = "Inliner failed to obtain function declaration: " + return result
functionDescriptor.fqNameSafe.toString()
getFunctionDeclaration(irCall)
context.reportWarning(message, currentFile, irCall) // Report warning.
return irCall
} }
functionDeclaration.transformChildrenVoid(this) // Process recursive inline. override fun visitCall(expression: IrCall, data: Ref<Boolean>): IrExpression {
val inliner = Inliner(
globalSubstituteMap, val argsAreBad = Ref(false)
functionDeclaration, val callSite = super.visitCall(expression, argsAreBad) as IrCall
currentScope!!, data.value = data.value or argsAreBad.value
context val functionDescriptor = callSite.descriptor
) // Create inliner for this scope. if (!functionDescriptor.needsInlining) return callSite // This call does not need inlining.
return inliner.inline(irCall ) // Return newly created IrInlineBody instead of IrCall.
val callee = getFunctionDeclaration(callSite) // Get declaration of the function to be inlined.
if (callee == null) { // We failed to get the declaration.
val message = "Inliner failed to obtain function declaration: " +
functionDescriptor.fqNameSafe.toString()
callee
context.reportWarning(message, currentFile, callSite) // Report warning.
return callSite
}
data.value = data.value or callee.second
val childIsBad = Ref(inlineFunctions[functionDescriptor] ?: false)
callee.first.transformChildren(this, childIsBad)
inlineFunctions[functionDescriptor] = childIsBad.value// Process recursive inline.
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.
return inliner.inline() // Return newly created IrInlineBody instead of IrCall.
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun getFunctionDeclaration(irCall: IrCall): IrFunction? { private fun getFunctionDeclaration(irCall: IrCall): Pair<IrFunction, Boolean>? {
val functionDescriptor = irCall.descriptor val functionDescriptor = irCall.descriptor
val originalDescriptor = functionDescriptor.resolveFakeOverride().original val originalDescriptor = functionDescriptor.resolveFakeOverride().original
@@ -94,12 +188,8 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
context.originalModuleIndex.functions[originalDescriptor] ?: context.symbolTable.referenceDeclaredFunction(originalDescriptor).owner context.originalModuleIndex.functions[originalDescriptor] ?: context.symbolTable.referenceDeclaredFunction(originalDescriptor).owner
// ?: // If function is declared in the current module. // ?: // If function is declared in the current module.
// TODO deserializer.deserializeInlineBody(originalDescriptor) // Function is declared in another module. // TODO deserializer.deserializeInlineBody(originalDescriptor) // Function is declared in another module.
return functionDeclaration as IrFunction? return (functionDeclaration as IrFunction?)?.let { it to false }
} }
//-------------------------------------------------------------------------//
override fun visitElement(element: IrElement) = element.accept(this, null)
} }
// TODO: should we keep this at all? // TODO: should we keep this at all?
@@ -109,52 +199,63 @@ private val FunctionDescriptor.isInlineConstructor get() = annotations.hasAnnota
//-----------------------------------------------------------------------------// //-----------------------------------------------------------------------------//
private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>, private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>,
val functionDeclaration: IrFunction, // Function to substitute. val callSite: IrCall,
val callee: IrFunction,
val local: Boolean,
val currentScope: ScopeWithIr, val currentScope: ScopeWithIr,
val context: Context val parent: IrDeclarationParent?,
) { val context: Context,
val owner: FunctionInlining /*TODO: make inner*/) {
val copyIrElement = DeepCopyIrTreeWithDescriptors( val copyIrElement =
functionDeclaration.descriptor, if (!local)
currentScope.scope.scopeOwner, DeepCopyIrTreeWithDescriptors(callee.descriptor, currentScope.scope.scopeOwner,
context context, createTypeSubstitutor(callSite))
) // Create DeepCopy for current scope. else {
val substituteMap = mutableMapOf<ValueDescriptor, IrExpression>() val typeParameters =
if (callee is IrConstructor)
//-------------------------------------------------------------------------// callee.parentAsClass.typeParameters
else callee.typeParameters
fun inline(irCall: IrCall): IrReturnableBlockImpl { // Call to be substituted. val typeArguments =
val inlineFunctionBody = inlineFunction(irCall, functionDeclaration) (0 until callSite.typeArgumentsCount).map {
copyIrElement.addCurrentSubstituteMap(globalSubstituteMap) typeParameters[it].symbol to callSite.getTypeArgument(it)
return inlineFunctionBody }.associate { it }
DeepCopyIrTreeWithSymbolsForInliner(context, typeArguments, parent)
} }
//-------------------------------------------------------------------------// val substituteMap = mutableMapOf<ValueDescriptor, IrExpression>()
private fun inlineFunction(callee: IrCall, // Call to be substituted. fun inline() = inlineFunction(callSite, callee)
caller: IrFunction): IrReturnableBlockImpl { // Function to substitute.
val copyFunctionDeclaration = copyIrElement.copy( // Create copy of original function. /**
irElement = caller, // Descriptors declared inside the function will be copied. * TODO: JVM inliner crashed on attempt inline this function from transform.kt with:
typeSubstitutor = createTypeSubstitutor(callee) // Type parameters will be substituted with type arguments. * j.l.IllegalStateException: Couldn't obtain compiled function body for
) as IrFunction * public inline fun <reified T : org.jetbrains.kotlin.ir.IrElement> kotlin.collections.MutableList<T>.transform...
*/
private inline fun <reified T : IrElement> MutableList<T>.transform(transformation: (T) -> IrElement) {
forEachIndexed { i, item ->
set(i, transformation(item) as T)
}
}
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copyFunctionDeclaration.descriptor.original) private fun inlineFunction(callSite: IrCall, callee: IrFunction): IrReturnableBlockImpl {
val copiedCallee = copyIrElement.copy(callee) as IrFunction
val evaluationStatements = evaluateArguments(callee, copyFunctionDeclaration) // And list of evaluation statements. val evaluationStatements = evaluateArguments(callSite, copiedCallee)
val statements = (copiedCallee.body as IrBlockBody).statements
val statements = (copyFunctionDeclaration.body as IrBlockBody).statements // IR statements from function copy. val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copiedCallee.descriptor.original)
val descriptor = callee.descriptor.original
val startOffset = callee.startOffset
val endOffset = callee.endOffset
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
val startOffset = caller.startOffset
val endOffset = caller.endOffset
val descriptor = caller.descriptor.original
if (descriptor.isInlineConstructor) { if (descriptor.isInlineConstructor) {
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
irBuilder.run { irBuilder.run {
val constructorDescriptor = delegatingConstructorCall.descriptor.original val constructorDescriptor = delegatingConstructorCall.descriptor.original
val constructorCall = irCall(delegatingConstructorCall.symbol).apply { val constructorCall = irCall(delegatingConstructorCall.symbol, callSite.type,
constructorDescriptor.typeParameters.forEach() { putTypeArgument(it.index, delegatingConstructorCall.getTypeArgument(it)!!) } constructorDescriptor.typeParameters.map { delegatingConstructorCall.getTypeArgument(it)!! }).apply {
constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) } constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) }
} }
val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter
@@ -168,22 +269,33 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
} }
} }
val returnType = copyFunctionDeclaration.returnType // Substituted return type. val sourceFileName = context.originalModuleIndex.declarationToFile[callee.descriptor.original] ?: ""
val sourceFileName = context.originalModuleIndex.declarationToFile[caller.descriptor.original] ?: ""
val inlineFunctionBody = IrReturnableBlockImpl( // Create new IR element to replace "call". copyIrElement.addCurrentSubstituteMap(globalSubstituteMap)
val transformer = ParameterSubstitutor()
statements.transform { it.transform(transformer, data = null) }
statements.addAll(0, evaluationStatements)
return IrReturnableBlockImpl(
startOffset = startOffset, startOffset = startOffset,
endOffset = endOffset, endOffset = endOffset,
type = returnType, type = copiedCallee.returnType,
symbol = irReturnableBlockSymbol, symbol = irReturnableBlockSymbol,
origin = null, origin = null,
statements = statements, statements = statements,
sourceFileName = sourceFileName sourceFileName = sourceFileName
) ).apply {
transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid(this)
val transformer = ParameterSubstitutor() if (expression.returnTargetSymbol == copiedCallee.symbol)
inlineFunctionBody.transformChildrenVoid(transformer) // Replace value parameters with arguments. return irBuilder.irReturn(expression.value)
inlineFunctionBody.statements.addAll(0, evaluationStatements) // Insert evaluation statements. return expression
return inlineFunctionBody // Replace call site with InlineFunctionBody. }
})
}
} }
//---------------------------------------------------------------------// //---------------------------------------------------------------------//
@@ -193,32 +305,71 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
val newExpression = super.visitGetValue(expression) as IrGetValue val newExpression = super.visitGetValue(expression) as IrGetValue
val descriptor = newExpression.descriptor val descriptor = newExpression.descriptor
val argument = substituteMap[descriptor] // Find expression to replace this parameter. val argument = substituteMap[descriptor]
if (argument == null) return newExpression // If there is no such expression - do nothing.
if (argument == null) return newExpression
argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution. argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution.
return copyIrElement.copy( // Make copy of argument expression. return copyIrElement.copy(argument) as IrExpression
irElement = argument,
typeSubstitutor = null
) as IrExpression
} }
//-----------------------------------------------------------------// //-----------------------------------------------------------------//
private val IrFunctionReference.isLambda: Boolean
get() {
return symbol.owner.visibility == Visibilities.LOCAL && origin == IrStatementOrigin.LAMBDA
}
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
if (!isLambdaCall(expression))
return super.visitCall(expression)
if (!isLambdaCall(expression)) return super.visitCall(expression) // If it is not lambda call - return. 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)
val dispatchReceiver = expression.dispatchReceiver as IrGetValue // Here we can have only GetValue as dispatch receiver. if (functionArgument is IrFunctionReference) {
val functionArgument = substituteMap[dispatchReceiver.descriptor] // Try to find lambda representation. // TODO original? if (!functionArgument.isLambda) return super.visitCall(expression)
if (functionArgument == null) return super.visitCall(expression) // It is not call of argument lambda - nothing to substitute.
if (functionArgument !is IrBlock) return super.visitCall(expression)
val dispatchDescriptor = dispatchReceiver.descriptor // Check if this functional parameter has "noInline" tag val functionDescriptor = functionArgument.descriptor
if (dispatchDescriptor is ValueParameterDescriptor && val functionParameters = functionDescriptor.explicitParameters
dispatchDescriptor.isNoinline) return super.visitCall(expression) val boundFunctionParameters = functionArgument.getArguments()
val unboundFunctionParameters = functionParameters - boundFunctionParameters.map { it.first }
val boundFunctionParametersMap = boundFunctionParameters.associate { it.first to it.second }
val functionDeclaration = getLambdaFunction(functionArgument) var unboundIndex = 0
val unboundArgsSet = unboundFunctionParameters.toSet()
val valueParameters = expression.getArguments().drop(1) // Skip dispatch receiver.
val immediateCall = IrCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = expression.type,
symbol = functionArgument.symbol,
descriptor = functionArgument.descriptor).apply {
functionParameters.forEach {
val argument =
if (!unboundArgsSet.contains(it))
boundFunctionParametersMap[it]!!
else
valueParameters[unboundIndex++].second
when (it) {
functionDescriptor.dispatchReceiverParameter -> this.dispatchReceiver = argument
functionDescriptor.extensionReceiverParameter -> this.extensionReceiver = argument
else -> putValueArgument((it as ValueParameterDescriptor).index, argument)
}
}
assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" }
}
return owner.visitCall(super.visitCall(immediateCall) as IrCall, Ref(false))
}
if (functionArgument !is IrBlock)
return super.visitCall(expression)
val functionDeclaration = functionArgument.statements[0] as IrFunction
val newExpression = inlineFunction(expression, functionDeclaration) // Inline the lambda. Lambda parameters will be substituted with lambda arguments. val newExpression = inlineFunction(expression, functionDeclaration) // Inline the lambda. Lambda parameters will be substituted with lambda arguments.
return newExpression.transform(this, null) // Substitute lambda arguments with target function arguments. return newExpression.transform(this, null) // Substitute lambda arguments with target function arguments.
} }
@@ -228,22 +379,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
override fun visitElement(element: IrElement) = element.accept(this, null) override fun visitElement(element: IrElement) = element.accept(this, null)
} }
//--- Helpers -------------------------------------------------------------// private fun isLambdaCall(irCall: IrCall) = irCall.descriptor.isFunctionInvoke && irCall.dispatchReceiver is IrGetValue
private fun isLambdaCall(irCall: IrCall) : Boolean {
if (!irCall.descriptor.isFunctionInvoke) return false // Lambda mast be called by "invoke".
if (irCall.dispatchReceiver !is IrGetValue) return false // Dispatch receiver mast be IrGetValue.
return true // It is lambda call.
}
//-------------------------------------------------------------------------//
private fun getLambdaFunction(lambdaArgument: IrBlock): IrFunction {
val statements = lambdaArgument.statements
return statements[0] as IrFunction
}
//-------------------------------------------------------------------------//
private fun createTypeSubstitutor(irCall: IrCall): TypeSubstitutor? { private fun createTypeSubstitutor(irCall: IrCall): TypeSubstitutor? {
if (irCall.typeArgumentsCount == 0) return null if (irCall.typeArgumentsCount == 0) return null
@@ -259,95 +395,100 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private class ParameterToArgument(val parameterDescriptor: ParameterDescriptor, private class ParameterToArgument(val parameter: IrValueParameter,
val argumentExpression : IrExpression) { val argumentExpression : IrExpression) {
val isInlinableLambda : Boolean val isInlinableLambdaArgument : Boolean
get() { get() {
if (!InlineUtil.isInlineParameter(parameterDescriptor)) return false if (!InlineUtil.isInlineParameter(parameter.descriptor)) return false
if (argumentExpression !is IrBlock) return false // Lambda must be represented with IrBlock. if (argumentExpression is IrFunctionReference
if (argumentExpression.origin != IrStatementOrigin.LAMBDA && // Origin must be LAMBDA or ANONYMOUS. && !argumentExpression.descriptor.isSuspend) return true // Skip suspend functions for now since it's not supported by FE anyway.
argumentExpression.origin != IrStatementOrigin.ANONYMOUS_FUNCTION) return false
// 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 statements = argumentExpression.statements
val irFunction = statements[0] // Lambda function declaration. val irFunction = statements[0]
val irCallableReference = statements[1] // Lambda callable reference. val irCallableReference = statements[1]
if (irFunction !is IrFunction) return false // First statement of the block must be lambda declaration. if (irFunction !is IrFunction) return false
if (irCallableReference !is IrCallableReference) return false // Second statement of the block must be CallableReference. if (irCallableReference !is IrCallableReference) return false
return true // The expression represents lambda. return true
}
val isImmutableVariableLoad: Boolean
get() = argumentExpression.let {
it is IrGetValue && !it.descriptor.let { it is VariableDescriptor && it.isVar }
} }
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun buildParameterToArgument(irCall : IrCall, // Call site. private fun buildParameterToArgument(callSite: IrCall, callee: IrFunction): List<ParameterToArgument> {
irFunction: IrFunction // Function to be called.
): List<ParameterToArgument> {
val parameterToArgument = mutableListOf<ParameterToArgument>() // Result list. val parameterToArgument = mutableListOf<ParameterToArgument>()
val functionDescriptor = irFunction.descriptor.original // Descriptor of function to be called.
if (irCall.dispatchReceiver != null && // Only if there are non null dispatch receivers both if (callSite.dispatchReceiver != null && // Only if there are non null dispatch receivers both
functionDescriptor.dispatchReceiverParameter != null) // on call site and in function declaration. callee.dispatchReceiverParameter != null) // on call site and in function declaration.
parameterToArgument += ParameterToArgument( parameterToArgument += ParameterToArgument(
parameterDescriptor = functionDescriptor.dispatchReceiverParameter!!, parameter = callee.dispatchReceiverParameter!!,
argumentExpression = irCall.dispatchReceiver!! argumentExpression = callSite.dispatchReceiver!!
) )
val valueArguments = val valueArguments =
irCall.descriptor.valueParameters.map { irCall.getValueArgument(it) }.toMutableList() callSite.descriptor.valueParameters.map { callSite.getValueArgument(it) }.toMutableList()
if (functionDescriptor.extensionReceiverParameter != null) { if (callee.extensionReceiverParameter != null) {
parameterToArgument += ParameterToArgument( parameterToArgument += ParameterToArgument(
parameterDescriptor = functionDescriptor.extensionReceiverParameter!!, parameter = callee.extensionReceiverParameter!!,
argumentExpression = if (irCall.extensionReceiver != null) { argumentExpression = if (callSite.extensionReceiver != null) {
irCall.extensionReceiver!! callSite.extensionReceiver!!
} else { } else {
// 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 (irCall.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, irCall.extensionReceiver!!) valueArguments.add(0, callSite.extensionReceiver!!)
} }
val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>() val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>()
irFunction.valueParameters.forEach { parameter -> // Iterate value parameter descriptors. for (parameter in callee.valueParameters) {
val parameterDescriptor = parameter.descriptor as ValueParameterDescriptor val argument = valueArguments[parameter.index]
val argument = valueArguments[parameterDescriptor.index] // Get appropriate argument from call site.
when { when {
argument != null -> { // Argument is good enough. argument != null -> {
parameterToArgument += ParameterToArgument( // Associate current parameter with the argument. parameterToArgument += ParameterToArgument(
parameterDescriptor = parameterDescriptor, parameter = parameter,
argumentExpression = argument argumentExpression = argument
) )
} }
parameterDescriptor.hasDefaultValue() -> { // There is no argument - try default value. // After ExpectDeclarationsRemoving pass default values from expect declarations
val defaultArgument = irFunction.getDefault(parameterDescriptor)!! // are represented correctly in IR.
parameter.defaultValue != null -> { // There is no argument - try default value.
parametersWithDefaultToArgument += ParameterToArgument( parametersWithDefaultToArgument += ParameterToArgument(
parameterDescriptor = parameterDescriptor, parameter = parameter,
argumentExpression = defaultArgument.expression argumentExpression = parameter.defaultValue!!.expression
) )
} }
parameterDescriptor.varargElementType != null -> { parameter.varargElementType != null -> {
val emptyArray = IrVarargImpl( val emptyArray = IrVarargImpl(
startOffset = irCall.startOffset, startOffset = callSite.startOffset,
endOffset = irCall.endOffset, endOffset = callSite.endOffset,
type = parameter.type, type = parameter.type,
varargElementType = parameter.varargElementType!! varargElementType = parameter.varargElementType!!
) )
parameterToArgument += ParameterToArgument( parameterToArgument += ParameterToArgument(
parameterDescriptor = parameterDescriptor, parameter = parameter,
argumentExpression = emptyArray argumentExpression = emptyArray
) )
} }
else -> { else -> {
val message = "Incomplete expression: call to $functionDescriptor " + val message = "Incomplete expression: call to ${callee.descriptor} " +
"has no argument at index ${parameterDescriptor.index}" "has no argument at index ${parameter.index}"
throw Error(message) throw Error(message)
} }
} }
@@ -358,34 +499,42 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun evaluateArguments(irCall : IrCall, // Call site. private fun evaluateArguments(callSite: IrCall, callee: IrFunction): List<IrStatement> {
functionDeclaration: IrFunction // Function to be called.
): List<IrStatement> {
val parameterToArgumentOld = buildParameterToArgument(irCall, functionDeclaration) // Create map parameter_descriptor -> original_argument_expression. val parameterToArgumentOld = buildParameterToArgument(callSite, callee)
val evaluationStatements = mutableListOf<IrStatement>() // List of evaluation statements. val evaluationStatements = mutableListOf<IrStatement>()
val substitutor = ParameterSubstitutor() val substitutor = ParameterSubstitutor()
parameterToArgumentOld.forEach { parameterToArgumentOld.forEach {
val parameterDescriptor = it.parameterDescriptor val parameterDescriptor = it.parameter.descriptor
if (it.isInlinableLambda || it.argumentExpression is IrGetValue) { // If argument is inlinable lambda. IrGetValue is skipped because of recursive inline. /*
substituteMap[parameterDescriptor] = it.argumentExpression // Associate parameter with lambda argument. * We need to create temporary variable for each argument except inlinable lambda arguments.
* For simplicity and to produce simpler IR we don't create temporaries for every immutable variable,
* not only for those referring to inlinable lambdas.
*/
if (it.isInlinableLambdaArgument) {
substituteMap[parameterDescriptor] = it.argumentExpression
return@forEach return@forEach
} }
val newVariable = currentScope.scope.createTemporaryVariable( // Create new variable and init it with the parameter expression. 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. irExpression = it.argumentExpression.transform(substitutor, data = null), // Arguments may reference the previous ones - substitute them.
nameHint = functionDeclaration.descriptor.name.toString(), nameHint = callee.descriptor.name.toString(),
isMutable = false) isMutable = false)
evaluationStatements.add(newVariable) // Add initialization of the new variable in statement list. evaluationStatements.add(newVariable)
val getVal = IrGetValueImpl( // Create new expression, representing access the new variable. val getVal = IrGetValueImpl(
startOffset = currentScope.irElement.startOffset, startOffset = currentScope.irElement.startOffset,
endOffset = currentScope.irElement.endOffset, endOffset = currentScope.irElement.endOffset,
type = newVariable.type, type = newVariable.type,
symbol = newVariable.symbol symbol = newVariable.symbol
) )
substituteMap[parameterDescriptor] = getVal // Parameter will be replaced with the new variable. substituteMap[parameterDescriptor] = getVal
} }
return evaluationStatements return evaluationStatements
} }
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
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.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
@@ -49,8 +50,8 @@ class Psi2IrTranslator(
return generateModuleFragment(context, ktFiles) return generateModuleFragment(context, ktFiles)
} }
fun createGeneratorContext(moduleDescriptor: ModuleDescriptor, bindingContext: BindingContext) = fun createGeneratorContext(moduleDescriptor: ModuleDescriptor, bindingContext: BindingContext, symbolTable: SymbolTable = SymbolTable()) =
GeneratorContext(configuration, moduleDescriptor, bindingContext, languageVersionSettings) GeneratorContext(configuration, moduleDescriptor, bindingContext, languageVersionSettings, symbolTable)
fun generateModuleFragment(context: GeneratorContext, ktFiles: Collection<KtFile>): IrModuleFragment { fun generateModuleFragment(context: GeneratorContext, ktFiles: Collection<KtFile>): IrModuleFragment {
val moduleGenerator = ModuleGenerator(context) val moduleGenerator = ModuleGenerator(context)
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.declarations.lazy.IrLazySymbolTable import org.jetbrains.kotlin.ir.declarations.lazy.IrLazySymbolTable
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
@@ -466,6 +467,17 @@ open class SymbolTable : ReferenceSymbolTable {
globalTypeParameterSymbolTable.descriptorToSymbol[declaration.descriptor] = declaration.symbol globalTypeParameterSymbolTable.descriptorToSymbol[declaration.descriptor] = declaration.symbol
super.visitTypeParameter(declaration) super.visitTypeParameter(declaration)
} }
override fun visitCall(expression: IrCall) {
expression.symbol.let {
when (it) {
is IrSimpleFunctionSymbol -> simpleFunctionSymbolTable.descriptorToSymbol[it.descriptor] = it
is IrConstructorSymbol -> constructorSymbolTable.descriptorToSymbol[it.descriptor] = it
}
}
super.visitCall(expression)
}
}) })
} }
} }