[JS IR BE] New Inliner from native
This commit is contained in:
+4
-9
@@ -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()
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -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)
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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()
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+435
-139
@@ -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,
|
||||||
|
|||||||
+312
-163
@@ -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)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user