JS IR: inliner
This commit is contained in:
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
|||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
|
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.inline.ModuleIndex
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
@@ -60,6 +61,8 @@ class JsIrBackendContext(
|
|||||||
|
|
||||||
fun getOperatorByName(name: Name, type: KotlinType) = operatorMap[name]?.get(type)
|
fun getOperatorByName(name: Name, type: KotlinType) = operatorMap[name]?.get(type)
|
||||||
|
|
||||||
|
val originalModuleIndex = ModuleIndex(irModuleFragment)
|
||||||
|
|
||||||
override val ir = object : Ir<CommonBackendContext>(this, irModuleFragment) {
|
override val ir = object : Ir<CommonBackendContext>(this, irModuleFragment) {
|
||||||
override val symbols = object : Symbols<CommonBackendContext>(this@JsIrBackendContext, symbolTable) {
|
override val symbols = object : Symbols<CommonBackendContext>(this@JsIrBackendContext, symbolTable) {
|
||||||
|
|
||||||
|
|||||||
@@ -10,9 +10,15 @@ import org.jetbrains.kotlin.backend.common.lower.*
|
|||||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.ir.backend.js.lower.*
|
import org.jetbrains.kotlin.ir.backend.js.lower.*
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.inline.FunctionInlining
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.inline.ReturnableBlockLowering
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.inline.referenceAllTypeExternalClassifiers
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.inline.replaceUnboundSymbols
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||||
|
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||||
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
|
||||||
@@ -33,7 +39,7 @@ fun compile(
|
|||||||
val psi2IrTranslator = Psi2IrTranslator()
|
val psi2IrTranslator = Psi2IrTranslator()
|
||||||
val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext)
|
val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext)
|
||||||
|
|
||||||
val moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files)
|
val moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files).removeDuplicates()
|
||||||
|
|
||||||
val context = JsIrBackendContext(
|
val context = JsIrBackendContext(
|
||||||
analysisResult.moduleDescriptor,
|
analysisResult.moduleDescriptor,
|
||||||
@@ -44,6 +50,8 @@ fun compile(
|
|||||||
|
|
||||||
ExternalDependenciesGenerator(psi2IrContext.symbolTable, psi2IrContext.irBuiltIns).generateUnboundSymbolsAsDependencies(moduleFragment)
|
ExternalDependenciesGenerator(psi2IrContext.symbolTable, psi2IrContext.irBuiltIns).generateUnboundSymbolsAsDependencies(moduleFragment)
|
||||||
|
|
||||||
|
context.performInlining(moduleFragment)
|
||||||
|
|
||||||
moduleFragment.files.forEach { context.lower(it) }
|
moduleFragment.files.forEach { context.lower(it) }
|
||||||
val transformer = SecondaryCtorLowering.CallsiteRedirectionTransformer(context)
|
val transformer = SecondaryCtorLowering.CallsiteRedirectionTransformer(context)
|
||||||
moduleFragment.files.forEach { it.accept(transformer, null) }
|
moduleFragment.files.forEach { it.accept(transformer, null) }
|
||||||
@@ -53,10 +61,25 @@ fun compile(
|
|||||||
return program.toString()
|
return program.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun JsIrBackendContext.performInlining(moduleFragment: IrModuleFragment) {
|
||||||
|
FunctionInlining(this).inline(moduleFragment)
|
||||||
|
|
||||||
|
moduleFragment.referenceAllTypeExternalClassifiers(symbolTable)
|
||||||
|
|
||||||
|
do {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
moduleFragment.replaceUnboundSymbols(this)
|
||||||
|
moduleFragment.referenceAllTypeExternalClassifiers(symbolTable)
|
||||||
|
} while (symbolTable.unboundClasses.isNotEmpty())
|
||||||
|
|
||||||
|
moduleFragment.patchDeclarationParents()
|
||||||
|
}
|
||||||
|
|
||||||
fun JsIrBackendContext.lower(file: IrFile) {
|
fun JsIrBackendContext.lower(file: IrFile) {
|
||||||
LateinitLowering(this, true).lower(file)
|
LateinitLowering(this, true).lower(file)
|
||||||
DefaultArgumentStubGenerator(this).runOnFilePostfix(file)
|
DefaultArgumentStubGenerator(this).runOnFilePostfix(file)
|
||||||
SharedVariablesLowering(this).runOnFilePostfix(file)
|
SharedVariablesLowering(this).runOnFilePostfix(file)
|
||||||
|
ReturnableBlockLowering(this).lower(file)
|
||||||
LocalDeclarationsLowering(this).runOnFilePostfix(file)
|
LocalDeclarationsLowering(this).runOnFilePostfix(file)
|
||||||
InnerClassesLowering(this).runOnFilePostfix(file)
|
InnerClassesLowering(this).runOnFilePostfix(file)
|
||||||
InnerClassConstructorCallsLowering(this).runOnFilePostfix(file)
|
InnerClassConstructorCallsLowering(this).runOnFilePostfix(file)
|
||||||
@@ -67,4 +90,19 @@ fun JsIrBackendContext.lower(file: IrFile) {
|
|||||||
SecondaryCtorLowering(this).runOnFilePostfix(file)
|
SecondaryCtorLowering(this).runOnFilePostfix(file)
|
||||||
CallableReferenceLowering(this).lower(file)
|
CallableReferenceLowering(this).lower(file)
|
||||||
IntrinsicifyCallsLowering(this).lower(file)
|
IntrinsicifyCallsLowering(this).lower(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO find out why duplicates occur
|
||||||
|
private fun IrModuleFragment.removeDuplicates(): IrModuleFragment {
|
||||||
|
|
||||||
|
fun <T> MutableList<T>.removeDuplicates() {
|
||||||
|
val tmp = toSet()
|
||||||
|
clear()
|
||||||
|
addAll(tmp)
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencyModules.removeDuplicates()
|
||||||
|
dependencyModules.forEach { it.externalPackageFragments.removeDuplicates() }
|
||||||
|
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
+22
-4
@@ -18,8 +18,7 @@ import org.jetbrains.kotlin.ir.declarations.*
|
|||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
private typealias VisitData = Nothing?
|
private typealias VisitData = Nothing?
|
||||||
@@ -153,7 +152,9 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
|
|||||||
private fun processStatement(statement: IrStatement, data: VisitData): List<IrStatement>? {
|
private fun processStatement(statement: IrStatement, data: VisitData): List<IrStatement>? {
|
||||||
val result = statement.accept(this, data)
|
val result = statement.accept(this, data)
|
||||||
|
|
||||||
if (result == KeptResult) return null
|
if (result == KeptResult) {
|
||||||
|
return if (statement is IrComposite) statement.statements else null
|
||||||
|
}
|
||||||
return result.statements
|
return result.statements
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,7 +437,11 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
|
|||||||
resultValue
|
resultValue
|
||||||
}
|
}
|
||||||
collectingList += JsIrBuilder.buildSetVariable(variable, result)
|
collectingList += JsIrBuilder.buildSetVariable(variable, result)
|
||||||
DecomposedResult(mutableListOf(varDeclaration, body), JsIrBuilder.buildGetValue(variable))
|
if (body is IrComposite) {
|
||||||
|
DecomposedResult(mutableListOf(varDeclaration, *collectingList.toTypedArray()) , JsIrBuilder.buildGetValue(variable))
|
||||||
|
} else {
|
||||||
|
DecomposedResult(mutableListOf(varDeclaration, body as IrStatement), JsIrBuilder.buildGetValue(variable))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// do not allow variable to be uninitialized
|
// do not allow variable to be uninitialized
|
||||||
DecomposedResult(mutableListOf(), unitValue)
|
DecomposedResult(mutableListOf(), unitValue)
|
||||||
@@ -658,6 +663,19 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : DeclarationCont
|
|||||||
return DecomposedResult(jump, JsIrBuilder.buildCall(unreachableFunction))
|
return DecomposedResult(jump, JsIrBuilder.buildCall(unreachableFunction))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitLoop(loop: IrLoop, data: VisitData): VisitResult {
|
||||||
|
val result = loop.accept(statementVisitor, data)
|
||||||
|
return if (result.status == VisitStatus.KEPT) {
|
||||||
|
DecomposedResult(loop, unitValue)
|
||||||
|
} else result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSetField(expression: IrSetField, data: VisitData): VisitResult {
|
||||||
|
val result = expression.accept(statementVisitor, data)
|
||||||
|
return if (result.status == VisitStatus.KEPT) {
|
||||||
|
DecomposedResult(expression, unitValue)
|
||||||
|
} else result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun makeTempVar(type: KotlinType) =
|
fun makeTempVar(type: KotlinType) =
|
||||||
|
|||||||
+766
@@ -0,0 +1,766 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.lower.inline
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||||
|
import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
|
||||||
|
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.impl.createClassSymbolOrNull
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.impl.createFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.impl.createValueSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.DeepCopyIrTree
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
|
||||||
|
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||||
|
|
||||||
|
|
||||||
|
// backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DeepCopyIrTreeWithDescriptors.kt
|
||||||
|
internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
|
||||||
|
val parentDescriptor: DeclarationDescriptor,
|
||||||
|
val context: JsIrBackendContext) {
|
||||||
|
|
||||||
|
private val descriptorSubstituteMap: MutableMap<DeclarationDescriptor, DeclarationDescriptor> = mutableMapOf()
|
||||||
|
private var typeSubstitutor: TypeSubstitutor? = null
|
||||||
|
private var nameIndex = 0
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
fun copy(irElement: IrElement, typeSubstitutor: TypeSubstitutor?): IrElement {
|
||||||
|
this.typeSubstitutor = typeSubstitutor
|
||||||
|
// Create all class descriptors and all necessary descriptors in order to create KotlinTypes.
|
||||||
|
irElement.acceptChildrenVoid(DescriptorCollectorCreatePhase())
|
||||||
|
// Initialize all created descriptors possibly using previously created types.
|
||||||
|
irElement.acceptChildrenVoid(DescriptorCollectorInitPhase())
|
||||||
|
return irElement.accept(InlineCopyIr(), null)
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class DescriptorCollectorCreatePhase : IrElementVisitorVoidWithContext() {
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildren(this, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitClassNew(declaration: IrClass) {
|
||||||
|
val oldDescriptor = declaration.descriptor
|
||||||
|
val newDescriptor = copyClassDescriptor(oldDescriptor)
|
||||||
|
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
||||||
|
descriptorSubstituteMap[oldDescriptor.thisAsReceiverParameter] = newDescriptor.thisAsReceiverParameter
|
||||||
|
|
||||||
|
super.visitClassNew(declaration)
|
||||||
|
|
||||||
|
val constructors = oldDescriptor.constructors.map { oldConstructorDescriptor ->
|
||||||
|
descriptorSubstituteMap[oldConstructorDescriptor] as ClassConstructorDescriptor
|
||||||
|
}.toSet()
|
||||||
|
|
||||||
|
val oldPrimaryConstructor = oldDescriptor.unsubstitutedPrimaryConstructor
|
||||||
|
val primaryConstructor = oldPrimaryConstructor?.let { descriptorSubstituteMap[it] as ClassConstructorDescriptor }
|
||||||
|
|
||||||
|
val contributedDescriptors = oldDescriptor.unsubstitutedMemberScope
|
||||||
|
.getContributedDescriptors()
|
||||||
|
.map { descriptorSubstituteMap[it]!! }
|
||||||
|
newDescriptor.initialize(
|
||||||
|
SimpleMemberScope(contributedDescriptors),
|
||||||
|
constructors,
|
||||||
|
primaryConstructor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitPropertyNew(declaration: IrProperty) {
|
||||||
|
copyPropertyOrField(declaration.descriptor)
|
||||||
|
super.visitPropertyNew(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitFieldNew(declaration: IrField) {
|
||||||
|
val oldDescriptor = declaration.descriptor
|
||||||
|
if (descriptorSubstituteMap[oldDescriptor] == null) {
|
||||||
|
copyPropertyOrField(oldDescriptor) // A field without a property or a field of a delegated property.
|
||||||
|
}
|
||||||
|
super.visitFieldNew(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitFunctionNew(declaration: IrFunction) {
|
||||||
|
val oldDescriptor = declaration.descriptor
|
||||||
|
if (oldDescriptor !is PropertyAccessorDescriptor) { // Property accessors are copied along with their property.
|
||||||
|
val oldContainingDeclaration =
|
||||||
|
if (oldDescriptor.visibility == Visibilities.LOCAL)
|
||||||
|
parentDescriptor
|
||||||
|
else
|
||||||
|
oldDescriptor.containingDeclaration
|
||||||
|
descriptorSubstituteMap[oldDescriptor] = copyFunctionDescriptor(oldDescriptor, oldContainingDeclaration)
|
||||||
|
}
|
||||||
|
super.visitFunctionNew(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--- Copy descriptors ------------------------------------------------//
|
||||||
|
|
||||||
|
private fun generateCopyName(name: Name): Name {
|
||||||
|
val declarationName = name.toString() // Name of declaration
|
||||||
|
val indexStr = (nameIndex++).toString() // Unique for inline target index
|
||||||
|
return Name.identifier(declarationName /*+ "_" + indexStr*/)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyFunctionDescriptor(oldDescriptor: CallableDescriptor, oldContainingDeclaration: DeclarationDescriptor) =
|
||||||
|
when (oldDescriptor) {
|
||||||
|
is ConstructorDescriptor -> copyConstructorDescriptor(oldDescriptor)
|
||||||
|
is SimpleFunctionDescriptor -> copySimpleFunctionDescriptor(oldDescriptor, oldContainingDeclaration)
|
||||||
|
else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor")
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copySimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor, oldContainingDeclaration: DeclarationDescriptor) : FunctionDescriptor {
|
||||||
|
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
|
||||||
|
return SimpleFunctionDescriptorImpl.create(
|
||||||
|
/* containingDeclaration = */ newContainingDeclaration,
|
||||||
|
/* annotations = */ oldDescriptor.annotations,
|
||||||
|
/* name = */ generateCopyName(oldDescriptor.name),
|
||||||
|
/* kind = */ oldDescriptor.kind,
|
||||||
|
/* source = */ oldDescriptor.source
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyConstructorDescriptor(oldDescriptor: ConstructorDescriptor) : FunctionDescriptor {
|
||||||
|
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
||||||
|
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
|
||||||
|
return ClassConstructorDescriptorImpl.create(
|
||||||
|
/* containingDeclaration = */ newContainingDeclaration as ClassDescriptor,
|
||||||
|
/* annotations = */ oldDescriptor.annotations,
|
||||||
|
/* isPrimary = */ oldDescriptor.isPrimary,
|
||||||
|
/* source = */ oldDescriptor.source
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyPropertyOrField(oldDescriptor: PropertyDescriptor) {
|
||||||
|
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
||||||
|
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) as ClassDescriptor
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
val newDescriptor = PropertyDescriptorImpl.create(
|
||||||
|
/* containingDeclaration = */ newContainingDeclaration,
|
||||||
|
/* annotations = */ oldDescriptor.annotations,
|
||||||
|
/* modality = */ oldDescriptor.modality,
|
||||||
|
/* visibility = */ oldDescriptor.visibility,
|
||||||
|
/* isVar = */ oldDescriptor.isVar,
|
||||||
|
/* name = */ oldDescriptor.name,
|
||||||
|
/* kind = */ oldDescriptor.kind,
|
||||||
|
/* source = */ oldDescriptor.source,
|
||||||
|
/* lateInit = */ oldDescriptor.isLateInit,
|
||||||
|
/* isConst = */ oldDescriptor.isConst,
|
||||||
|
/* isExpect = */ oldDescriptor.isExpect,
|
||||||
|
/* isActual = */ oldDescriptor.isActual,
|
||||||
|
/* isExternal = */ oldDescriptor.isExternal,
|
||||||
|
/* isDelegated = */ oldDescriptor.isDelegated
|
||||||
|
)
|
||||||
|
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyClassDescriptor(oldDescriptor: ClassDescriptor): ClassDescriptorImpl {
|
||||||
|
val oldSuperClass = oldDescriptor.getSuperClassOrAny()
|
||||||
|
val newSuperClass = descriptorSubstituteMap.getOrDefault(oldSuperClass, oldSuperClass) as ClassDescriptor
|
||||||
|
val oldInterfaces = oldDescriptor.getSuperInterfaces()
|
||||||
|
val newInterfaces = oldInterfaces.map { descriptorSubstituteMap.getOrDefault(it, it) as ClassDescriptor }
|
||||||
|
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
||||||
|
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
|
||||||
|
val newName = if (DescriptorUtils.isAnonymousObject(oldDescriptor)) // Anonymous objects are identified by their name.
|
||||||
|
oldDescriptor.name // We need to preserve it for LocalDeclarationsLowering.
|
||||||
|
else
|
||||||
|
generateCopyName(oldDescriptor.name)
|
||||||
|
|
||||||
|
val visibility = oldDescriptor.visibility
|
||||||
|
|
||||||
|
return object : ClassDescriptorImpl(
|
||||||
|
/* containingDeclaration = */ newContainingDeclaration,
|
||||||
|
/* name = */ newName,
|
||||||
|
/* modality = */ oldDescriptor.modality,
|
||||||
|
/* kind = */ oldDescriptor.kind,
|
||||||
|
/* supertypes = */ listOf(newSuperClass.defaultType) + newInterfaces.map { it.defaultType },
|
||||||
|
/* source = */ oldDescriptor.source,
|
||||||
|
/* isExternal = */ oldDescriptor.isExternal,
|
||||||
|
LockBasedStorageManager.NO_LOCKS
|
||||||
|
) {
|
||||||
|
override fun getVisibility() = visibility
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
inner class DescriptorCollectorInitPhase : IrElementVisitorVoidWithContext() {
|
||||||
|
|
||||||
|
private val initializedProperties = mutableSetOf<PropertyDescriptor>()
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildren(this, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitPropertyNew(declaration: IrProperty) {
|
||||||
|
initPropertyOrField(declaration.descriptor)
|
||||||
|
super.visitPropertyNew(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitFieldNew(declaration: IrField) {
|
||||||
|
val oldDescriptor = declaration.descriptor
|
||||||
|
if (!initializedProperties.contains(oldDescriptor)) {
|
||||||
|
initPropertyOrField(oldDescriptor) // A field without a property or a field of a delegated property.
|
||||||
|
}
|
||||||
|
super.visitFieldNew(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitFunctionNew(declaration: IrFunction) {
|
||||||
|
val oldDescriptor = declaration.descriptor
|
||||||
|
if (oldDescriptor !is PropertyAccessorDescriptor) { // Property accessors are copied along with their property.
|
||||||
|
val newDescriptor = initFunctionDescriptor(oldDescriptor)
|
||||||
|
oldDescriptor.extensionReceiverParameter?.let {
|
||||||
|
descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.visitFunctionNew(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitVariable(declaration: IrVariable) {
|
||||||
|
declaration.descriptor.let { descriptorSubstituteMap[it] = copyVariableDescriptor(it) }
|
||||||
|
|
||||||
|
super.visitVariable(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitCatch(aCatch: IrCatch) {
|
||||||
|
aCatch.parameter.let { descriptorSubstituteMap[it] = copyVariableDescriptor(it) }
|
||||||
|
|
||||||
|
super.visitCatch(aCatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--- Copy descriptors ------------------------------------------------//
|
||||||
|
|
||||||
|
private fun generateCopyName(name: Name): Name {
|
||||||
|
val declarationName = name.toString() // Name of declaration
|
||||||
|
val indexStr = (nameIndex++).toString() // Unique for inline target index
|
||||||
|
return Name.identifier(declarationName /*+ "_" + indexStr*/)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyVariableDescriptor(oldDescriptor: VariableDescriptor): VariableDescriptor {
|
||||||
|
val oldContainingDeclaration = oldDescriptor.containingDeclaration
|
||||||
|
val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
|
||||||
|
return IrTemporaryVariableDescriptorImpl(
|
||||||
|
containingDeclaration = newContainingDeclaration,
|
||||||
|
name = generateCopyName(oldDescriptor.name),
|
||||||
|
outType = substituteTypeAndTryGetCopied(oldDescriptor.type)!!,
|
||||||
|
isMutable = oldDescriptor.isVar
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun initFunctionDescriptor(oldDescriptor: CallableDescriptor): CallableDescriptor =
|
||||||
|
when (oldDescriptor) {
|
||||||
|
is ConstructorDescriptor -> initConstructorDescriptor(oldDescriptor)
|
||||||
|
is SimpleFunctionDescriptor -> initSimpleFunctionDescriptor(oldDescriptor)
|
||||||
|
else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor")
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun initSimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor): FunctionDescriptor =
|
||||||
|
(descriptorSubstituteMap[oldDescriptor] as SimpleFunctionDescriptorImpl).apply {
|
||||||
|
val oldDispatchReceiverParameter = oldDescriptor.dispatchReceiverParameter
|
||||||
|
val newDispatchReceiverParameter = oldDispatchReceiverParameter?.let { descriptorSubstituteMap.getOrDefault(it, it) as ReceiverParameterDescriptor }
|
||||||
|
val newTypeParameters = oldDescriptor.typeParameters // TODO substitute types
|
||||||
|
val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
|
||||||
|
val newReceiverParameterType = substituteTypeAndTryGetCopied(oldDescriptor.extensionReceiverParameter?.type)
|
||||||
|
val newReturnType = substituteTypeAndTryGetCopied(oldDescriptor.returnType)
|
||||||
|
|
||||||
|
initialize(
|
||||||
|
/* receiverParameterType = */ newReceiverParameterType,
|
||||||
|
/* dispatchReceiverParameter = */ newDispatchReceiverParameter,
|
||||||
|
/* typeParameters = */ newTypeParameters,
|
||||||
|
/* unsubstitutedValueParameters = */ newValueParameters,
|
||||||
|
/* unsubstitutedReturnType = */ newReturnType,
|
||||||
|
/* modality = */ oldDescriptor.modality,
|
||||||
|
/* visibility = */ oldDescriptor.visibility
|
||||||
|
)
|
||||||
|
isTailrec = oldDescriptor.isTailrec
|
||||||
|
isSuspend = oldDescriptor.isSuspend
|
||||||
|
overriddenDescriptors += oldDescriptor.overriddenDescriptors
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun initConstructorDescriptor(oldDescriptor: ConstructorDescriptor): FunctionDescriptor =
|
||||||
|
(descriptorSubstituteMap[oldDescriptor] as ClassConstructorDescriptorImpl).apply {
|
||||||
|
val newTypeParameters = oldDescriptor.typeParameters
|
||||||
|
val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
|
||||||
|
val receiverParameterType = substituteTypeAndTryGetCopied(oldDescriptor.dispatchReceiverParameter?.type)
|
||||||
|
val returnType = substituteTypeAndTryGetCopied(oldDescriptor.returnType)
|
||||||
|
|
||||||
|
initialize(
|
||||||
|
/* receiverParameterType = */ receiverParameterType,
|
||||||
|
/* dispatchReceiverParameter = */ null, // For constructor there is no explicit dispatch receiver.
|
||||||
|
/* typeParameters = */ newTypeParameters,
|
||||||
|
/* unsubstitutedValueParameters = */ newValueParameters,
|
||||||
|
/* unsubstitutedReturnType = */ returnType,
|
||||||
|
/* modality = */ oldDescriptor.modality,
|
||||||
|
/* visibility = */ oldDescriptor.visibility
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun initPropertyOrField(oldDescriptor: PropertyDescriptor) {
|
||||||
|
val newDescriptor = (descriptorSubstituteMap[oldDescriptor] as PropertyDescriptorImpl).apply {
|
||||||
|
setType(
|
||||||
|
/* outType = */ substituteTypeAndTryGetCopied(oldDescriptor.type)!!,
|
||||||
|
/* typeParameters = */ oldDescriptor.typeParameters,
|
||||||
|
/* dispatchReceiverParameter = */ (containingDeclaration as ClassDescriptor).thisAsReceiverParameter,
|
||||||
|
/* receiverType = */ substituteTypeAndTryGetCopied(oldDescriptor.extensionReceiverParameter?.type))
|
||||||
|
|
||||||
|
initialize(
|
||||||
|
/* getter = */ oldDescriptor.getter?.let { copyPropertyGetterDescriptor(it, this) },
|
||||||
|
/* setter = */ oldDescriptor.setter?.let { copyPropertySetterDescriptor(it, this) })
|
||||||
|
|
||||||
|
overriddenDescriptors += oldDescriptor.overriddenDescriptors
|
||||||
|
}
|
||||||
|
oldDescriptor.getter?.let { descriptorSubstituteMap[it] = newDescriptor.getter!! }
|
||||||
|
oldDescriptor.setter?.let { descriptorSubstituteMap[it] = newDescriptor.setter!! }
|
||||||
|
oldDescriptor.extensionReceiverParameter?.let {
|
||||||
|
descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!!
|
||||||
|
}
|
||||||
|
initializedProperties.add(oldDescriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyPropertyGetterDescriptor(oldDescriptor: PropertyGetterDescriptor, newPropertyDescriptor: PropertyDescriptor) =
|
||||||
|
PropertyGetterDescriptorImpl(
|
||||||
|
/* correspondingProperty = */ newPropertyDescriptor,
|
||||||
|
/* annotations = */ oldDescriptor.annotations,
|
||||||
|
/* modality = */ oldDescriptor.modality,
|
||||||
|
/* visibility = */ oldDescriptor.visibility,
|
||||||
|
/* isDefault = */ oldDescriptor.isDefault,
|
||||||
|
/* isExternal = */ oldDescriptor.isExternal,
|
||||||
|
/* isInline = */ oldDescriptor.isInline,
|
||||||
|
/* kind = */ oldDescriptor.kind,
|
||||||
|
/* original = */ null,
|
||||||
|
/* source = */ oldDescriptor.source).apply {
|
||||||
|
initialize(substituteTypeAndTryGetCopied(oldDescriptor.returnType))
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyPropertySetterDescriptor(oldDescriptor: PropertySetterDescriptor, newPropertyDescriptor: PropertyDescriptor) =
|
||||||
|
PropertySetterDescriptorImpl(
|
||||||
|
/* correspondingProperty = */ newPropertyDescriptor,
|
||||||
|
/* annotations = */ oldDescriptor.annotations,
|
||||||
|
/* modality = */ oldDescriptor.modality,
|
||||||
|
/* visibility = */ oldDescriptor.visibility,
|
||||||
|
/* isDefault = */ oldDescriptor.isDefault,
|
||||||
|
/* isExternal = */ oldDescriptor.isExternal,
|
||||||
|
/* isInline = */ oldDescriptor.isInline,
|
||||||
|
/* kind = */ oldDescriptor.kind,
|
||||||
|
/* original = */ null,
|
||||||
|
/* source = */ oldDescriptor.source).apply {
|
||||||
|
initialize(copyValueParameters(oldDescriptor.valueParameters, this).single())
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyValueParameters(oldValueParameters: List <ValueParameterDescriptor>, containingDeclaration: CallableDescriptor) =
|
||||||
|
oldValueParameters.map { oldDescriptor ->
|
||||||
|
val newDescriptor = ValueParameterDescriptorImpl(
|
||||||
|
containingDeclaration = containingDeclaration,
|
||||||
|
original = oldDescriptor.original,
|
||||||
|
index = oldDescriptor.index,
|
||||||
|
annotations = oldDescriptor.annotations,
|
||||||
|
name = oldDescriptor.name,
|
||||||
|
outType = substituteTypeAndTryGetCopied(oldDescriptor.type)!!,
|
||||||
|
declaresDefaultValue = oldDescriptor.declaresDefaultValue(),
|
||||||
|
isCrossinline = oldDescriptor.isCrossinline,
|
||||||
|
isNoinline = oldDescriptor.isNoinline,
|
||||||
|
varargElementType = substituteTypeAndTryGetCopied(oldDescriptor.varargElementType),
|
||||||
|
source = oldDescriptor.source
|
||||||
|
)
|
||||||
|
descriptorSubstituteMap[oldDescriptor] = newDescriptor
|
||||||
|
newDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
inner class InlineCopyIr : DeepCopyIrTree() {
|
||||||
|
|
||||||
|
override fun mapClassDeclaration (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
|
||||||
|
override fun mapTypeAliasDeclaration (descriptor: TypeAliasDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as TypeAliasDescriptor
|
||||||
|
override fun mapFunctionDeclaration (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
|
||||||
|
override fun mapConstructorDeclaration (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
|
||||||
|
override fun mapPropertyDeclaration (descriptor: PropertyDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as PropertyDescriptor
|
||||||
|
override fun mapLocalPropertyDeclaration (descriptor: VariableDescriptorWithAccessors) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptorWithAccessors
|
||||||
|
override fun mapEnumEntryDeclaration (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
|
||||||
|
override fun mapVariableDeclaration (descriptor: VariableDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptor
|
||||||
|
override fun mapErrorDeclaration (descriptor: DeclarationDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor)
|
||||||
|
|
||||||
|
override fun mapClassReference (descriptor: ClassDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassDescriptor
|
||||||
|
override fun mapValueReference (descriptor: ValueDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ValueDescriptor
|
||||||
|
override fun mapVariableReference (descriptor: VariableDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptor
|
||||||
|
override fun mapPropertyReference (descriptor: PropertyDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as PropertyDescriptor
|
||||||
|
override fun mapCallee (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
|
||||||
|
override fun mapDelegatedConstructorCallee (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
|
||||||
|
override fun mapEnumConstructorCallee (descriptor: ClassConstructorDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassConstructorDescriptor
|
||||||
|
override fun mapLocalPropertyReference (descriptor: VariableDescriptorWithAccessors) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as VariableDescriptorWithAccessors
|
||||||
|
override fun mapClassifierReference (descriptor: ClassifierDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as ClassifierDescriptor
|
||||||
|
override fun mapReturnTarget (descriptor: FunctionDescriptor) = descriptorSubstituteMap.getOrDefault(descriptor, descriptor) as FunctionDescriptor
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun mapSuperQualifier(qualifier: ClassDescriptor?): ClassDescriptor? {
|
||||||
|
if (qualifier == null) return null
|
||||||
|
return descriptorSubstituteMap.getOrDefault(qualifier, qualifier) as ClassDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
//--- Visits ----------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrCall {
|
||||||
|
if (expression !is IrCallImpl) return super.visitCall(expression)
|
||||||
|
val newDescriptor = mapCallee(expression.descriptor)
|
||||||
|
return IrCallImpl(
|
||||||
|
startOffset = expression.startOffset,
|
||||||
|
endOffset = expression.endOffset,
|
||||||
|
type = newDescriptor.returnType!!,
|
||||||
|
descriptor = newDescriptor,
|
||||||
|
typeArgumentsCount = expression.typeArgumentsCount,
|
||||||
|
origin = expression.origin,
|
||||||
|
superQualifierDescriptor = mapSuperQualifier(expression.superQualifier)
|
||||||
|
).apply {
|
||||||
|
transformValueArguments(expression)
|
||||||
|
substituteTypeArguments(expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction): IrFunction =
|
||||||
|
IrFunctionImpl(
|
||||||
|
startOffset = declaration.startOffset,
|
||||||
|
endOffset = declaration.endOffset,
|
||||||
|
origin = mapDeclarationOrigin(declaration.origin),
|
||||||
|
descriptor = mapFunctionDeclaration(declaration.descriptor),
|
||||||
|
body = declaration.body?.transform(this, null)
|
||||||
|
).also {
|
||||||
|
it.setOverrides(context.symbolTable)
|
||||||
|
}.transformParameters(declaration)
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun <T : IrFunction> T.transformDefaults(original: T): T {
|
||||||
|
for (originalValueParameter in original.descriptor.valueParameters) {
|
||||||
|
val valueParameter = descriptor.valueParameters[originalValueParameter.index]
|
||||||
|
original.getDefault(originalValueParameter)?.let { irDefaultParameterValue ->
|
||||||
|
putDefault(valueParameter, irDefaultParameterValue.transform(this@InlineCopyIr, null))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
fun getTypeOperatorReturnType(operator: IrTypeOperator, type: KotlinType) : KotlinType {
|
||||||
|
return when (operator) {
|
||||||
|
IrTypeOperator.CAST,
|
||||||
|
IrTypeOperator.IMPLICIT_CAST,
|
||||||
|
IrTypeOperator.IMPLICIT_NOTNULL,
|
||||||
|
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
|
||||||
|
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> type
|
||||||
|
IrTypeOperator.SAFE_CAST -> type.makeNullable()
|
||||||
|
IrTypeOperator.INSTANCEOF,
|
||||||
|
IrTypeOperator.NOT_INSTANCEOF -> context.builtIns.booleanType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall {
|
||||||
|
val typeOperand = substituteType(expression.typeOperand)!!
|
||||||
|
val returnType = getTypeOperatorReturnType(expression.operator, typeOperand)
|
||||||
|
return IrTypeOperatorCallImpl(
|
||||||
|
startOffset = expression.startOffset,
|
||||||
|
endOffset = expression.endOffset,
|
||||||
|
type = returnType,
|
||||||
|
operator = expression.operator,
|
||||||
|
typeOperand = typeOperand,
|
||||||
|
argument = expression.argument.transform(this, null)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitReturn(expression: IrReturn): IrReturn =
|
||||||
|
IrReturnImpl(
|
||||||
|
startOffset = expression.startOffset,
|
||||||
|
endOffset = expression.endOffset,
|
||||||
|
type = substituteType(expression.type)!!,
|
||||||
|
returnTargetDescriptor = mapReturnTarget(expression.returnTarget),
|
||||||
|
value = expression.value.transform(this, null)
|
||||||
|
)
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitBlock(expression: IrBlock): IrBlock {
|
||||||
|
return if (expression is IrReturnableBlock) {
|
||||||
|
IrReturnableBlockImpl(
|
||||||
|
startOffset = expression.startOffset,
|
||||||
|
endOffset = expression.endOffset,
|
||||||
|
type = expression.type,
|
||||||
|
descriptor = expression.descriptor,
|
||||||
|
origin = mapStatementOrigin(expression.origin),
|
||||||
|
statements = expression.statements.map { it.transform(this, null) },
|
||||||
|
sourceFileName = expression.sourceFileName
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
super.visitBlock(expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitClassReference(expression: IrClassReference): IrClassReference {
|
||||||
|
val newExpressionType = substituteType(expression.type)!! // Substituted expression type.
|
||||||
|
val newDescriptorType = substituteType(expression.descriptor.defaultType)!! // Substituted type of referenced class.
|
||||||
|
val classDescriptor = newDescriptorType.constructor.declarationDescriptor!! // Get ClassifierDescriptor of the referenced class.
|
||||||
|
return IrClassReferenceImpl(
|
||||||
|
startOffset = expression.startOffset,
|
||||||
|
endOffset = expression.endOffset,
|
||||||
|
type = newExpressionType,
|
||||||
|
descriptor = classDescriptor,
|
||||||
|
classType = expression.classType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitGetClass(expression: IrGetClass): IrGetClass {
|
||||||
|
val type = substituteType(expression.type)!!
|
||||||
|
return IrGetClassImpl(
|
||||||
|
startOffset = expression.startOffset,
|
||||||
|
endOffset = expression.endOffset,
|
||||||
|
type = type,
|
||||||
|
argument = expression.argument.transform(this, null)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
|
||||||
|
return irLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun substituteType(oldType: KotlinType?): KotlinType? {
|
||||||
|
if (typeSubstitutor == null) return oldType
|
||||||
|
if (oldType == null) return oldType
|
||||||
|
return typeSubstitutor!!.substitute(oldType, Variance.INVARIANT) ?: oldType
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun IrMemberAccessExpression.substituteTypeArguments(original: IrMemberAccessExpression) {
|
||||||
|
for (index in 0 until original.typeArgumentsCount) {
|
||||||
|
val originalTypeArgument = original.getTypeArgument(index)
|
||||||
|
val newTypeArgument = substituteType(originalTypeArgument)!!
|
||||||
|
this.putTypeArgument(index, newTypeArgument)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>) {
|
||||||
|
descriptorSubstituteMap.forEach { t, u ->
|
||||||
|
globalSubstituteMap.put(t, SubstitutedDescriptor(targetDescriptor, u))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubstitutedDescriptor(val inlinedFunction: FunctionDescriptor, val descriptor: DeclarationDescriptor)
|
||||||
|
|
||||||
|
class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>)
|
||||||
|
: IrElementTransformerVoidWithContext() {
|
||||||
|
|
||||||
|
private val variableSubstituteMap = mutableMapOf<VariableDescriptor, VariableDescriptor>()
|
||||||
|
|
||||||
|
fun run(element: IrElement) {
|
||||||
|
collectVariables(element)
|
||||||
|
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 {
|
||||||
|
val oldExpression = super.visitCall(expression) as IrCall
|
||||||
|
|
||||||
|
val substitutedDescriptor = globalSubstituteMap[expression.descriptor.original]
|
||||||
|
?: return oldExpression
|
||||||
|
if (allScopes.any { it.scope.scopeOwner == substitutedDescriptor.inlinedFunction })
|
||||||
|
return oldExpression
|
||||||
|
return when (oldExpression) {
|
||||||
|
is IrCallImpl -> copyIrCallImpl(oldExpression, substitutedDescriptor)
|
||||||
|
is IrCallWithShallowCopy -> copyIrCallWithShallowCopy(oldExpression, substitutedDescriptor)
|
||||||
|
else -> oldExpression
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyIrCallImpl(oldExpression: IrCallImpl, substitutedDescriptor: SubstitutedDescriptor): IrCallImpl {
|
||||||
|
|
||||||
|
val oldDescriptor = oldExpression.descriptor
|
||||||
|
val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
|
||||||
|
|
||||||
|
if (newDescriptor == oldDescriptor)
|
||||||
|
return oldExpression
|
||||||
|
|
||||||
|
return IrCallImpl(
|
||||||
|
startOffset = oldExpression.startOffset,
|
||||||
|
endOffset = oldExpression.endOffset,
|
||||||
|
type = newDescriptor.returnType!!,
|
||||||
|
symbol = createFunctionSymbol(newDescriptor),
|
||||||
|
descriptor = newDescriptor,
|
||||||
|
typeArgumentsCount = oldExpression.typeArgumentsCount,
|
||||||
|
origin = oldExpression.origin,
|
||||||
|
superQualifierSymbol = createClassSymbolOrNull(oldExpression.superQualifier)
|
||||||
|
).apply {
|
||||||
|
copyTypeArgumentsFrom(oldExpression)
|
||||||
|
|
||||||
|
oldExpression.descriptor.valueParameters.forEach {
|
||||||
|
val valueArgument = oldExpression.getValueArgument(it)
|
||||||
|
putValueArgument(it.index, valueArgument)
|
||||||
|
}
|
||||||
|
extensionReceiver = oldExpression.extensionReceiver
|
||||||
|
dispatchReceiver = oldExpression.dispatchReceiver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun copyIrCallWithShallowCopy(oldExpression: IrCallWithShallowCopy, substitutedDescriptor: SubstitutedDescriptor): IrCall {
|
||||||
|
|
||||||
|
val oldDescriptor = oldExpression.descriptor
|
||||||
|
val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
|
||||||
|
|
||||||
|
if (newDescriptor == oldDescriptor)
|
||||||
|
return oldExpression
|
||||||
|
|
||||||
|
return oldExpression.shallowCopy(oldExpression.origin, createFunctionSymbol(newDescriptor), oldExpression.superQualifierSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+386
@@ -0,0 +1,386 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("FoldInitializerAndIfToElvis")
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.lower.inline
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||||
|
import org.jetbrains.kotlin.backend.common.ScopeWithIr
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
|
import org.jetbrains.kotlin.backend.common.reportWarning
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.propertyIfAccessor
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irCall
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irGet
|
||||||
|
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
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.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.impl.createValueSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
|
||||||
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
|
import org.jetbrains.kotlin.types.TypeConstructor
|
||||||
|
import org.jetbrains.kotlin.types.TypeProjection
|
||||||
|
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||||
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
typealias Context = JsIrBackendContext
|
||||||
|
|
||||||
|
// backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt
|
||||||
|
internal class FunctionInlining(val context: Context): IrElementTransformerVoidWithContext() {
|
||||||
|
|
||||||
|
// TODO private val deserializer = DeserializerDriver(context)
|
||||||
|
private val globalSubstituteMap = mutableMapOf<DeclarationDescriptor, SubstitutedDescriptor>()
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
fun inline(irModule: IrModuleFragment): IrElement {
|
||||||
|
val transformedModule = irModule.accept(this, null)
|
||||||
|
DescriptorSubstitutorForExternalScope(globalSubstituteMap).run(transformedModule) // Transform calls to object that might be returned from inline function call.
|
||||||
|
return transformedModule
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
|
||||||
|
val irCall = super.visitCall(expression) as IrCall
|
||||||
|
val functionDescriptor = irCall.descriptor
|
||||||
|
if (!functionDescriptor.needsInlining) return irCall // This call does not need inlining.
|
||||||
|
|
||||||
|
val functionDeclaration = getFunctionDeclaration(irCall) // Get declaration of the function to be inlined.
|
||||||
|
if (functionDeclaration == null) { // We failed to get the declaration.
|
||||||
|
val message = "Inliner failed to obtain function declaration: " +
|
||||||
|
functionDescriptor.fqNameSafe.toString()
|
||||||
|
context.reportWarning(message, currentFile, irCall) // Report warning.
|
||||||
|
return irCall
|
||||||
|
}
|
||||||
|
|
||||||
|
functionDeclaration.transformChildrenVoid(this) // Process recursive inline.
|
||||||
|
val inliner = Inliner(
|
||||||
|
globalSubstituteMap,
|
||||||
|
functionDeclaration,
|
||||||
|
currentScope!!,
|
||||||
|
context
|
||||||
|
) // Create inliner for this scope.
|
||||||
|
return inliner.inline(irCall ) // Return newly created IrInlineBody instead of IrCall.
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun getFunctionDeclaration(irCall: IrCall): IrFunction? {
|
||||||
|
|
||||||
|
val functionDescriptor = irCall.descriptor
|
||||||
|
val originalDescriptor = functionDescriptor.resolveFakeOverride().original
|
||||||
|
val functionDeclaration =
|
||||||
|
context.originalModuleIndex.functions[originalDescriptor] // ?: // If function is declared in the current module.
|
||||||
|
// TODO deserializer.deserializeInlineBody(originalDescriptor) // Function is declared in another module.
|
||||||
|
return functionDeclaration as IrFunction?
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement) = element.accept(this, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: should we keep this at all?
|
||||||
|
private val inlineConstructor = FqName("konan.internal.InlineConstructor")
|
||||||
|
private val FunctionDescriptor.isInlineConstructor get() = annotations.hasAnnotation(inlineConstructor)
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor, SubstitutedDescriptor>,
|
||||||
|
val functionDeclaration: IrFunction, // Function to substitute.
|
||||||
|
val currentScope: ScopeWithIr,
|
||||||
|
val context: Context
|
||||||
|
) {
|
||||||
|
|
||||||
|
val copyIrElement = DeepCopyIrTreeWithDescriptors(
|
||||||
|
functionDeclaration.descriptor,
|
||||||
|
currentScope.scope.scopeOwner,
|
||||||
|
context
|
||||||
|
) // Create DeepCopy for current scope.
|
||||||
|
val substituteMap = mutableMapOf<ValueDescriptor, IrExpression>()
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
fun inline(irCall: IrCall): IrReturnableBlockImpl { // Call to be substituted.
|
||||||
|
val inlineFunctionBody = inlineFunction(irCall, functionDeclaration)
|
||||||
|
copyIrElement.addCurrentSubstituteMap(globalSubstituteMap)
|
||||||
|
return inlineFunctionBody
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun inlineFunction(callee: IrCall, // Call to be substituted.
|
||||||
|
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.
|
||||||
|
typeSubstitutor = createTypeSubstitutor(callee) // Type parameters will be substituted with type arguments.
|
||||||
|
) as IrFunction
|
||||||
|
|
||||||
|
val irReturnableBlockSymbol = IrReturnableBlockSymbolImpl(copyFunctionDeclaration.descriptor.original)
|
||||||
|
|
||||||
|
val evaluationStatements = evaluateArguments(callee, copyFunctionDeclaration) // And list of evaluation statements.
|
||||||
|
|
||||||
|
val statements = (copyFunctionDeclaration.body as IrBlockBody).statements // IR statements from function copy.
|
||||||
|
|
||||||
|
val startOffset = caller.startOffset
|
||||||
|
val endOffset = caller.endOffset
|
||||||
|
val descriptor = caller.descriptor.original
|
||||||
|
if (descriptor.isInlineConstructor) {
|
||||||
|
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
|
||||||
|
val irBuilder = context.createIrBuilder(irReturnableBlockSymbol, startOffset, endOffset)
|
||||||
|
irBuilder.run {
|
||||||
|
val constructorDescriptor = delegatingConstructorCall.descriptor.original
|
||||||
|
val constructorCall = irCall(delegatingConstructorCall.symbol,
|
||||||
|
constructorDescriptor.typeParameters.associate { it to delegatingConstructorCall.getTypeArgument(it)!! }).apply {
|
||||||
|
constructorDescriptor.valueParameters.forEach { putValueArgument(it, delegatingConstructorCall.getValueArgument(it)) }
|
||||||
|
}
|
||||||
|
val oldThis = delegatingConstructorCall.descriptor.constructedClass.thisAsReceiverParameter
|
||||||
|
val newThis = currentScope.scope.createTemporaryVariable(
|
||||||
|
irExpression = constructorCall,
|
||||||
|
nameHint = delegatingConstructorCall.descriptor.fqNameSafe.toString() + ".this"
|
||||||
|
)
|
||||||
|
statements[0] = newThis
|
||||||
|
substituteMap[oldThis] = irGet(newThis.symbol)
|
||||||
|
statements.add(irReturn(irGet(newThis.symbol)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val returnType = copyFunctionDeclaration.descriptor.returnType!! // Substituted return type.
|
||||||
|
val sourceFileName = context.originalModuleIndex.declarationToFile[caller.descriptor.original] ?: ""
|
||||||
|
val inlineFunctionBody = IrReturnableBlockImpl( // Create new IR element to replace "call".
|
||||||
|
startOffset = startOffset,
|
||||||
|
endOffset = endOffset,
|
||||||
|
type = returnType,
|
||||||
|
symbol = irReturnableBlockSymbol,
|
||||||
|
origin = null,
|
||||||
|
statements = statements,
|
||||||
|
sourceFileName = sourceFileName
|
||||||
|
)
|
||||||
|
|
||||||
|
val transformer = ParameterSubstitutor()
|
||||||
|
inlineFunctionBody.transformChildrenVoid(transformer) // Replace value parameters with arguments.
|
||||||
|
inlineFunctionBody.statements.addAll(0, evaluationStatements) // Insert evaluation statements.
|
||||||
|
return inlineFunctionBody // Replace call site with InlineFunctionBody.
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private inner class ParameterSubstitutor: IrElementTransformerVoid() {
|
||||||
|
|
||||||
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
|
val newExpression = super.visitGetValue(expression) as IrGetValue
|
||||||
|
val descriptor = newExpression.descriptor
|
||||||
|
val argument = substituteMap[descriptor] // Find expression to replace this parameter.
|
||||||
|
if (argument == null) return newExpression // If there is no such expression - do nothing.
|
||||||
|
|
||||||
|
argument.transformChildrenVoid(this) // Default argument can contain subjects for substitution.
|
||||||
|
return copyIrElement.copy( // Make copy of argument expression.
|
||||||
|
irElement = argument,
|
||||||
|
typeSubstitutor = null
|
||||||
|
) as IrExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
|
||||||
|
if (!isLambdaCall(expression)) return super.visitCall(expression) // If it is not lambda call - return.
|
||||||
|
|
||||||
|
val dispatchReceiver = expression.dispatchReceiver as IrGetValue // Here we can have only GetValue as dispatch receiver.
|
||||||
|
val functionArgument = substituteMap[dispatchReceiver.descriptor] // Try to find lambda representation. // TODO original?
|
||||||
|
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
|
||||||
|
if (dispatchDescriptor is ValueParameterDescriptor &&
|
||||||
|
dispatchDescriptor.isNoinline) return super.visitCall(expression)
|
||||||
|
|
||||||
|
val functionDeclaration = getLambdaFunction(functionArgument)
|
||||||
|
val newExpression = inlineFunction(expression, functionDeclaration) // Inline the lambda. Lambda parameters will be substituted with lambda arguments.
|
||||||
|
return newExpression.transform(this, null) // Substitute lambda arguments with target function arguments.
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------//
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement) = element.accept(this, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--- Helpers -------------------------------------------------------------//
|
||||||
|
|
||||||
|
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? {
|
||||||
|
if (irCall.typeArgumentsCount == 0) return null
|
||||||
|
val descriptor = irCall.descriptor.resolveFakeOverride().original
|
||||||
|
val typeParameters = descriptor.propertyIfAccessor.typeParameters
|
||||||
|
val substitutionContext = mutableMapOf<TypeConstructor, TypeProjection>()
|
||||||
|
for (index in 0 until irCall.typeArgumentsCount) {
|
||||||
|
val typeArgument = irCall.getTypeArgument(index) ?: continue
|
||||||
|
substitutionContext[typeParameters[index].typeConstructor] = TypeProjectionImpl(typeArgument)
|
||||||
|
}
|
||||||
|
return TypeSubstitutor.create(substitutionContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private class ParameterToArgument(val parameterDescriptor: ParameterDescriptor,
|
||||||
|
val argumentExpression : IrExpression) {
|
||||||
|
|
||||||
|
val isInlinableLambda : Boolean
|
||||||
|
get() {
|
||||||
|
if (!InlineUtil.isInlineParameter(parameterDescriptor)) return false
|
||||||
|
if (argumentExpression !is IrBlock) return false // Lambda must be represented with IrBlock.
|
||||||
|
if (argumentExpression.origin != IrStatementOrigin.LAMBDA && // Origin must be LAMBDA or ANONYMOUS.
|
||||||
|
argumentExpression.origin != IrStatementOrigin.ANONYMOUS_FUNCTION) return false
|
||||||
|
|
||||||
|
val statements = argumentExpression.statements
|
||||||
|
val irFunction = statements[0] // Lambda function declaration.
|
||||||
|
val irCallableReference = statements[1] // Lambda callable reference.
|
||||||
|
if (irFunction !is IrFunction) return false // First statement of the block must be lambda declaration.
|
||||||
|
if (irCallableReference !is IrCallableReference) return false // Second statement of the block must be CallableReference.
|
||||||
|
return true // The expression represents lambda.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun buildParameterToArgument(irCall : IrCall, // Call site.
|
||||||
|
irFunction: IrFunction // Function to be called.
|
||||||
|
): List<ParameterToArgument> {
|
||||||
|
|
||||||
|
val parameterToArgument = mutableListOf<ParameterToArgument>() // Result list.
|
||||||
|
val functionDescriptor = irFunction.descriptor.original // Descriptor of function to be called.
|
||||||
|
|
||||||
|
if (irCall.dispatchReceiver != null && // Only if there are non null dispatch receivers both
|
||||||
|
functionDescriptor.dispatchReceiverParameter != null) // on call site and in function declaration.
|
||||||
|
parameterToArgument += ParameterToArgument(
|
||||||
|
parameterDescriptor = functionDescriptor.dispatchReceiverParameter!!,
|
||||||
|
argumentExpression = irCall.dispatchReceiver!!
|
||||||
|
)
|
||||||
|
|
||||||
|
val valueArguments =
|
||||||
|
irCall.descriptor.valueParameters.map { irCall.getValueArgument(it) }.toMutableList()
|
||||||
|
|
||||||
|
if (functionDescriptor.extensionReceiverParameter != null) {
|
||||||
|
parameterToArgument += ParameterToArgument(
|
||||||
|
parameterDescriptor = functionDescriptor.extensionReceiverParameter!!,
|
||||||
|
argumentExpression = if (irCall.extensionReceiver != null) {
|
||||||
|
irCall.extensionReceiver!!
|
||||||
|
} else {
|
||||||
|
// Special case: lambda with receiver is called as usual lambda:
|
||||||
|
valueArguments.removeAt(0)!!
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else if (irCall.extensionReceiver != null) {
|
||||||
|
// Special case: usual lambda is called as lambda with receiver:
|
||||||
|
valueArguments.add(0, irCall.extensionReceiver!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
val parametersWithDefaultToArgument = mutableListOf<ParameterToArgument>()
|
||||||
|
functionDescriptor.valueParameters.forEach { parameterDescriptor -> // Iterate value parameter descriptors.
|
||||||
|
val argument = valueArguments[parameterDescriptor.index] // Get appropriate argument from call site.
|
||||||
|
when {
|
||||||
|
argument != null -> { // Argument is good enough.
|
||||||
|
parameterToArgument += ParameterToArgument( // Associate current parameter with the argument.
|
||||||
|
parameterDescriptor = parameterDescriptor,
|
||||||
|
argumentExpression = argument
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
parameterDescriptor.hasDefaultValue() -> { // There is no argument - try default value.
|
||||||
|
val defaultArgument = irFunction.getDefault(parameterDescriptor)!!
|
||||||
|
parametersWithDefaultToArgument += ParameterToArgument(
|
||||||
|
parameterDescriptor = parameterDescriptor,
|
||||||
|
argumentExpression = defaultArgument.expression
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
parameterDescriptor.varargElementType != null -> {
|
||||||
|
val emptyArray = IrVarargImpl(
|
||||||
|
startOffset = irCall.startOffset,
|
||||||
|
endOffset = irCall.endOffset,
|
||||||
|
type = parameterDescriptor.type,
|
||||||
|
varargElementType = parameterDescriptor.varargElementType!!
|
||||||
|
)
|
||||||
|
parameterToArgument += ParameterToArgument(
|
||||||
|
parameterDescriptor = parameterDescriptor,
|
||||||
|
argumentExpression = emptyArray
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
val message = "Incomplete expression: call to $functionDescriptor " +
|
||||||
|
"has no argument at index ${parameterDescriptor.index}"
|
||||||
|
throw Error(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parameterToArgument + parametersWithDefaultToArgument // All arguments except default are evaluated at callsite,
|
||||||
|
// but default arguments are evaluated inside callee.
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
private fun evaluateArguments(irCall : IrCall, // Call site.
|
||||||
|
functionDeclaration: IrFunction // Function to be called.
|
||||||
|
): List<IrStatement> {
|
||||||
|
|
||||||
|
val parameterToArgumentOld = buildParameterToArgument(irCall, functionDeclaration) // Create map parameter_descriptor -> original_argument_expression.
|
||||||
|
val evaluationStatements = mutableListOf<IrStatement>() // List of evaluation statements.
|
||||||
|
val substitutor = ParameterSubstitutor()
|
||||||
|
parameterToArgumentOld.forEach {
|
||||||
|
val parameterDescriptor = it.parameterDescriptor
|
||||||
|
|
||||||
|
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.
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
|
||||||
|
val newVariable = currentScope.scope.createTemporaryVariable( // Create new variable and init it with the parameter expression.
|
||||||
|
irExpression = it.argumentExpression.transform(substitutor, data = null), // Arguments may reference the previous ones - substitute them.
|
||||||
|
nameHint = functionDeclaration.descriptor.name.toString(),
|
||||||
|
isMutable = false)
|
||||||
|
|
||||||
|
evaluationStatements.add(newVariable) // Add initialization of the new variable in statement list.
|
||||||
|
val getVal = IrGetValueImpl( // Create new expression, representing access the new variable.
|
||||||
|
startOffset = currentScope.irElement.startOffset,
|
||||||
|
endOffset = currentScope.irElement.endOffset,
|
||||||
|
symbol = createValueSymbol(newVariable.descriptor)
|
||||||
|
)
|
||||||
|
substituteMap[parameterDescriptor] = getVal // Parameter will be replaced with the new variable.
|
||||||
|
}
|
||||||
|
return evaluationStatements
|
||||||
|
}
|
||||||
|
}
|
||||||
+417
@@ -0,0 +1,417 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.lower.inline
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.pop
|
||||||
|
import org.jetbrains.kotlin.backend.common.push
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.inline.addChildren
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrReturnTargetSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||||
|
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
|
|
||||||
|
// backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUnboundSymbolReplacer.kt
|
||||||
|
@Deprecated("")
|
||||||
|
internal fun IrModuleFragment.replaceUnboundSymbols(context: JsIrBackendContext) {
|
||||||
|
val collector = DeclarationSymbolCollector()
|
||||||
|
with(collector) {
|
||||||
|
with(irBuiltins) {
|
||||||
|
for (op in arrayOf(eqeqeqFun, eqeqFun, throwNpeFun, booleanNotFun, noWhenBranchMatchedExceptionFun) +
|
||||||
|
lessFunByOperandType.values +
|
||||||
|
lessOrEqualFunByOperandType.values +
|
||||||
|
greaterOrEqualFunByOperandType.values +
|
||||||
|
greaterFunByOperandType.values +
|
||||||
|
ieee754equalsFunByOperandType.values) {
|
||||||
|
register(op.symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.acceptVoid(collector)
|
||||||
|
|
||||||
|
val symbolTable = context.symbolTable
|
||||||
|
|
||||||
|
this.transformChildrenVoid(
|
||||||
|
IrUnboundSymbolReplacer(
|
||||||
|
symbolTable,
|
||||||
|
collector.descriptorToSymbol
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Generate missing external stubs:
|
||||||
|
// TODO: ModuleGenerator::generateUnboundSymbolsAsDependencies(IRModuleFragment) is private function :/
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
ExternalDependenciesGenerator(symbolTable = context.symbolTable, irBuiltIns = context.irBuiltIns).generateUnboundSymbolsAsDependencies(this)
|
||||||
|
|
||||||
|
// Merge duplicated module and package declarations:
|
||||||
|
this.acceptVoid(object : IrElementVisitorVoid {
|
||||||
|
override fun visitElement(element: IrElement) {}
|
||||||
|
|
||||||
|
override fun visitModuleFragment(declaration: IrModuleFragment) {
|
||||||
|
declaration.dependencyModules.forEach { it.acceptVoid(this) }
|
||||||
|
|
||||||
|
val dependencyModules = declaration.dependencyModules.toSet().groupBy { it.descriptor }.map { (_, fragments) ->
|
||||||
|
fragments.reduce { firstModule, nextModule ->
|
||||||
|
firstModule.apply {
|
||||||
|
mergeFrom(nextModule)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declaration.dependencyModules.clear()
|
||||||
|
declaration.dependencyModules.addAll(dependencyModules)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrModuleFragment.mergeFrom(other: IrModuleFragment): Unit {
|
||||||
|
assert(this.files.isEmpty())
|
||||||
|
assert(other.files.isEmpty())
|
||||||
|
|
||||||
|
val thisPackages = this.externalPackageFragments.groupBy { it.packageFragmentDescriptor }
|
||||||
|
other.externalPackageFragments.forEach {
|
||||||
|
val thisPackage = thisPackages[it.packageFragmentDescriptor]?.toSet()?.single()
|
||||||
|
if (thisPackage == null) {
|
||||||
|
this.externalPackageFragments.add(it)
|
||||||
|
} else {
|
||||||
|
thisPackage.addChildren(it.declarations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DeclarationSymbolCollector : IrElementVisitorVoid {
|
||||||
|
|
||||||
|
val descriptorToSymbol = mutableMapOf<DeclarationDescriptor, IrSymbol>()
|
||||||
|
|
||||||
|
fun register(symbol: IrSymbol) {
|
||||||
|
descriptorToSymbol[symbol.descriptor] = symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
|
|
||||||
|
if (element is IrSymbolOwner && element !is IrAnonymousInitializer) {
|
||||||
|
register(element.symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IrUnboundSymbolReplacer(
|
||||||
|
val symbolTable: SymbolTable,
|
||||||
|
val descriptorToSymbol: Map<DeclarationDescriptor, IrSymbol>
|
||||||
|
) : IrElementTransformerVoid() {
|
||||||
|
|
||||||
|
private val localDescriptorToSymbol = mutableMapOf<DeclarationDescriptor, MutableList<IrSymbol>>()
|
||||||
|
|
||||||
|
private inline fun <R> withLocal(symbol: IrSymbol?, block: () -> R): R {
|
||||||
|
if (symbol == null) return block()
|
||||||
|
|
||||||
|
val locals = localDescriptorToSymbol.getOrPut(symbol.descriptor) { mutableListOf() }
|
||||||
|
locals.add(symbol)
|
||||||
|
return try {
|
||||||
|
block()
|
||||||
|
} finally {
|
||||||
|
locals.removeAt(locals.lastIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <reified D : DeclarationDescriptor, reified S : IrSymbol> S.replace(
|
||||||
|
referenceSymbol: (SymbolTable, D) -> S): S? {
|
||||||
|
|
||||||
|
if (this.isBound) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
localDescriptorToSymbol[this.descriptor]?.lastOrNull()?.let {
|
||||||
|
return it as S
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
descriptorToSymbol[this.descriptor]?.let {
|
||||||
|
return it as S
|
||||||
|
}
|
||||||
|
|
||||||
|
return referenceSymbol(symbolTable, this.descriptor as D)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <reified D : DeclarationDescriptor, reified S : IrSymbol> S.replaceOrSame(
|
||||||
|
referenceSymbol: (SymbolTable, D) -> S): S = this.replace(referenceSymbol) ?: this
|
||||||
|
|
||||||
|
private inline fun <reified S : IrSymbol> S.replaceLocal(): S? {
|
||||||
|
return if (this.isBound) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
(localDescriptorToSymbol[this.descriptor]?.lastOrNull() ?: descriptorToSymbol[this.descriptor]) as S
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
|
val symbol = expression.symbol.replaceLocal() ?: return super.visitGetValue(expression)
|
||||||
|
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
return with(expression) {
|
||||||
|
IrGetValueImpl(startOffset, endOffset, symbol, origin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSetVariable(expression: IrSetVariable): IrExpression {
|
||||||
|
val symbol = expression.symbol.replaceLocal() ?: return super.visitSetVariable(expression)
|
||||||
|
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
return with(expression) {
|
||||||
|
IrSetVariableImpl(startOffset, endOffset, symbol, value, origin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
|
||||||
|
val symbol = expression.symbol.replace(SymbolTable::referenceClass) ?:
|
||||||
|
return super.visitGetObjectValue(expression)
|
||||||
|
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
return with(expression) {
|
||||||
|
IrGetObjectValueImpl(startOffset, endOffset, type, symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitGetEnumValue(expression: IrGetEnumValue): IrExpression {
|
||||||
|
val symbol = expression.symbol.replace(SymbolTable::referenceEnumEntry) ?:
|
||||||
|
return super.visitGetEnumValue(expression)
|
||||||
|
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
return with(expression) {
|
||||||
|
IrGetEnumValueImpl(startOffset, endOffset, type, symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitClassReference(expression: IrClassReference): IrExpression {
|
||||||
|
val symbol = expression.symbol.replace(SymbolTable::referenceClassifier)
|
||||||
|
?: return super.visitClassReference(expression)
|
||||||
|
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
return with(expression) {
|
||||||
|
IrClassReferenceImpl(startOffset, endOffset, type, symbol, symbol.descriptor.defaultType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitClass(declaration: IrClass): IrStatement {
|
||||||
|
declaration.superClasses.forEachIndexed { index, symbol ->
|
||||||
|
val newSymbol = symbol.replace(SymbolTable::referenceClass)
|
||||||
|
if (newSymbol != null) {
|
||||||
|
declaration.superClasses[index] = newSymbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
withLocal(declaration.thisReceiver?.symbol) {
|
||||||
|
return super.visitClass(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitGetField(expression: IrGetField): IrExpression {
|
||||||
|
val symbol = expression.symbol.replaceOrSame(SymbolTable::referenceField)
|
||||||
|
|
||||||
|
val superQualifierSymbol = expression.superQualifierSymbol?.replaceOrSame(SymbolTable::referenceClass)
|
||||||
|
|
||||||
|
if (symbol == expression.symbol && superQualifierSymbol == expression.superQualifierSymbol) {
|
||||||
|
return super.visitGetField(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
return with(expression) {
|
||||||
|
IrGetFieldImpl(startOffset, endOffset, symbol, receiver, origin, superQualifierSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSetField(expression: IrSetField): IrExpression {
|
||||||
|
val symbol = expression.symbol.replaceOrSame(SymbolTable::referenceField)
|
||||||
|
|
||||||
|
val superQualifierSymbol = expression.superQualifierSymbol?.replaceOrSame(SymbolTable::referenceClass)
|
||||||
|
|
||||||
|
if (symbol == expression.symbol && superQualifierSymbol == expression.superQualifierSymbol) {
|
||||||
|
return super.visitSetField(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
return with(expression) {
|
||||||
|
IrSetFieldImpl(startOffset, endOffset, symbol, receiver, value, origin, superQualifierSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
val symbol = expression.symbol.replace(SymbolTable::referenceFunction) ?: expression.symbol
|
||||||
|
|
||||||
|
val superQualifierSymbol = expression.superQualifierSymbol?.replaceOrSame(SymbolTable::referenceClass)
|
||||||
|
|
||||||
|
if (symbol == expression.symbol && superQualifierSymbol == expression.superQualifierSymbol) {
|
||||||
|
return super.visitCall(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
expression.transformChildrenVoid()
|
||||||
|
return with(expression) {
|
||||||
|
IrCallImpl(startOffset, endOffset, symbol, descriptor,
|
||||||
|
getTypeArgumentsMap(),
|
||||||
|
origin, superQualifierSymbol).also {
|
||||||
|
|
||||||
|
it.copyArgumentsFrom(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrMemberAccessExpression.getTypeArgumentsMap() =
|
||||||
|
descriptor.original.typeParameters.associate { it to getTypeArgumentOrDefault(it) }
|
||||||
|
|
||||||
|
private fun IrMemberAccessExpressionBase.copyArgumentsFrom(original: IrMemberAccessExpression) {
|
||||||
|
dispatchReceiver = original.dispatchReceiver
|
||||||
|
extensionReceiver = original.extensionReceiver
|
||||||
|
original.descriptor.valueParameters.forEachIndexed { index, _ ->
|
||||||
|
putValueArgument(index, original.getValueArgument(index))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression {
|
||||||
|
val symbol = expression.symbol.replace(SymbolTable::referenceConstructor) ?:
|
||||||
|
return super.visitEnumConstructorCall(expression)
|
||||||
|
|
||||||
|
return with(expression) {
|
||||||
|
IrEnumConstructorCallImpl(startOffset, endOffset, symbol, null).also {
|
||||||
|
it.copyArgumentsFrom(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||||
|
val symbol = expression.symbol.replace(SymbolTable::referenceConstructor) ?:
|
||||||
|
return super.visitDelegatingConstructorCall(expression)
|
||||||
|
|
||||||
|
expression.transformChildrenVoid()
|
||||||
|
return with(expression) {
|
||||||
|
IrDelegatingConstructorCallImpl(startOffset, endOffset, symbol, descriptor, getTypeArgumentsMap()).also {
|
||||||
|
it.copyArgumentsFrom(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||||
|
val symbol = expression.symbol.replace(SymbolTable::referenceFunction) ?:
|
||||||
|
return super.visitFunctionReference(expression)
|
||||||
|
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
return with(expression) {
|
||||||
|
IrFunctionReferenceImpl(startOffset, endOffset, type, symbol, descriptor, getTypeArgumentsMap()).also {
|
||||||
|
it.copyArgumentsFrom(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
|
||||||
|
val field = expression.field?.replaceOrSame(SymbolTable::referenceField)
|
||||||
|
val getter = expression.getter?.replace(SymbolTable::referenceFunction) ?: expression.getter
|
||||||
|
val setter = expression.setter?.replace(SymbolTable::referenceFunction) ?: expression.setter
|
||||||
|
|
||||||
|
if (field == expression.field && getter == expression.getter && setter == expression.setter) {
|
||||||
|
return super.visitPropertyReference(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
return with(expression) {
|
||||||
|
IrPropertyReferenceImpl(startOffset, endOffset, type, descriptor,
|
||||||
|
field,
|
||||||
|
getter,
|
||||||
|
setter,
|
||||||
|
getTypeArgumentsMap(), origin).also {
|
||||||
|
|
||||||
|
it.copyArgumentsFrom(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference): IrExpression {
|
||||||
|
val delegate = expression.delegate.replaceOrSame(SymbolTable::referenceVariable)
|
||||||
|
val getter = expression.getter.replace(SymbolTable::referenceFunction) ?: expression.getter
|
||||||
|
val setter = expression.setter?.replace(SymbolTable::referenceFunction) ?: expression.setter
|
||||||
|
|
||||||
|
if (delegate == expression.delegate && getter == expression.getter && setter == expression.setter) {
|
||||||
|
return super.visitLocalDelegatedPropertyReference(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
return with(expression) {
|
||||||
|
IrLocalDelegatedPropertyReferenceImpl(startOffset, endOffset, type, descriptor,
|
||||||
|
delegate, getter, setter, origin).also {
|
||||||
|
|
||||||
|
it.copyArgumentsFrom(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val returnTargetStack = mutableListOf<IrReturnTargetSymbol>()
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||||
|
returnTargetStack.push(declaration.symbol)
|
||||||
|
try {
|
||||||
|
if (declaration is IrSimpleFunction) {
|
||||||
|
declaration.overriddenSymbols.forEachIndexed { index, symbol ->
|
||||||
|
val newSymbol = symbol.replace(SymbolTable::referenceSimpleFunction)
|
||||||
|
if (newSymbol != null) {
|
||||||
|
declaration.overriddenSymbols[index] = newSymbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
withLocal(declaration.dispatchReceiverParameter?.symbol) {
|
||||||
|
withLocal(declaration.extensionReceiverParameter?.symbol) {
|
||||||
|
return super.visitFunction(declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
returnTargetStack.pop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBlock(expression: IrBlock): IrExpression {
|
||||||
|
if (expression is IrReturnableBlock) {
|
||||||
|
returnTargetStack.push(expression.symbol)
|
||||||
|
try {
|
||||||
|
return super.visitBlock(expression)
|
||||||
|
} finally {
|
||||||
|
returnTargetStack.pop()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return super.visitBlock(expression)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||||
|
if (expression.returnTargetSymbol.isBound) {
|
||||||
|
return super.visitReturn(expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
val returnTargetSymbol = returnTargetStack.last { it.descriptor == expression.returnTarget }
|
||||||
|
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
|
||||||
|
return with(expression) {
|
||||||
|
IrReturnImpl(startOffset, endOffset, type, returnTargetSymbol, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression {
|
||||||
|
val classSymbol = expression.classSymbol.replace(SymbolTable::referenceClass) ?:
|
||||||
|
return super.visitInstanceInitializerCall(expression)
|
||||||
|
|
||||||
|
expression.transformChildrenVoid(this)
|
||||||
|
|
||||||
|
return with(expression) {
|
||||||
|
IrInstanceInitializerCallImpl(startOffset, endOffset, classSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.lower.inline
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
|
||||||
|
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
|
||||||
|
// backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/util/IrUtils2.kt
|
||||||
|
fun IrSimpleFunction.setOverrides(symbolTable: SymbolTable) {
|
||||||
|
assert(this.overriddenSymbols.isEmpty())
|
||||||
|
|
||||||
|
this.descriptor.overriddenDescriptors.mapTo(this.overriddenSymbols) {
|
||||||
|
symbolTable.referenceSimpleFunction(it.original)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.typeParameters.forEach { it.setSupers(symbolTable) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrTypeParameter.setSupers(symbolTable: SymbolTable) {
|
||||||
|
assert(this.superClassifiers.isEmpty())
|
||||||
|
this.descriptor.upperBounds.mapNotNullTo(this.superClassifiers) {
|
||||||
|
it.constructor.declarationDescriptor?.let {
|
||||||
|
if (it is TypeParameterDescriptor) {
|
||||||
|
IrTypeParameterSymbolImpl(it) // Workaround for deserialized inline functions
|
||||||
|
} else {
|
||||||
|
symbolTable.referenceClassifier(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrDeclarationContainer.addChildren(declarations: List<IrDeclaration>) {
|
||||||
|
declarations.forEach { this.addChild(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrDeclarationContainer.addChild(declaration: IrDeclaration) {
|
||||||
|
this.declarations += declaration
|
||||||
|
declaration.accept(SetDeclarationsParentVisitor, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
object SetDeclarationsParentVisitor : IrElementVisitor<Unit, IrDeclarationParent> {
|
||||||
|
override fun visitElement(element: IrElement, data: IrDeclarationParent) {
|
||||||
|
if (element !is IrDeclarationParent) {
|
||||||
|
element.acceptChildren(this, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclarationParent) {
|
||||||
|
declaration.parent = data
|
||||||
|
super.visitDeclaration(declaration, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.lower.inline
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
|
||||||
|
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
|
// backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/LegacyDescriptorUtils.kt
|
||||||
|
/**
|
||||||
|
* Implementation of given method.
|
||||||
|
*
|
||||||
|
* TODO: this method is actually a part of resolve and probably duplicates another one
|
||||||
|
*/
|
||||||
|
internal fun <T : CallableMemberDescriptor> T.resolveFakeOverride(): T {
|
||||||
|
if (this.kind.isReal) {
|
||||||
|
return this
|
||||||
|
} else {
|
||||||
|
val overridden = OverridingUtil.getOverriddenDeclarations(this)
|
||||||
|
val filtered = OverridingUtil.filterOutOverridden(overridden)
|
||||||
|
// TODO: is it correct to take first?
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return filtered.first { it.modality != Modality.ABSTRACT } as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val KotlinType.isKFunctionType: Boolean
|
||||||
|
get() {
|
||||||
|
val kind = constructor.declarationDescriptor?.getFunctionalClassKind()
|
||||||
|
return kind == FunctionClassDescriptor.Kind.KFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val FunctionDescriptor.isFunctionInvoke: Boolean
|
||||||
|
get() {
|
||||||
|
val dispatchReceiver = dispatchReceiverParameter ?: return false
|
||||||
|
assert(!dispatchReceiver.type.isKFunctionType)
|
||||||
|
|
||||||
|
return dispatchReceiver.type.isFunctionType &&
|
||||||
|
this.isOperator && this.name == OperatorNameConventions.INVOKE
|
||||||
|
}
|
||||||
|
|
||||||
|
// It is possible to declare "external inline fun",
|
||||||
|
// but it doesn't have much sense for native,
|
||||||
|
// since externals don't have IR bodies.
|
||||||
|
// Enforce inlining of constructors annotated with @InlineConstructor.
|
||||||
|
// TODO: should we keep this?
|
||||||
|
private val inlineConstructor = FqName("konan.internal.InlineConstructor")
|
||||||
|
|
||||||
|
internal val FunctionDescriptor.needsInlining: Boolean
|
||||||
|
get() {
|
||||||
|
val inlineConstructor = annotations.hasAnnotation(inlineConstructor)
|
||||||
|
if (inlineConstructor) return true
|
||||||
|
return (this.isInline && !this.isExternal)
|
||||||
|
}
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.lower.inline
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
|
|
||||||
|
// backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/ModuleIndex.kt
|
||||||
|
class ModuleIndex(val module: IrModuleFragment) {
|
||||||
|
|
||||||
|
var currentFile: IrFile? = null
|
||||||
|
/**
|
||||||
|
* Contains all classes declared in [module]
|
||||||
|
*/
|
||||||
|
val classes: Map<ClassDescriptor, IrClass>
|
||||||
|
|
||||||
|
val enumEntries: Map<ClassDescriptor, IrEnumEntry>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains all functions declared in [module]
|
||||||
|
*/
|
||||||
|
val functions = mutableMapOf<FunctionDescriptor, IrFunction>()
|
||||||
|
val declarationToFile = mutableMapOf<DeclarationDescriptor, String>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
val map = mutableMapOf<ClassDescriptor, IrClass>()
|
||||||
|
enumEntries = mutableMapOf()
|
||||||
|
|
||||||
|
module.acceptVoid(object : IrElementVisitorVoid {
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFile(declaration: IrFile) {
|
||||||
|
currentFile = declaration
|
||||||
|
super.visitFile(declaration)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitClass(declaration: IrClass) {
|
||||||
|
super.visitClass(declaration)
|
||||||
|
|
||||||
|
map[declaration.descriptor] = declaration
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitEnumEntry(declaration: IrEnumEntry) {
|
||||||
|
super.visitEnumEntry(declaration)
|
||||||
|
|
||||||
|
enumEntries[declaration.descriptor] = declaration
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction) {
|
||||||
|
super.visitFunction(declaration)
|
||||||
|
functions[declaration.descriptor] = declaration
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDeclaration(declaration: IrDeclaration) {
|
||||||
|
super.visitDeclaration(declaration)
|
||||||
|
declarationToFile[declaration.descriptor] = currentFile!!.name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
classes = map
|
||||||
|
}
|
||||||
|
}
|
||||||
+128
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.lower.inline
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.getTypeArgumentOrDefault
|
||||||
|
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.*
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
|
||||||
|
// backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/irasdescriptors/NewIrUtils.kt
|
||||||
|
fun IrModuleFragment.referenceAllTypeExternalClassifiers(symbolTable: SymbolTable) {
|
||||||
|
val moduleDescriptor = this.descriptor
|
||||||
|
|
||||||
|
fun KotlinType.referenceAllClassifiers() {
|
||||||
|
TypeUtils.getClassDescriptor(this)?.let {
|
||||||
|
if (!ErrorUtils.isError(it) && it.module != moduleDescriptor) {
|
||||||
|
if (it.kind == ClassKind.ENUM_ENTRY) {
|
||||||
|
symbolTable.referenceEnumEntry(it)
|
||||||
|
} else {
|
||||||
|
symbolTable.referenceClass(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.constructor.supertypes.forEach {
|
||||||
|
it.referenceAllClassifiers()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val visitor = object : IrElementVisitorVoid {
|
||||||
|
override fun visitElement(element: IrElement) {
|
||||||
|
element.acceptChildrenVoid(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitValueParameter(declaration: IrValueParameter) {
|
||||||
|
super.visitValueParameter(declaration)
|
||||||
|
declaration.type.referenceAllClassifiers()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitVariable(declaration: IrVariable) {
|
||||||
|
super.visitVariable(declaration)
|
||||||
|
declaration.type.referenceAllClassifiers()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitExpression(expression: IrExpression) {
|
||||||
|
super.visitExpression(expression)
|
||||||
|
expression.type.referenceAllClassifiers()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDeclaration(declaration: IrDeclaration) {
|
||||||
|
super.visitDeclaration(declaration)
|
||||||
|
declaration.descriptor.annotations.getAllAnnotations().forEach {
|
||||||
|
handleClassReferences(it.annotation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleClassReferences(annotation: AnnotationDescriptor) {
|
||||||
|
annotation.allValueArguments.values.forEach {
|
||||||
|
it.accept(object : AnnotationArgumentVisitor<Unit, Nothing?> {
|
||||||
|
|
||||||
|
override fun visitKClassValue(p0: KClassValue?, p1: Nothing?) {
|
||||||
|
p0?.value?.referenceAllClassifiers()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitArrayValue(p0: ArrayValue?, p1: Nothing?) {
|
||||||
|
p0?.value?.forEach { it.accept(this, null) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitAnnotationValue(p0: AnnotationValue?, p1: Nothing?) {
|
||||||
|
p0?.let { handleClassReferences(p0.value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBooleanValue(p0: BooleanValue?, p1: Nothing?) {}
|
||||||
|
override fun visitShortValue(p0: ShortValue?, p1: Nothing?) {}
|
||||||
|
override fun visitByteValue(p0: ByteValue?, p1: Nothing?) {}
|
||||||
|
override fun visitNullValue(p0: NullValue?, p1: Nothing?) {}
|
||||||
|
override fun visitDoubleValue(p0: DoubleValue?, p1: Nothing?) {}
|
||||||
|
override fun visitLongValue(p0: LongValue, p1: Nothing?) {}
|
||||||
|
override fun visitCharValue(p0: CharValue?, p1: Nothing?) {}
|
||||||
|
override fun visitIntValue(p0: IntValue?, p1: Nothing?) {}
|
||||||
|
override fun visitErrorValue(p0: ErrorValue?, p1: Nothing?) {}
|
||||||
|
override fun visitFloatValue(p0: FloatValue?, p1: Nothing?) {}
|
||||||
|
override fun visitEnumValue(p0: EnumValue?, p1: Nothing?) {}
|
||||||
|
override fun visitStringValue(p0: StringValue?, p1: Nothing?) {}
|
||||||
|
override fun visitUByteValue(value: UByteValue?, data: Nothing?) {}
|
||||||
|
override fun visitUShortValue(value: UShortValue?, data: Nothing?) {}
|
||||||
|
override fun visitUIntValue(value: UIntValue?, data: Nothing?) {}
|
||||||
|
override fun visitULongValue(value: ULongValue?, data: Nothing?) {}
|
||||||
|
}, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction) {
|
||||||
|
super.visitFunction(declaration)
|
||||||
|
declaration.returnType.referenceAllClassifiers()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
|
||||||
|
super.visitFunctionAccess(expression)
|
||||||
|
expression.descriptor.original.typeParameters.forEach {
|
||||||
|
expression.getTypeArgumentOrDefault(it).referenceAllClassifiers()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.acceptVoid(visitor)
|
||||||
|
this.dependencyModules.forEach { module ->
|
||||||
|
module.externalPackageFragments.forEach {
|
||||||
|
it.acceptVoid(visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+179
@@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js.lower.inline
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.symbols.JsSymbolBuilder
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrDoWhileLoopImpl
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces returnable blocks and `return`'s with loops and `break`'s correspondingly.
|
||||||
|
*
|
||||||
|
* Converts returnable blocks into regular composite blocks when the only `return` is the last statement.
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* block {
|
||||||
|
* ...
|
||||||
|
* return@block e
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* is transformed into
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* {
|
||||||
|
* val result
|
||||||
|
* loop@ do {
|
||||||
|
* ...
|
||||||
|
* {
|
||||||
|
* result = e
|
||||||
|
* break@loop
|
||||||
|
* }
|
||||||
|
* ...
|
||||||
|
* } while (false)
|
||||||
|
* result
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* When the only `return` for the block is the last statement:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* block {
|
||||||
|
* ...
|
||||||
|
* return@block e
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* is transformed into
|
||||||
|
*
|
||||||
|
* {
|
||||||
|
* ...
|
||||||
|
* e
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class ReturnableBlockLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||||
|
override fun lower(irFile: IrFile) {
|
||||||
|
irFile.transform(ReturnableBlockTransformer(context), ReturnableBlockLoweringContext(irFile))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ReturnableBlockLoweringContext(val containingDeclaration: IrSymbolOwner) {
|
||||||
|
var labelCnt = 0
|
||||||
|
val returnMap = mutableMapOf<IrReturnableBlockSymbol, (IrReturn) -> IrExpression>()
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ReturnableBlockTransformer(
|
||||||
|
val context: JsIrBackendContext
|
||||||
|
) : IrElementTransformer<ReturnableBlockLoweringContext> {
|
||||||
|
|
||||||
|
override fun visitReturn(expression: IrReturn, data: ReturnableBlockLoweringContext): IrExpression {
|
||||||
|
expression.transformChildren(this, data)
|
||||||
|
return data.returnMap[expression.returnTargetSymbol]?.invoke(expression) ?: expression
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDeclaration(declaration: IrDeclaration, data: ReturnableBlockLoweringContext): IrStatement {
|
||||||
|
if (declaration is IrSymbolOwner) {
|
||||||
|
declaration.transformChildren(this, ReturnableBlockLoweringContext(declaration))
|
||||||
|
}
|
||||||
|
return super.visitDeclaration(declaration, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val constFalse = JsIrBuilder.buildBoolean(context.builtIns.booleanType, false)
|
||||||
|
|
||||||
|
override fun visitContainerExpression(expression: IrContainerExpression, data: ReturnableBlockLoweringContext): IrExpression {
|
||||||
|
if (expression !is IrReturnableBlock) return super.visitContainerExpression(expression, data)
|
||||||
|
|
||||||
|
val variable by lazy {
|
||||||
|
JsSymbolBuilder.buildTempVar(
|
||||||
|
data.containingDeclaration.symbol,
|
||||||
|
expression.type,
|
||||||
|
"tmp\$ret\$${data.labelCnt++}",
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val loop by lazy {
|
||||||
|
IrDoWhileLoopImpl(
|
||||||
|
expression.startOffset,
|
||||||
|
expression.endOffset,
|
||||||
|
context.builtIns.unitType,
|
||||||
|
expression.origin
|
||||||
|
).apply {
|
||||||
|
label = "l\$ret\$${data.labelCnt++}"
|
||||||
|
condition = constFalse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasReturned = false
|
||||||
|
|
||||||
|
data.returnMap[expression.symbol] = { returnExpression ->
|
||||||
|
hasReturned = true
|
||||||
|
|
||||||
|
IrCompositeImpl(
|
||||||
|
returnExpression.startOffset,
|
||||||
|
returnExpression.endOffset,
|
||||||
|
context.builtIns.unitType
|
||||||
|
).apply {
|
||||||
|
statements += JsIrBuilder.buildSetVariable(variable, returnExpression.value)
|
||||||
|
statements += JsIrBuilder.buildBreak(context.builtIns.unitType, loop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val newStatements = expression.statements.mapIndexed { i, s ->
|
||||||
|
if (i == expression.statements.lastIndex && s is IrReturn && s.returnTargetSymbol == expression.symbol) {
|
||||||
|
s.transformChildren(this, data)
|
||||||
|
if (!hasReturned) s.value else {
|
||||||
|
JsIrBuilder.buildSetVariable(variable, s.value)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.transform(this, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data.returnMap.remove(expression.symbol)
|
||||||
|
|
||||||
|
if (!hasReturned) {
|
||||||
|
return IrCompositeImpl(
|
||||||
|
expression.startOffset,
|
||||||
|
expression.endOffset,
|
||||||
|
expression.type,
|
||||||
|
expression.origin,
|
||||||
|
newStatements
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
loop.body = IrBlockImpl(
|
||||||
|
expression.startOffset,
|
||||||
|
expression.endOffset,
|
||||||
|
context.builtIns.unitType,
|
||||||
|
expression.origin,
|
||||||
|
newStatements
|
||||||
|
)
|
||||||
|
|
||||||
|
return IrCompositeImpl(
|
||||||
|
expression.startOffset,
|
||||||
|
expression.endOffset,
|
||||||
|
expression.type,
|
||||||
|
expression.origin
|
||||||
|
).apply {
|
||||||
|
statements += JsIrBuilder.buildVar(variable)
|
||||||
|
statements += loop
|
||||||
|
statements += JsIrBuilder.buildGetValue(variable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter
|
|||||||
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
|
||||||
@@ -67,7 +68,7 @@ object JsSymbolBuilder {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun buildTempVar(containingSymbol: IrFunctionSymbol, type: KotlinType, name: String? = null, mutable: Boolean = false) =
|
fun buildTempVar(containingSymbol: IrSymbol, type: KotlinType, name: String? = null, mutable: Boolean = false) =
|
||||||
buildTempVar(containingSymbol.descriptor, type, name, mutable)
|
buildTempVar(containingSymbol.descriptor, type, name, mutable)
|
||||||
|
|
||||||
fun buildTempVar(containingDeclaration: DeclarationDescriptor, type: KotlinType, name: String? = null, mutable: Boolean = false) =
|
fun buildTempVar(containingDeclaration: DeclarationDescriptor, type: KotlinType, name: String? = null, mutable: Boolean = false) =
|
||||||
|
|||||||
+1
-1
@@ -77,7 +77,7 @@ class SimpleNameGenerator : NameGenerator {
|
|||||||
is ConstructorDescriptor -> {
|
is ConstructorDescriptor -> {
|
||||||
nameBuilder.append(getNameForDescriptor(descriptor.constructedClass, context))
|
nameBuilder.append(getNameForDescriptor(descriptor.constructedClass, context))
|
||||||
}
|
}
|
||||||
is LocalVariableDescriptor -> {
|
is VariableDescriptor -> {
|
||||||
nameBuilder.append(descriptor.name.identifier)
|
nameBuilder.append(descriptor.name.identifier)
|
||||||
nameDeclarator = context.currentScope::declareFreshName
|
nameDeclarator = context.currentScope::declareFreshName
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -9,6 +9,10 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
@@ -50,4 +54,8 @@ fun createValueParameter(containingDeclaration: CallableDescriptor, index: Int,
|
|||||||
varargElementType = null,
|
varargElementType = null,
|
||||||
source = SourceElement.NO_SOURCE
|
source = SourceElement.NO_SOURCE
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
val CallableMemberDescriptor.propertyIfAccessor
|
||||||
|
get() = if (this is PropertyAccessorDescriptor)
|
||||||
|
this.correspondingProperty
|
||||||
|
else this
|
||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
class TestClass {
|
class TestClass {
|
||||||
companion object {
|
companion object {
|
||||||
inline operator fun <T> invoke(task: () -> T) = task()
|
inline operator fun <T> invoke(task: () -> T) = task()
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
class TestClass {
|
class TestClass {
|
||||||
inline operator fun <T> invoke(task: () -> T) = task()
|
inline operator fun <T> invoke(task: () -> T) = task()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// IGNORE_BACKEND: JS_IR
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// IGNORE_BACKEND: JS_IR
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
package test
|
package test
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
package test
|
package test
|
||||||
|
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// NO_CHECK_LAMBDA_INLINING
|
// NO_CHECK_LAMBDA_INLINING
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
package test
|
package test
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// SKIP_INLINE_CHECK_IN: bar$default
|
// SKIP_INLINE_CHECK_IN: bar$default
|
||||||
package test
|
package test
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// NO_CHECK_LAMBDA_INLINING
|
// NO_CHECK_LAMBDA_INLINING
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
package test
|
package test
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
package test
|
package test
|
||||||
|
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
// LANGUAGE_VERSION: 1.2
|
// LANGUAGE_VERSION: 1.2
|
||||||
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
// SKIP_INLINE_CHECK_IN: inlineFun$default
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// IGNORE_BACKEND: JS_IR
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
+2
@@ -1,3 +1,4 @@
|
|||||||
|
// IGNORE_BACKEND: JS_IR
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
@@ -80,4 +81,5 @@ fun box(): String {
|
|||||||
else "OK"
|
else "OK"
|
||||||
} ()
|
} ()
|
||||||
|
|
||||||
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
inline fun foo(f: () -> Unit) {
|
inline fun foo(f: () -> Unit) {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1114
|
// EXPECTED_REACHABLE_NODES: 1114
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1114
|
// EXPECTED_REACHABLE_NODES: 1114
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// IGNORE_BACKEND: JS_IR
|
||||||
// EXPECTED_REACHABLE_NODES: 1110
|
// EXPECTED_REACHABLE_NODES: 1110
|
||||||
var log = ""
|
var log = ""
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1110
|
// EXPECTED_REACHABLE_NODES: 1110
|
||||||
/*
|
/*
|
||||||
* Copy of JVM-backend test
|
* Copy of JVM-backend test
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// IGNORE_BACKEND: JS_IR
|
||||||
// EXPECTED_REACHABLE_NODES: 1124
|
// EXPECTED_REACHABLE_NODES: 1124
|
||||||
/*
|
/*
|
||||||
* Copy of JVM-backend test
|
* Copy of JVM-backend test
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// IGNORE_BACKEND: JS_IR
|
||||||
// EXPECTED_REACHABLE_NODES: 1117
|
// EXPECTED_REACHABLE_NODES: 1117
|
||||||
/*
|
/*
|
||||||
* Copy of JVM-backend test
|
* Copy of JVM-backend test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1110
|
// EXPECTED_REACHABLE_NODES: 1110
|
||||||
/*
|
/*
|
||||||
* Copy of JVM-backend test
|
* Copy of JVM-backend test
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JS_IR
|
|
||||||
// EXPECTED_REACHABLE_NODES: 1117
|
// EXPECTED_REACHABLE_NODES: 1117
|
||||||
package foo
|
package foo
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user