diff --git a/compiler/ir/backend.common/backend.common.iml b/compiler/ir/backend.common/backend.common.iml
index 56e15c15f12..a98ff1c560f 100644
--- a/compiler/ir/backend.common/backend.common.iml
+++ b/compiler/ir/backend.common/backend.common.iml
@@ -10,5 +10,7 @@
+
+
\ No newline at end of file
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CheckIrElementVisitor.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CheckIrElementVisitor.kt
new file mode 100644
index 00000000000..a7029a86c45
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CheckIrElementVisitor.kt
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.backend.common
+
+import org.jetbrains.kotlin.builtins.KotlinBuiltIns
+import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
+import org.jetbrains.kotlin.descriptors.ClassKind
+import org.jetbrains.kotlin.ir.IrElement
+import org.jetbrains.kotlin.ir.declarations.IrClass
+import org.jetbrains.kotlin.ir.expressions.*
+import org.jetbrains.kotlin.ir.symbols.IrSymbol
+import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.typeUtil.makeNullable
+
+typealias ReportError = (element: IrElement, message: String) -> Unit
+
+class CheckIrElementVisitor(val builtIns: KotlinBuiltIns, val reportError: ReportError, val ensureAllNodesAreDifferent: Boolean) : IrElementVisitorVoid {
+
+ val set = mutableSetOf()
+
+ override fun visitElement(element: IrElement) {
+ if (ensureAllNodesAreDifferent) {
+ if (set.contains(element))
+ reportError(element, "Duplicate IR node")
+ set.add(element)
+ }
+ // Nothing to do.
+ }
+
+ private fun IrExpression.ensureTypeIs(expectedType: KotlinType) {
+ if (expectedType != type) {
+ reportError(this, "unexpected expression.type: expected $expectedType, got ${type}")
+ }
+ }
+
+ private fun IrSymbol.ensureBound(expression: IrExpression) {
+ if (!this.isBound) {
+ reportError(expression, "Unbound symbol ${this}")
+ }
+ }
+
+ override fun visitConst(expression: IrConst) {
+ super.visitConst(expression)
+
+ val naturalType = when (expression.kind) {
+ IrConstKind.Null -> builtIns.nullableNothingType
+ IrConstKind.Boolean -> builtIns.booleanType
+ IrConstKind.Char -> builtIns.charType
+ IrConstKind.Byte -> builtIns.byteType
+ IrConstKind.Short -> builtIns.shortType
+ IrConstKind.Int -> builtIns.intType
+ IrConstKind.Long -> builtIns.longType
+ IrConstKind.String -> builtIns.stringType
+ IrConstKind.Float -> builtIns.floatType
+ IrConstKind.Double -> builtIns.doubleType
+ }
+
+ expression.ensureTypeIs(naturalType)
+ }
+
+ override fun visitStringConcatenation(expression: IrStringConcatenation) {
+ super.visitStringConcatenation(expression)
+
+ expression.ensureTypeIs(builtIns.stringType)
+ }
+
+ override fun visitGetObjectValue(expression: IrGetObjectValue) {
+ super.visitGetObjectValue(expression)
+
+ expression.ensureTypeIs(expression.descriptor.defaultType)
+ }
+
+ // TODO: visitGetEnumValue
+
+ override fun visitGetValue(expression: IrGetValue) {
+ super.visitGetValue(expression)
+
+ expression.ensureTypeIs(expression.descriptor.type)
+ }
+
+ override fun visitSetVariable(expression: IrSetVariable) {
+ super.visitSetVariable(expression)
+
+ expression.ensureTypeIs(builtIns.unitType)
+ }
+
+ override fun visitGetField(expression: IrGetField) {
+ super.visitGetField(expression)
+
+ expression.ensureTypeIs(expression.descriptor.type)
+ }
+
+ override fun visitSetField(expression: IrSetField) {
+ super.visitSetField(expression)
+
+ expression.ensureTypeIs(builtIns.unitType)
+ }
+
+ override fun visitCall(expression: IrCall) {
+ super.visitCall(expression)
+
+ val returnType = expression.descriptor.returnType
+ if (returnType == null) {
+ reportError(expression, "${expression.descriptor} return type is null")
+ } else {
+ expression.ensureTypeIs(returnType)
+ }
+
+ expression.superQualifierSymbol?.ensureBound(expression)
+ }
+
+ override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
+ super.visitDelegatingConstructorCall(expression)
+
+ expression.ensureTypeIs(builtIns.unitType)
+ }
+
+ override fun visitEnumConstructorCall(expression: IrEnumConstructorCall) {
+ super.visitEnumConstructorCall(expression)
+
+ expression.ensureTypeIs(builtIns.unitType)
+ }
+
+ override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall) {
+ super.visitInstanceInitializerCall(expression)
+
+ expression.ensureTypeIs(builtIns.unitType)
+ expression.classSymbol.ensureBound(expression)
+ }
+
+ override fun visitTypeOperator(expression: IrTypeOperatorCall) {
+ super.visitTypeOperator(expression)
+
+ val operator = expression.operator
+ val typeOperand = expression.typeOperand
+
+ val naturalType = when (operator) {
+ IrTypeOperator.CAST,
+ IrTypeOperator.IMPLICIT_CAST,
+ IrTypeOperator.IMPLICIT_NOTNULL,
+ IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
+ IrTypeOperator.IMPLICIT_INTEGER_COERCION -> typeOperand
+
+ IrTypeOperator.SAFE_CAST -> typeOperand.makeNullable()
+
+ IrTypeOperator.INSTANCEOF, IrTypeOperator.NOT_INSTANCEOF -> builtIns.booleanType
+ }
+
+ if (operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT && typeOperand != builtIns.unitType) {
+ reportError(expression, "typeOperand is $typeOperand")
+ }
+
+ // TODO: check IMPLICIT_NOTNULL's argument type.
+
+ expression.ensureTypeIs(naturalType)
+ }
+
+ override fun visitLoop(loop: IrLoop) {
+ super.visitLoop(loop)
+
+ loop.ensureTypeIs(builtIns.unitType)
+ }
+
+ override fun visitBreakContinue(jump: IrBreakContinue) {
+ super.visitBreakContinue(jump)
+
+ jump.ensureTypeIs(builtIns.nothingType)
+ }
+
+ override fun visitReturn(expression: IrReturn) {
+ super.visitReturn(expression)
+
+ expression.ensureTypeIs(builtIns.nothingType)
+ expression.returnTargetSymbol.ensureBound(expression)
+ }
+
+ override fun visitThrow(expression: IrThrow) {
+ super.visitThrow(expression)
+
+ expression.ensureTypeIs(builtIns.nothingType)
+ }
+
+ override fun visitClass(declaration: IrClass) {
+ super.visitClass(declaration)
+
+ if (declaration.descriptor.kind != ClassKind.ANNOTATION_CLASS) {
+ // Check that all functions and properties from memberScope are present in IR
+ // (including FAKE_OVERRIDE ones).
+
+ val allDescriptors = declaration.descriptor.unsubstitutedMemberScope
+ .getContributedDescriptors().filterIsInstance()
+
+ val presentDescriptors = declaration.declarations.map { it.descriptor }
+
+ val missingDescriptors = allDescriptors - presentDescriptors
+
+ if (missingDescriptors.isNotEmpty()) {
+ reportError(declaration, "Missing declarations for descriptors:\n" +
+ missingDescriptors.joinToString("\n"))
+ }
+ }
+ }
+
+ override fun visitDeclarationReference(expression: IrDeclarationReference) {
+ super.visitDeclarationReference(expression)
+
+ expression.symbol.ensureBound(expression)
+ }
+
+ override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
+ super.visitFunctionAccess(expression)
+
+ expression.symbol.ensureBound(expression)
+ }
+
+ override fun visitFunctionReference(expression: IrFunctionReference) {
+ super.visitFunctionReference(expression)
+
+ expression.symbol.ensureBound(expression)
+ }
+
+ override fun visitPropertyReference(expression: IrPropertyReference) {
+ super.visitPropertyReference(expression)
+
+ expression.field?.ensureBound(expression)
+ expression.getter?.ensureBound(expression)
+ expression.setter?.ensureBound(expression)
+ }
+
+ override fun visitLocalDelegatedPropertyReference(expression: IrLocalDelegatedPropertyReference) {
+ super.visitLocalDelegatedPropertyReference(expression)
+
+ expression.delegate.ensureBound(expression)
+ expression.getter.ensureBound(expression)
+ expression.setter?.ensureBound(expression)
+ }
+
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt
new file mode 100644
index 00000000000..6a65cce7003
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/CommonBackendContext.kt
@@ -0,0 +1,107 @@
+package org.jetbrains.kotlin.backend.common
+
+import org.jetbrains.kotlin.backend.common.ir.Ir
+import org.jetbrains.kotlin.builtins.KOTLIN_REFLECT_FQ_NAME
+import org.jetbrains.kotlin.cli.common.messages.MessageCollector
+import org.jetbrains.kotlin.config.CompilerConfiguration
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.descriptors.ModuleDescriptor
+import org.jetbrains.kotlin.descriptors.annotations.Annotations
+import org.jetbrains.kotlin.incremental.components.NoLookupLocation
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.resolve.scopes.MemberScope
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.KotlinTypeFactory
+import org.jetbrains.kotlin.types.TypeProjection
+import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
+import org.jetbrains.kotlin.utils.addIfNotNull
+import java.util.*
+import kotlin.reflect.KProperty
+
+
+interface CommonBackendContext : BackendContext {
+
+ val ir: Ir
+
+ //TODO move to builtins
+ fun getInternalClass(name: String): ClassDescriptor
+
+ //TODO move to builtins
+ fun getInternalFunctions(name: String): List
+
+ val reflectionTypes: ReflectionTypes
+
+ fun log(message: () -> String)
+
+ val messageCollector: MessageCollector
+}
+
+class ReflectionTypes(module: ModuleDescriptor, internalPackage: FqName) {
+
+ private val kotlinReflectScope: MemberScope by lazy(LazyThreadSafetyMode.PUBLICATION) {
+ module.getPackage(KOTLIN_REFLECT_FQ_NAME).memberScope
+ }
+
+ private val internalScope: MemberScope by lazy(LazyThreadSafetyMode.PUBLICATION) {
+ module.getPackage(internalPackage).memberScope
+ }
+
+ private fun find(memberScope: MemberScope, className: String): ClassDescriptor {
+ val name = Name.identifier(className)
+ return memberScope.getContributedClassifier(name, NoLookupLocation.FROM_REFLECTION) as ClassDescriptor
+ }
+
+ private class ClassLookup(val memberScope: MemberScope) {
+ operator fun getValue(types: ReflectionTypes, property: KProperty<*>): ClassDescriptor {
+ return types.find(memberScope, property.name.capitalize())
+ }
+ }
+
+ private fun getFunctionTypeArgumentProjections(
+ receiverType: KotlinType?,
+ parameterTypes: List,
+ returnType: KotlinType
+ ): List {
+ val arguments = ArrayList(parameterTypes.size + (if (receiverType != null) 1 else 0) + 1)
+
+ arguments.addIfNotNull(receiverType?.asTypeProjection())
+
+ parameterTypes.mapTo(arguments, KotlinType::asTypeProjection)
+
+ arguments.add(returnType.asTypeProjection())
+
+ return arguments
+ }
+
+ fun getKFunction(n: Int): ClassDescriptor = find(kotlinReflectScope, "KFunction$n")
+
+ val kClass: ClassDescriptor by ClassLookup(kotlinReflectScope)
+ val kProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope)
+ val kProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope)
+ val kProperty2: ClassDescriptor by ClassLookup(kotlinReflectScope)
+ val kMutableProperty0: ClassDescriptor by ClassLookup(kotlinReflectScope)
+ val kMutableProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope)
+ val kMutableProperty2: ClassDescriptor by ClassLookup(kotlinReflectScope)
+ val kFunctionImpl: ClassDescriptor by ClassLookup(internalScope)
+ val kProperty0Impl: ClassDescriptor by ClassLookup(internalScope)
+ val kProperty1Impl: ClassDescriptor by ClassLookup(internalScope)
+ val kProperty2Impl: ClassDescriptor by ClassLookup(internalScope)
+ val kMutableProperty0Impl: ClassDescriptor by ClassLookup(internalScope)
+ val kMutableProperty1Impl: ClassDescriptor by ClassLookup(internalScope)
+ val kMutableProperty2Impl: ClassDescriptor by ClassLookup(internalScope)
+ val kLocalDelegatedPropertyImpl: ClassDescriptor by ClassLookup(internalScope)
+ val kLocalDelegatedMutablePropertyImpl: ClassDescriptor by ClassLookup(internalScope)
+
+ fun getKFunctionType(
+ annotations: Annotations,
+ receiverType: KotlinType?,
+ parameterTypes: List,
+ returnType: KotlinType
+ ): KotlinType {
+ val arguments = getFunctionTypeArgumentProjections(receiverType, parameterTypes, returnType)
+ val classDescriptor = getKFunction(arguments.size - 1 /* return type */)
+ return KotlinTypeFactory.simpleNotNullType(annotations, classDescriptor, arguments)
+ }
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDeclarations.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDeclarations.kt
new file mode 100644
index 00000000000..c7f69b754e4
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDeclarations.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.backend.common
+
+import org.jetbrains.kotlin.descriptors.VariableDescriptor
+import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
+import org.jetbrains.kotlin.ir.IrElement
+import org.jetbrains.kotlin.ir.expressions.IrLoop
+import org.jetbrains.kotlin.ir.util.DeepCopySymbolsRemapper
+import org.jetbrains.kotlin.ir.util.DescriptorsRemapper
+import org.jetbrains.kotlin.ir.visitors.acceptVoid
+
+fun IrElement.deepCopyWithVariablesImpl(): IrElement {
+ val descriptorsRemapper = object : DescriptorsRemapper {
+ override fun remapDeclaredVariable(descriptor: VariableDescriptor) = LocalVariableDescriptor(
+ /* containingDeclaration = */ descriptor.containingDeclaration,
+ /* annotations = */ descriptor.annotations,
+ /* name = */ descriptor.name,
+ /* type = */ descriptor.type,
+ /* mutable = */ descriptor.isVar,
+ /* isDelegated = */ false,
+ /* source = */ descriptor.source
+ )
+ }
+
+ val symbolsRemapper = DeepCopySymbolsRemapper(descriptorsRemapper)
+ acceptVoid(symbolsRemapper)
+
+ return this.transform(
+ object : DeepCopyIrTreeWithReturnableBlockSymbols(symbolsRemapper) {
+ override fun getNonTransformedLoop(irLoop: IrLoop): IrLoop {
+ return irLoop
+ }
+ },
+ null
+ )
+}
+
+inline fun T.deepCopyWithVariables(): T =
+ this.deepCopyWithVariablesImpl() as T
\ No newline at end of file
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDescriptoros.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDescriptoros.kt
new file mode 100644
index 00000000000..2946a4f5a4c
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DeepCopyIrTreeWithDescriptoros.kt
@@ -0,0 +1,618 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.backend.common
+
+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.declarations.*
+import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
+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.util.DeepCopyIrTree
+import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.resolve.DescriptorUtils
+import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.TypeSubstitutor
+import org.jetbrains.kotlin.types.Variance
+import org.jetbrains.kotlin.types.typeUtil.makeNullable
+
+internal class DeepCopyIrTreeWithDescriptors(val targetDescriptor: FunctionDescriptor,
+ val context: CommonBackendContext) {
+
+ private val descriptorSubstituteMap: MutableMap = mutableMapOf()
+ private var typeSubstitutor: TypeSubstitutor? = null
+ private var nameIndex = 0
+
+ //-------------------------------------------------------------------------//
+
+ fun copy(irElement: IrElement, typeSubstitutor: TypeSubstitutor?): IrElement {
+ this.typeSubstitutor = typeSubstitutor
+ irElement.acceptChildrenVoid(DescriptorCollector())
+ return irElement.accept(InlineCopyIr(), null)
+ }
+
+ //-------------------------------------------------------------------------//
+
+ inner class DescriptorCollector: IrElementVisitorVoid {
+
+ override fun visitElement(element: IrElement) {
+ element.acceptChildren(this, null)
+ }
+
+ //---------------------------------------------------------------------//
+
+ override fun visitClass(declaration: IrClass) {
+
+ val oldDescriptor = declaration.descriptor
+ val newDescriptor = copyClassDescriptor(oldDescriptor)
+ descriptorSubstituteMap[oldDescriptor] = newDescriptor
+ descriptorSubstituteMap[oldDescriptor.thisAsReceiverParameter] = newDescriptor.thisAsReceiverParameter
+
+ super.visitClass(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 visitProperty(declaration: IrProperty) {
+
+ copyPropertyOrField(declaration.descriptor)
+ super.visitProperty(declaration)
+ }
+
+ //---------------------------------------------------------------------//
+
+ override fun visitField(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.visitField(declaration)
+ }
+
+ //---------------------------------------------------------------------//
+
+ override fun visitFunction(declaration: IrFunction) {
+
+ val oldDescriptor = declaration.descriptor
+ if (oldDescriptor !is PropertyAccessorDescriptor) { // Property accessors are copied along with their property.
+ val newDescriptor = copyFunctionDescriptor(oldDescriptor)
+ descriptorSubstituteMap[oldDescriptor] = newDescriptor
+ oldDescriptor.extensionReceiverParameter?.let{
+ descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!!
+ }
+ }
+ super.visitFunction(declaration)
+ }
+
+ //---------------------------------------------------------------------//
+
+ override fun visitVariable(declaration: IrVariable) {
+
+ val oldDescriptor = declaration.descriptor
+ val oldContainingDeclaration = oldDescriptor.containingDeclaration
+ val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
+ val newDescriptor = IrTemporaryVariableDescriptorImpl(
+ containingDeclaration = newContainingDeclaration,
+ name = generateCopyName(oldDescriptor.name),
+ outType = substituteType(oldDescriptor.type)!!,
+ isMutable = oldDescriptor.isVar)
+ descriptorSubstituteMap[oldDescriptor] = newDescriptor
+
+ super.visitVariable(declaration)
+ }
+
+ //---------------------------------------------------------------------//
+
+ override fun visitCatch(aCatch: IrCatch) {
+ val oldDescriptor = aCatch.parameter
+ val oldContainingDeclaration = oldDescriptor.containingDeclaration
+ val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
+ val newDescriptor = IrTemporaryVariableDescriptorImpl(
+ containingDeclaration = newContainingDeclaration,
+ name = generateCopyName(oldDescriptor.name),
+ outType = substituteType(oldDescriptor.type)!!,
+ isMutable = oldDescriptor.isVar)
+ descriptorSubstituteMap[oldDescriptor] = newDescriptor
+
+ 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 copyFunctionDescriptor(oldDescriptor: CallableDescriptor): CallableDescriptor {
+
+ return when (oldDescriptor) {
+ is ConstructorDescriptor -> copyConstructorDescriptor(oldDescriptor)
+ is SimpleFunctionDescriptor -> copySimpleFunctionDescriptor(oldDescriptor)
+ else -> TODO("Unsupported FunctionDescriptor subtype: $oldDescriptor")
+ }
+ }
+
+ //---------------------------------------------------------------------//
+
+ private fun copySimpleFunctionDescriptor(oldDescriptor: SimpleFunctionDescriptor) : FunctionDescriptor {
+
+ val oldContainingDeclaration = oldDescriptor.containingDeclaration
+ val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration)
+ return SimpleFunctionDescriptorImpl.create(
+ /* containingDeclaration = */ newContainingDeclaration,
+ /* annotations = */ oldDescriptor.annotations,
+ /* name = */ generateCopyName(oldDescriptor.name),
+ /* kind = */ oldDescriptor.kind,
+ /* source = */ oldDescriptor.source
+ ).apply {
+
+ val oldDispatchReceiverParameter = oldDescriptor.dispatchReceiverParameter
+ val newDispatchReceiverParameter = oldDispatchReceiverParameter?.let { descriptorSubstituteMap.getOrDefault(it, it) as ReceiverParameterDescriptor }
+ val newTypeParameters = oldDescriptor.typeParameters // TODO substitute types
+ val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
+ val newReceiverParameterType = substituteType(oldDescriptor.extensionReceiverParameter?.type)
+ val newReturnType = substituteType(oldDescriptor.returnType)
+
+ initialize(
+ /* receiverParameterType = */ newReceiverParameterType,
+ /* 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 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
+ ).apply {
+
+ val newTypeParameters = oldDescriptor.typeParameters
+ val newValueParameters = copyValueParameters(oldDescriptor.valueParameters, this)
+ val receiverParameterType = substituteType(oldDescriptor.dispatchReceiverParameter?.type)
+ val returnType = substituteType(oldDescriptor.returnType)
+
+ initialize(
+ /* receiverParameterType = */ receiverParameterType,
+ /* dispatchReceiverParameter = */ null, // For constructor there is no explicit dispatch receiver.
+ /* typeParameters = */ newTypeParameters,
+ /* unsubstitutedValueParameters = */ newValueParameters,
+ /* unsubstitutedReturnType = */ returnType,
+ /* modality = */ oldDescriptor.modality,
+ /* visibility = */ oldDescriptor.visibility
+ )
+ }
+ }
+
+ //---------------------------------------------------------------------//
+
+ private fun copyPropertyOrField(oldDescriptor: PropertyDescriptor) {
+
+ val newDescriptor = copyPropertyDescriptor(oldDescriptor)
+ descriptorSubstituteMap[oldDescriptor] = newDescriptor
+ oldDescriptor.getter?.let {
+ descriptorSubstituteMap[it] = newDescriptor.getter!!
+ }
+ oldDescriptor.setter?.let {
+ descriptorSubstituteMap[it] = newDescriptor.setter!!
+ }
+ oldDescriptor.extensionReceiverParameter?.let{
+ descriptorSubstituteMap[it] = newDescriptor.extensionReceiverParameter!!
+ }
+
+ }
+
+ //---------------------------------------------------------------------//
+
+ private fun copyPropertyDescriptor(oldDescriptor: PropertyDescriptor): PropertyDescriptor {
+
+ val oldContainingDeclaration = oldDescriptor.containingDeclaration
+ val newContainingDeclaration = descriptorSubstituteMap.getOrDefault(oldContainingDeclaration, oldContainingDeclaration) as ClassDescriptor
+ return 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,
+ /* isHeader = */ oldDescriptor.isHeader,
+ /* isImpl = */ oldDescriptor.isImpl,
+ /* isExternal = */ oldDescriptor.isExternal,
+ /* isDelegated = */ oldDescriptor.isDelegated
+ ).apply {
+
+ setType(
+ /* outType = */ oldDescriptor.type,
+ /* typeParameters = */ oldDescriptor.typeParameters,
+ /* dispatchReceiverParameter = */ newContainingDeclaration.thisAsReceiverParameter,
+ /* receiverType = */ oldDescriptor.extensionReceiverParameter?.type)
+
+ initialize(
+ /* getter = */ oldDescriptor.getter?.let { copyPropertyGetterDescriptor(it, this) },
+ /* setter = */ oldDescriptor.setter?.let { copyPropertySetterDescriptor(it, this) })
+
+ overriddenDescriptors += oldDescriptor.overriddenDescriptors
+ }
+ }
+
+ //---------------------------------------------------------------------//
+
+ private fun copyPropertyGetterDescriptor(oldDescriptor: PropertyGetterDescriptor, newPropertyDescriptor: PropertyDescriptor)
+ : PropertyGetterDescriptorImpl {
+
+ return 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(oldDescriptor.returnType)
+ }
+ }
+
+ //---------------------------------------------------------------------//
+
+ private fun copyPropertySetterDescriptor(oldDescriptor: PropertySetterDescriptor, newPropertyDescriptor: PropertyDescriptor)
+ : PropertySetterDescriptorImpl {
+
+ return 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 copyClassDescriptor(oldDescriptor: ClassDescriptor): ClassDescriptorImpl {
+
+ val oldSuperClass = oldDescriptor.getSuperClassOrAny()
+ val newSuperClass = descriptorSubstituteMap.getOrDefault(oldSuperClass, oldSuperClass) 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)
+ return ClassDescriptorImpl(
+ /* containingDeclaration = */ newContainingDeclaration,
+ /* name = */ newName,
+ /* modality = */ oldDescriptor.modality,
+ /* kind = */ oldDescriptor.kind,
+ /* supertypes = */ listOf(newSuperClass.defaultType),
+ /* source = */ oldDescriptor.source,
+ /* isExternal = */ oldDescriptor.isExternal
+ )
+ }
+ }
+
+//-----------------------------------------------------------------------------//
+
+ 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!!,
+ calleeDescriptor = newDescriptor,
+ typeArguments = substituteTypeArguments(expression.transformTypeArguments(newDescriptor)),
+ origin = expression.origin,
+ superQualifierDescriptor = mapSuperQualifier(expression.superQualifier)
+ ).transformValueArguments(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)
+ ).transformParameters(declaration)
+
+ //---------------------------------------------------------------------//
+
+ private fun 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 getNonTransformedLoop(irLoop: IrLoop): IrLoop {
+ return irLoop
+ }
+ }
+
+ //-------------------------------------------------------------------------//
+
+ private fun copyValueParameters(oldValueParameters: List , containingDeclaration: CallableDescriptor): List {
+
+ return oldValueParameters.map { oldDescriptor ->
+ val newDescriptor = ValueParameterDescriptorImpl(
+ containingDeclaration = containingDeclaration,
+ original = oldDescriptor.original,
+ index = oldDescriptor.index,
+ annotations = oldDescriptor.annotations,
+ name = oldDescriptor.name,
+ outType = substituteType(oldDescriptor.type)!!,
+ declaresDefaultValue = oldDescriptor.declaresDefaultValue(),
+ isCrossinline = oldDescriptor.isCrossinline,
+ isNoinline = oldDescriptor.isNoinline,
+ varargElementType = substituteType(oldDescriptor.varargElementType),
+ source = oldDescriptor.source
+ )
+ descriptorSubstituteMap[oldDescriptor] = newDescriptor
+ newDescriptor
+ }
+ }
+
+ //-------------------------------------------------------------------------//
+
+ 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 substituteTypeArguments(oldTypeArguments: Map ?): Map ? {
+
+ if (oldTypeArguments == null) return null
+ if (typeSubstitutor == null) return oldTypeArguments
+
+ val newTypeArguments = oldTypeArguments.entries.associate {
+ val typeParameterDescriptor = it.key
+ val oldTypeArgument = it.value
+ val newTypeArgument = substituteType(oldTypeArgument)!!
+ typeParameterDescriptor to newTypeArgument
+ }
+ return newTypeArguments
+ }
+
+ //-------------------------------------------------------------------------//
+
+ fun addCurrentSubstituteMap(globalSubstituteMap: MutableMap) {
+ descriptorSubstituteMap.forEach { t, u ->
+ globalSubstituteMap.put(t, SubstitutedDescriptor(targetDescriptor, u))
+ }
+ }
+
+}
+
+internal class SubstitutedDescriptor(val inlinedFunction: FunctionDescriptor, val descriptor: DeclarationDescriptor)
+
+internal class DescriptorSubstitutorForExternalScope(val globalSubstituteMap: MutableMap)
+ : IrElementTransformerVoidWithContext() {
+
+ override fun visitCall(expression: IrCall): IrExpression {
+ val oldExpression = super.visitCall(expression) as IrCall
+
+ val substitutedDescriptor = globalSubstituteMap[expression.descriptor.original]
+ ?: return oldExpression
+ if (allScopes.any { it.scope.scopeOwner == substitutedDescriptor.inlinedFunction })
+ return oldExpression
+ return when (oldExpression) {
+ is IrCallImpl -> copyIrCallImpl(oldExpression, substitutedDescriptor)
+ is IrCallWithShallowCopy -> copyIrCallWithShallowCopy(oldExpression, substitutedDescriptor)
+ else -> oldExpression
+ }
+ }
+
+ //-------------------------------------------------------------------------//
+
+ private fun copyIrCallImpl(oldExpression: IrCallImpl, substitutedDescriptor: SubstitutedDescriptor): IrCallImpl {
+
+ val oldDescriptor = oldExpression.descriptor
+ val newDescriptor = substitutedDescriptor.descriptor as FunctionDescriptor
+
+ if (newDescriptor == oldDescriptor)
+ return oldExpression
+
+ val newExpression = IrCallImpl(
+ startOffset = oldExpression.startOffset,
+ endOffset = oldExpression.endOffset,
+ type = oldExpression.type,
+ calleeDescriptor = newDescriptor,
+ typeArguments = oldExpression.typeArguments,
+ origin = oldExpression.origin,
+ superQualifierDescriptor = oldExpression.superQualifier
+ ).apply {
+ oldExpression.descriptor.valueParameters.forEach {
+ val valueArgument = oldExpression.getValueArgument(it)
+ putValueArgument(it.index, valueArgument)
+ }
+ extensionReceiver = oldExpression.extensionReceiver
+ dispatchReceiver = oldExpression.dispatchReceiver
+ }
+
+ return newExpression
+ }
+
+ //-------------------------------------------------------------------------//
+
+ 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, newDescriptor, oldExpression.superQualifier)
+ }
+}
+
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DumpIrTreeWithDescriptorsVisitor.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DumpIrTreeWithDescriptorsVisitor.kt
new file mode 100644
index 00000000000..b27f0e2c024
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/DumpIrTreeWithDescriptorsVisitor.kt
@@ -0,0 +1,365 @@
+package org.jetbrains.kotlin.backend.common
+
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
+import org.jetbrains.kotlin.ir.IrElement
+import org.jetbrains.kotlin.ir.declarations.*
+import org.jetbrains.kotlin.ir.expressions.*
+import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
+import org.jetbrains.kotlin.renderer.*
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.utils.Printer
+
+class RenderIrElementWithDescriptorsVisitor : IrElementVisitor {
+ override fun visitElement(element: IrElement, data: Nothing?): String =
+ "? ${element.javaClass.simpleName}"
+
+ override fun visitDeclaration(declaration: IrDeclaration, data: Nothing?): String =
+ "? ${declaration.javaClass.simpleName} ${declaration.descriptor.ref()}"
+
+ override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): String =
+ "MODULE_FRAGMENT ${declaration.descriptor}"
+
+ override fun visitFile(declaration: IrFile, data: Nothing?): String =
+ "FILE ${declaration.name}"
+
+ override fun visitFunction(declaration: IrFunction, data: Nothing?): String =
+ "FUN ${declaration.descriptor}"
+
+ override fun visitConstructor(declaration: IrConstructor, data: Nothing?): String =
+ "CONSTRUCTOR ${declaration.descriptor}"
+
+ override fun visitProperty(declaration: IrProperty, data: Nothing?): String =
+ "PROPERTY ${declaration.descriptor}"
+
+ override fun visitField(declaration: IrField, data: Nothing?): String =
+ "FIELD ${declaration.descriptor}"
+
+ override fun visitClass(declaration: IrClass, data: Nothing?): String =
+ "CLASS ${declaration.descriptor}"
+
+ override fun visitTypeAlias(declaration: IrTypeAlias, data: Nothing?): String =
+ "TYPEALIAS ${declaration.descriptor} type=${declaration.descriptor.underlyingType.render()}"
+
+ override fun visitVariable(declaration: IrVariable, data: Nothing?): String =
+ "VAR ${declaration.descriptor}"
+
+ override fun visitEnumEntry(declaration: IrEnumEntry, data: Nothing?): String =
+ "ENUM_ENTRY ${declaration.descriptor}"
+
+ override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer, data: Nothing?): String =
+ "ANONYMOUS_INITIALIZER ${declaration.descriptor}"
+
+ override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty, data: Nothing?): String =
+ "LOCAL_DELEGATED_PROPERTY ${declaration.descriptor}"
+
+ override fun visitExpressionBody(body: IrExpressionBody, data: Nothing?): String =
+ "EXPRESSION_BODY"
+
+ override fun visitBlockBody(body: IrBlockBody, data: Nothing?): String =
+ "BLOCK_BODY"
+
+ override fun visitSyntheticBody(body: IrSyntheticBody, data: Nothing?): String =
+ "SYNTHETIC_BODY kind=${body.kind}"
+
+ override fun visitExpression(expression: IrExpression, data: Nothing?): String =
+ "? ${expression.javaClass.simpleName} type=${expression.type.render()}"
+
+ override fun visitConst(expression: IrConst, data: Nothing?): String =
+ "CONST ${expression.kind} type=${expression.type.render()} value='${expression.value}'"
+
+ override fun visitVararg(expression: IrVararg, data: Nothing?): String =
+ "VARARG type=${expression.type} varargElementType=${expression.varargElementType}"
+
+ override fun visitSpreadElement(spread: IrSpreadElement, data: Nothing?): String =
+ "SPREAD_ELEMENT"
+
+ override fun visitBlock(expression: IrBlock, data: Nothing?): String =
+ "BLOCK type=${expression.type.render()} origin=${expression.origin}"
+
+ override fun visitComposite(expression: IrComposite, data: Nothing?): String =
+ "COMPOSITE type=${expression.type.render()} origin=${expression.origin}"
+
+ override fun visitReturn(expression: IrReturn, data: Nothing?): String =
+ "RETURN type=${expression.type.render()} from='${expression.returnTarget}'"
+
+ override fun visitCall(expression: IrCall, data: Nothing?): String =
+ "CALL '${expression.descriptor}' ${expression.renderSuperQualifier()}" +
+ "type=${expression.type.render()} origin=${expression.origin}"
+
+ private fun IrCall.renderSuperQualifier(): String =
+ superQualifier?.let { "superQualifier=${it.name} " } ?: ""
+
+ override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Nothing?): String =
+ "DELEGATING_CONSTRUCTOR_CALL '${expression.descriptor}'"
+
+ override fun visitEnumConstructorCall(expression: IrEnumConstructorCall, data: Nothing?): String =
+ "ENUM_CONSTRUCTOR_CALL '${expression.descriptor}'"
+
+ override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall, data: Nothing?): String =
+ "INSTANCE_INITIALIZER_CALL classDescriptor='${expression.classDescriptor}'"
+
+ override fun visitGetValue(expression: IrGetValue, data: Nothing?): String =
+ "GET_VAR '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
+
+ override fun visitSetVariable(expression: IrSetVariable, data: Nothing?): String =
+ "SET_VAR '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
+
+ override fun visitGetField(expression: IrGetField, data: Nothing?): String =
+ "GET_FIELD '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
+
+ override fun visitSetField(expression: IrSetField, data: Nothing?): String =
+ "SET_FIELD '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
+
+ override fun visitGetObjectValue(expression: IrGetObjectValue, data: Nothing?): String =
+ "GET_OBJECT '${expression.descriptor}' type=${expression.type.render()}"
+
+ override fun visitGetEnumValue(expression: IrGetEnumValue, data: Nothing?): String =
+ "GET_ENUM '${expression.descriptor}' type=${expression.type.render()}"
+
+ override fun visitStringConcatenation(expression: IrStringConcatenation, data: Nothing?): String =
+ "STRING_CONCATENATION type=${expression.type.render()}"
+
+ override fun visitTypeOperator(expression: IrTypeOperatorCall, data: Nothing?): String =
+ "TYPE_OP origin=${expression.operator} typeOperand=${expression.typeOperand.render()}"
+
+ override fun visitWhen(expression: IrWhen, data: Nothing?): String =
+ "WHEN type=${expression.type.render()} origin=${expression.origin}"
+
+ override fun visitBranch(branch: IrBranch, data: Nothing?): String =
+ "BRANCH"
+
+ override fun visitWhileLoop(loop: IrWhileLoop, data: Nothing?): String =
+ "WHILE label=${loop.label} origin=${loop.origin}"
+
+ override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: Nothing?): String =
+ "DO_WHILE label=${loop.label} origin=${loop.origin}"
+
+ override fun visitBreak(jump: IrBreak, data: Nothing?): String =
+ "BREAK label=${jump.label} loop.label=${jump.loop.label}"
+
+ override fun visitContinue(jump: IrContinue, data: Nothing?): String =
+ "CONTINUE label=${jump.label} loop.label=${jump.loop.label}"
+
+ override fun visitThrow(expression: IrThrow, data: Nothing?): String =
+ "THROW type=${expression.type.render()}"
+
+ override fun visitCallableReference(expression: IrCallableReference, data: Nothing?): String =
+ "CALLABLE_REFERENCE '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}"
+
+ override fun visitClassReference(expression: IrClassReference, data: Nothing?): String =
+ "CLASS_REFERENCE '${expression.descriptor}' type=${expression.type.render()}"
+
+ override fun visitGetClass(expression: IrGetClass, data: Nothing?): String =
+ "GET_CLASS type=${expression.type.render()}"
+
+ override fun visitTry(aTry: IrTry, data: Nothing?): String =
+ "TRY type=${aTry.type.render()}"
+
+ override fun visitCatch(aCatch: IrCatch, data: Nothing?): String =
+ "CATCH parameter=${aCatch.parameter.ref()}"
+
+ override fun visitErrorDeclaration(declaration: IrErrorDeclaration, data: Nothing?): String =
+ "ERROR_DECL ${declaration.descriptor.javaClass.simpleName} ${declaration.descriptor.ref()}"
+
+ override fun visitErrorExpression(expression: IrErrorExpression, data: Nothing?): String =
+ "ERROR_EXPR '${expression.description}' type=${expression.type.render()}"
+
+ override fun visitErrorCallExpression(expression: IrErrorCallExpression, data: Nothing?): String =
+ "ERROR_CALL '${expression.description}' type=${expression.type.render()}"
+
+ companion object {
+ val DECLARATION_RENDERER = DescriptorRenderer.withOptions {
+ withDefinedIn = false
+ overrideRenderingPolicy = OverrideRenderingPolicy.RENDER_OPEN_OVERRIDE
+ includePropertyConstant = true
+ classifierNamePolicy = ClassifierNamePolicy.FULLY_QUALIFIED
+ verbose = false
+ modifiers = DescriptorRendererModifier.ALL
+ }
+
+ val REFERENCE_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES
+
+ internal fun IrDeclaration.name(): String =
+ descriptor.let { it.name.toString() }
+
+ internal fun IrDeclaration.renderDeclared(): String =
+ DECLARATION_RENDERER.render(this.descriptor)
+
+ internal fun DeclarationDescriptor.ref(): String =
+ if (this is ReceiverParameterDescriptor)
+ ""
+ else
+ REFERENCE_RENDERER.render(this)
+
+ internal fun KotlinType.render(): String =
+ DECLARATION_RENDERER.renderType(this)
+
+ internal fun IrDeclaration.renderOrigin(): String =
+ if (origin != IrDeclarationOrigin.DEFINED) origin.toString() + " " else ""
+ }
+}
+
+class DumpIrTreeWithDescriptorsVisitor(out: Appendable): IrElementVisitor {
+ val printer = Printer(out, " ")
+ val elementRenderer = RenderIrElementWithDescriptorsVisitor()
+
+ companion object {
+ val ANNOTATIONS_RENDERER = DescriptorRenderer.withOptions {
+ verbose = true
+ annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY
+ }
+ }
+
+ override fun visitElement(element: IrElement, data: String) {
+ element.dumpLabeledSubTree(data)
+ }
+
+ override fun visitFile(declaration: IrFile, data: String) {
+ declaration.dumpLabeledElementWith(data) {
+ if (declaration.fileAnnotations.isNotEmpty()) {
+ printer.println("fileAnnotations:")
+ indented {
+ declaration.fileAnnotations.forEach {
+ printer.println(ANNOTATIONS_RENDERER.renderAnnotation(it))
+ }
+ }
+ }
+ declaration.declarations.forEach { it.accept(this, "") }
+ }
+ }
+
+ override fun visitBlock(expression: IrBlock, data: String) {
+ if (expression is IrReturnableBlock) {
+ printer.println("RETURNABLE BLOCK " + expression.descriptor)
+ indented { super.visitBlock(expression, data) }
+ return
+ }
+ super.visitBlock(expression, data)
+ }
+
+ override fun visitFunction(declaration: IrFunction, data: String) {
+ visitFunctionWithParameters(declaration, data)
+ }
+
+ override fun visitConstructor(declaration: IrConstructor, data: String) {
+ visitFunctionWithParameters(declaration, data)
+ }
+
+ override fun visitErrorCallExpression(expression: IrErrorCallExpression, data: String) {
+ expression.dumpLabeledElementWith(data) {
+ expression.explicitReceiver?.accept(this, "receiver")
+ expression.arguments.forEach { it.accept(this, "") }
+ }
+ }
+
+ private fun visitFunctionWithParameters(declaration: IrFunction, data: String) {
+ declaration.dumpLabeledElementWith(data) {
+ declaration.descriptor.valueParameters.forEach { valueParameter ->
+ declaration.getDefault(valueParameter)?.accept(this, valueParameter.name.asString())
+ }
+ declaration.body?.accept(this, "")
+ }
+ }
+
+ override fun visitEnumEntry(declaration: IrEnumEntry, data: String) {
+ declaration.dumpLabeledElementWith(data) {
+ declaration.initializerExpression?.accept(this, "init")
+ declaration.correspondingClass?.accept(this, "class")
+ }
+ }
+
+ override fun visitMemberAccess(expression: IrMemberAccessExpression, data: String) {
+ expression.dumpLabeledElementWith(data) {
+ dumpTypeArguments(expression)
+
+ expression.dispatchReceiver?.accept(this, "\$this")
+ expression.extensionReceiver?.accept(this, "\$receiver")
+ for (valueParameter in expression.descriptor.valueParameters) {
+ expression.getValueArgument(valueParameter.index)?.accept(this, valueParameter.name.asString())
+ }
+ }
+ }
+
+ private fun dumpTypeArguments(expression: IrMemberAccessExpression) {
+ for (typeParameter in expression.descriptor.original.typeParameters) {
+ val typeArgument = expression.getTypeArgument(typeParameter) ?: continue
+ val renderedParameter = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.render(typeParameter)
+ val renderedType = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.renderType(typeArgument)
+ printer.println("$renderedParameter: $renderedType")
+ }
+ }
+
+ override fun visitGetField(expression: IrGetField, data: String) {
+ expression.dumpLabeledElementWith(data) {
+ expression.receiver?.accept(this, "receiver")
+ }
+ }
+
+ override fun visitSetField(expression: IrSetField, data: String) {
+ expression.dumpLabeledElementWith(data) {
+ expression.receiver?.accept(this, "receiver")
+ expression.value.accept(this, "value")
+ }
+ }
+
+ override fun visitWhen(expression: IrWhen, data: String) {
+ expression.dumpLabeledElementWith(data) {
+ expression.branches.forEach {
+ it.accept(this, "")
+ }
+ }
+ }
+
+ override fun visitBranch(branch: IrBranch, data: String) {
+ branch.dumpLabeledElementWith(data) {
+ branch.condition.accept(this, "if")
+ branch.result.accept(this, "then")
+ }
+ }
+
+ override fun visitWhileLoop(loop: IrWhileLoop, data: String) {
+ loop.dumpLabeledElementWith(data) {
+ loop.condition.accept(this, "condition")
+ loop.body?.accept(this, "body")
+ }
+ }
+
+ override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: String) {
+ loop.dumpLabeledElementWith(data) {
+ loop.body?.accept(this, "body")
+ loop.condition.accept(this, "condition")
+ }
+ }
+
+ override fun visitTry(aTry: IrTry, data: String) {
+ aTry.dumpLabeledElementWith(data) {
+ aTry.tryResult.accept(this, "try")
+ for (aCatch in aTry.catches) {
+ aCatch.accept(this, "")
+ }
+ aTry.finallyExpression?.accept(this, "finally")
+ }
+ }
+
+ private inline fun IrElement.dumpLabeledElementWith(label: String, body: () -> Unit) {
+ printer.println(accept(elementRenderer, null).withLabel(label))
+ indented(body)
+ }
+
+ private fun IrElement.dumpLabeledSubTree(label: String) {
+ printer.println(accept(elementRenderer, null).withLabel(label))
+ indented {
+ acceptChildren(this@DumpIrTreeWithDescriptorsVisitor, "")
+ }
+ }
+
+ private inline fun indented(body: () -> Unit) {
+ printer.pushIndent()
+ body()
+ printer.popIndent()
+ }
+
+ private fun String.withLabel(label: String) =
+ if (label.isEmpty()) this else "$label: $this"
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrCopy.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrCopy.kt
new file mode 100644
index 00000000000..9c7b90e2dcb
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrCopy.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.backend.common
+
+import org.jetbrains.kotlin.ir.IrElement
+import org.jetbrains.kotlin.ir.expressions.IrBlock
+import org.jetbrains.kotlin.ir.expressions.IrReturn
+import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
+import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
+import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl
+import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
+import org.jetbrains.kotlin.ir.util.DeepCopyIrTreeWithSymbols
+import org.jetbrains.kotlin.ir.util.SymbolRemapper
+
+open class DeepCopyIrTreeWithReturnableBlockSymbols(
+ private val symbolRemapper: SymbolRemapper
+) : DeepCopyIrTreeWithSymbols(symbolRemapper) {
+
+ private inline fun T.transform() =
+ transform(this@DeepCopyIrTreeWithReturnableBlockSymbols, null) as T
+
+ private val transformedReturnableBlocks = mutableMapOf()
+
+ override fun visitBlock(expression: IrBlock): IrBlock = if (expression is IrReturnableBlock) {
+ IrReturnableBlockImpl(
+ expression.startOffset, expression.endOffset,
+ expression.type,
+ expression.descriptor,
+ expression.origin,
+ expression.sourceFileName
+ ).also {
+ transformedReturnableBlocks.put(expression, it)
+ it.statements.addAll(expression.statements.map { it.transform() })
+ }
+ } else {
+ super.visitBlock(expression)
+ }
+
+ override fun visitReturn(expression: IrReturn): IrReturn {
+ val returnTargetSymbol = expression.returnTargetSymbol
+ return if (returnTargetSymbol is IrReturnableBlockSymbol) {
+ IrReturnImpl(
+ expression.startOffset, expression.endOffset,
+ expression.type,
+ transformedReturnableBlocks.getOrElse(returnTargetSymbol.owner) { returnTargetSymbol.owner }.symbol,
+ expression.value.transform()
+ )
+ } else {
+ super.visitReturn(expression)
+ }
+ }
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt
new file mode 100644
index 00000000000..dc2a673c438
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrElementTransformerVoidWithContext.kt
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.backend.common
+
+import org.jetbrains.kotlin.ir.IrElement
+import org.jetbrains.kotlin.ir.IrStatement
+import org.jetbrains.kotlin.ir.builders.Scope
+import org.jetbrains.kotlin.ir.declarations.*
+import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
+import org.jetbrains.kotlin.descriptors.*
+
+class ScopeWithIr(val scope: Scope, val irElement: IrElement)
+
+abstract class IrElementTransformerVoidWithContext : IrElementTransformerVoid() {
+
+ private val scopeStack = mutableListOf()
+
+ override final fun visitFile(declaration: IrFile): IrFile {
+ scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
+ val result = visitFileNew(declaration)
+ scopeStack.pop()
+ return result
+ }
+
+ override final fun visitClass(declaration: IrClass): IrStatement {
+ scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
+ val result = visitClassNew(declaration)
+ scopeStack.pop()
+ return result
+ }
+
+ override final fun visitProperty(declaration: IrProperty): IrStatement {
+ scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
+ val result = visitPropertyNew(declaration)
+ scopeStack.pop()
+ return result
+ }
+
+ override final fun visitField(declaration: IrField): IrStatement {
+ scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
+ val result = visitFieldNew(declaration)
+ scopeStack.pop()
+ return result
+ }
+
+ override final fun visitFunction(declaration: IrFunction): IrStatement {
+ scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
+ val result = visitFunctionNew(declaration)
+ scopeStack.pop()
+ return result
+ }
+
+ protected val currentFile get() = scopeStack.lastOrNull { it.irElement is IrFile }!!.irElement as IrFile
+ protected val currentClass get() = scopeStack.lastOrNull { it.scope.scopeOwner is ClassDescriptor }
+ protected val currentFunction get() = scopeStack.lastOrNull { it.scope.scopeOwner is FunctionDescriptor }
+ protected val currentProperty get() = scopeStack.lastOrNull { it.scope.scopeOwner is PropertyDescriptor }
+ protected val currentScope get() = scopeStack.peek()
+ protected val parentScope get() = if (scopeStack.size < 2) null else scopeStack[scopeStack.size - 2]
+ protected val allScopes get() = scopeStack
+
+ fun printScopeStack() {
+ scopeStack.forEach { println(it.scope.scopeOwner) }
+ }
+
+ open fun visitFileNew(declaration: IrFile): IrFile {
+ return super.visitFile(declaration)
+ }
+
+ open fun visitClassNew(declaration: IrClass): IrStatement {
+ return super.visitClass(declaration)
+ }
+
+ open fun visitFunctionNew(declaration: IrFunction): IrStatement {
+ return super.visitFunction(declaration)
+ }
+
+ open fun visitPropertyNew(declaration: IrProperty): IrStatement {
+ return super.visitProperty(declaration)
+ }
+
+ open fun visitFieldNew(declaration: IrField): IrStatement {
+ return super.visitField(declaration)
+ }
+}
+
+abstract internal class IrElementVisitorVoidWithContext : IrElementVisitorVoid {
+
+ private val scopeStack = mutableListOf()
+
+ override final fun visitFile(declaration: IrFile) {
+ scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
+ visitFileNew(declaration)
+ scopeStack.pop()
+ }
+
+ override final fun visitClass(declaration: IrClass) {
+ scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
+ visitClassNew(declaration)
+ scopeStack.pop()
+ }
+
+ override final fun visitProperty(declaration: IrProperty) {
+ scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
+ visitPropertyNew(declaration)
+ scopeStack.pop()
+ }
+
+ override final fun visitField(declaration: IrField) {
+ val isDelegated = declaration.descriptor.isDelegated
+ if (isDelegated) scopeStack.push(ScopeWithIr(Scope(declaration.symbol), declaration))
+ visitFieldNew(declaration)
+ if (isDelegated) scopeStack.pop()
+ }
+
+ override final fun visitFunction(declaration: IrFunction) {
+ scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
+ visitFunctionNew(declaration)
+ scopeStack.pop()
+ }
+
+ protected val currentFile get() = scopeStack.lastOrNull { it.scope.scopeOwner is PackageFragmentDescriptor }
+ protected val currentClass get() = scopeStack.lastOrNull { it.scope.scopeOwner is ClassDescriptor }
+ protected val currentFunction get() = scopeStack.lastOrNull { it.scope.scopeOwner is FunctionDescriptor }
+ protected val currentProperty get() = scopeStack.lastOrNull { it.scope.scopeOwner is PropertyDescriptor }
+ protected val currentScope get() = scopeStack.peek()
+ protected val parentScope get() = if (scopeStack.size < 2) null else scopeStack[scopeStack.size - 2]
+
+ fun printScopeStack() {
+ scopeStack.forEach { println(it.scope.scopeOwner) }
+ }
+
+ open fun visitFileNew(declaration: IrFile) {
+ super.visitFile(declaration)
+ }
+
+ open fun visitClassNew(declaration: IrClass) {
+ super.visitClass(declaration)
+ }
+
+ open fun visitFunctionNew(declaration: IrFunction) {
+ super.visitFunction(declaration)
+ }
+
+ open fun visitPropertyNew(declaration: IrProperty) {
+ super.visitProperty(declaration)
+ }
+
+ open fun visitFieldNew(declaration: IrField) {
+ super.visitField(declaration)
+ }
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrValidator.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrValidator.kt
new file mode 100644
index 00000000000..6457f235a87
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/IrValidator.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.backend.common
+
+import org.jetbrains.kotlin.ir.IrElement
+import org.jetbrains.kotlin.ir.declarations.*
+import org.jetbrains.kotlin.ir.util.render
+import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
+import org.jetbrains.kotlin.ir.visitors.acceptVoid
+
+fun validateIrFile(context: CommonBackendContext, irFile: IrFile) {
+ val visitor = IrValidator(context, false)
+ irFile.acceptVoid(visitor)
+}
+
+fun validateIrModule(context: CommonBackendContext, irModule: IrModuleFragment) {
+ val visitor = IrValidator(context, true) // TODO: consider taking the boolean from settings.
+ irModule.acceptVoid(visitor)
+
+ // TODO: also check that all referenced symbol targets are reachable.
+}
+
+private fun CommonBackendContext.reportIrValidationError(message: String, irFile: IrFile, irElement: IrElement) {
+ try {
+ this.reportWarning("[IR VALIDATION] $message", irFile, irElement)
+ } catch (e: Throwable) {
+ println("an error trying to print a warning message: $e")
+ e.printStackTrace()
+ }
+ // TODO: throw an exception after fixing bugs leading to invalid IR.
+}
+
+private class IrValidator(val context: CommonBackendContext, performHeavyValidations: Boolean) : IrElementVisitorVoid {
+
+ val builtIns = context.builtIns
+ lateinit var currentFile: IrFile
+
+ override fun visitFile(declaration: IrFile) {
+ currentFile = declaration
+ super.visitFile(declaration)
+ }
+
+ private fun error(element: IrElement, message: String) {
+ // TODO: render all element's parents.
+ context.reportIrValidationError(
+ "$message\n" +
+ element.render(),
+ currentFile, element)
+ }
+
+ private val elementChecker = CheckIrElementVisitor(builtIns, this::error, performHeavyValidations)
+
+ override fun visitElement(element: IrElement) {
+ element.acceptVoid(elementChecker)
+ element.acceptChildrenVoid(this)
+ }
+}
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/TailRecursionCallsCollector.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/TailRecursionCallsCollector.kt
new file mode 100644
index 00000000000..66e1e4e3e6f
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/TailRecursionCallsCollector.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.backend.common
+
+import org.jetbrains.kotlin.ir.IrElement
+import org.jetbrains.kotlin.ir.declarations.IrClass
+import org.jetbrains.kotlin.ir.declarations.IrFunction
+import org.jetbrains.kotlin.ir.expressions.*
+import org.jetbrains.kotlin.ir.util.usesDefaultArguments
+import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
+import org.jetbrains.kotlin.resolve.DescriptorUtils
+import org.jetbrains.kotlin.types.typeUtil.isUnit
+
+/**
+ * Collects calls to be treated as tail recursion.
+ * The checks are partially based on the frontend implementation
+ * in `ControlFlowInformationProvider.markAndCheckRecursiveTailCalls()`.
+ *
+ * This analysis is not very precise and can miss some calls.
+ * It is also not guaranteed that each returned call is detected as tail recursion by the frontend.
+ * However any returned call can be correctly optimized as tail recursion.
+ */
+fun collectTailRecursionCalls(irFunction: IrFunction): Set {
+ if (!irFunction.descriptor.isTailrec) {
+ return emptySet()
+ }
+
+ val result = mutableSetOf()
+
+ val visitor = object : IrElementVisitor {
+
+ override fun visitElement(element: IrElement, data: ElementKind) {
+ val childKind = ElementKind.NOT_SURE // Not sure by default.
+ element.acceptChildren(this, childKind)
+ }
+
+ override fun visitFunction(declaration: IrFunction, data: ElementKind) {
+ // Ignore local functions.
+ }
+
+ override fun visitClass(declaration: IrClass, data: ElementKind) {
+ // Ignore local classes.
+ }
+
+ override fun visitTry(aTry: IrTry, data: ElementKind) {
+ // We do not support tail calls in try-catch-finally, for simplicity of the mental model
+ // very few cases there would be real tail-calls, and it's often not so easy for the user to see why
+ }
+
+ override fun visitReturn(expression: IrReturn, data: ElementKind) {
+ val valueKind = if (expression.returnTarget == irFunction.descriptor) {
+ ElementKind.TAIL_STATEMENT
+ } else {
+ ElementKind.NOT_SURE
+ }
+ expression.value.accept(this, valueKind)
+ }
+
+ override fun visitContainerExpression(expression: IrContainerExpression, data: ElementKind) {
+ expression.statements.forEachIndexed { index, irStatement ->
+ val statementKind = if (index == expression.statements.lastIndex) {
+ // The last statement defines the result of the container expression, so it has the same kind.
+ data
+ } else {
+ ElementKind.NOT_SURE
+ }
+ irStatement.accept(this, statementKind)
+ }
+ }
+
+ override fun visitWhen(expression: IrWhen, data: ElementKind) {
+ expression.branches.forEach {
+ it.condition.accept(this, ElementKind.NOT_SURE)
+ it.result.accept(this, data)
+ }
+ }
+
+ override fun visitCall(expression: IrCall, data: ElementKind) {
+ expression.acceptChildren(this, ElementKind.NOT_SURE)
+
+ // Is it a tail call?
+ if (data != ElementKind.TAIL_STATEMENT) {
+ return
+ }
+
+ // Is it a recursive call?
+ if (expression.descriptor.original != irFunction.descriptor) {
+ return
+ }
+ // TODO: check type arguments
+
+ if (DescriptorUtils.isOverride(irFunction.descriptor) && expression.usesDefaultArguments()) {
+ // Overridden functions using default arguments at tail call are not included: KT-4285
+ return
+ }
+
+ expression.dispatchReceiver?.let {
+ if (it !is IrGetValue || it.descriptor != irFunction.descriptor.dispatchReceiverParameter) {
+ // A tail call is not allowed to change dispatch receiver
+ // class C {
+ // fun foo(other: C) {
+ // other.foo(this) // not a tail call
+ // }
+ // }
+ return
+ }
+ }
+
+ result.add(expression)
+
+ }
+
+ }
+
+ val body = irFunction.body
+ if (body !is IrBlockBody) {
+ return emptySet() // TODO: should an assert be here instead?
+ }
+
+ body.statements.forEachIndexed { index, irStatement ->
+ val kind = if (index == body.statements.lastIndex && irFunction.descriptor.returnType?.isUnit() == true) {
+ ElementKind.TAIL_STATEMENT
+ } else {
+ ElementKind.NOT_SURE
+ }
+ irStatement.accept(visitor, kind)
+ }
+
+ return result
+}
+
+/**
+ * The kind of IR element used to detect tail calls.
+ */
+private enum class ElementKind {
+ /**
+ * This element is the last statement to be executed before the return from the function.
+ * If the return type is not `Unit`, the result of this statement defines the result of the entire function.
+ */
+ TAIL_STATEMENT,
+
+ /**
+ * Not sure if the element meets the requirements to be [TAIL_STATEMENT].
+ */
+ NOT_SURE
+}
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Utils.kt
new file mode 100644
index 00000000000..eaa9236628b
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/Utils.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.backend.common
+
+import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
+import org.jetbrains.kotlin.ir.IrElement
+import org.jetbrains.kotlin.ir.declarations.IrFile
+import org.jetbrains.kotlin.ir.util.getCompilerMessageLocation
+
+fun CommonBackendContext.reportWarning(message: String, irFile: IrFile, irElement: IrElement) {
+ val location = irElement.getCompilerMessageLocation(irFile)
+ messageCollector.report(CompilerMessageSeverity.WARNING, message, location)
+}
+
+fun MutableList.push(element: E) = this.add(element)
+
+fun MutableList.pop() = this.removeAt(size - 1)
+
+fun MutableList.peek(): E? = if (size == 0) null else this[size - 1]
+
+fun Collection.atMostOne(): T? {
+ return when (this.size) {
+ 0 -> null
+ 1 -> this.iterator().next()
+ else -> throw IllegalArgumentException("Collection has more than one element.")
+ }
+}
+
+inline fun Iterable.atMostOne(predicate: (T) -> Boolean): T? = this.filter(predicate).atMostOne()
+
+fun T.onlyIf(condition: T.()->Boolean, then: (T)->Unit): T {
+ if (this.condition()) then(this)
+ return this
+}
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt
new file mode 100644
index 00000000000..ba40b8a7369
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/DescriptorUtils.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.backend.common.descriptors
+
+import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
+import org.jetbrains.kotlin.builtins.getFunctionalClassKind
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.incremental.components.NoLookupLocation
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.TypeProjectionImpl
+import org.jetbrains.kotlin.types.TypeSubstitutor
+import org.jetbrains.kotlin.types.replace
+
+val CallableDescriptor.isSuspend: Boolean
+ get() = this is FunctionDescriptor && isSuspend
+
+/**
+ * @return naturally-ordered list of all parameters available inside the function body.
+ */
+val CallableDescriptor.allParameters: List
+ get() = if (this is ConstructorDescriptor) {
+ listOf(this.constructedClass.thisAsReceiverParameter) + explicitParameters
+ } else {
+ explicitParameters
+ }
+
+/**
+ * @return naturally-ordered list of the parameters that can have values specified at call site.
+ */
+val CallableDescriptor.explicitParameters: List
+ get() {
+ val result = ArrayList(valueParameters.size + 2)
+
+ this.dispatchReceiverParameter?.let {
+ result.add(it)
+ }
+
+ this.extensionReceiverParameter?.let {
+ result.add(it)
+ }
+
+ result.addAll(valueParameters)
+
+ return result
+ }
+
+fun KotlinType.replace(types: List) = this.replace(types.map(::TypeProjectionImpl))
+
+fun FunctionDescriptor.substitute(vararg types: KotlinType): FunctionDescriptor {
+ val typeSubstitutor = TypeSubstitutor.create(
+ typeParameters
+ .withIndex()
+ .associateBy({ it.value.typeConstructor }, { TypeProjectionImpl(types[it.index]) })
+ )
+ return substitute(typeSubstitutor)!!
+}
+
+fun FunctionDescriptor.substitute(typeArguments: Map): FunctionDescriptor {
+ val typeSubstitutor = TypeSubstitutor.create(
+ typeParameters.associateBy({ it.typeConstructor }, { TypeProjectionImpl(typeArguments[it]!!) })
+ )
+ return substitute(typeSubstitutor)!!
+}
+
+fun ClassDescriptor.getFunction(name: String, types: List): FunctionDescriptor {
+ val typeSubstitutor = TypeSubstitutor.create(
+ declaredTypeParameters
+ .withIndex()
+ .associateBy({ it.value.typeConstructor }, { TypeProjectionImpl(types[it.index]) })
+ )
+ return unsubstitutedMemberScope
+ .getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).single().substitute(typeSubstitutor)!!
+}
+
+val KotlinType.isFunctionOrKFunctionType: Boolean
+ get() {
+ val kind = constructor.declarationDescriptor?.getFunctionalClassKind()
+ return kind == FunctionClassDescriptor.Kind.Function || kind == FunctionClassDescriptor.Kind.KFunction
+ }
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/utils.kt
new file mode 100644
index 00000000000..16b4c60c40a
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/descriptors/utils.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.backend.common.descriptors
+
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.incremental.components.NoLookupLocation
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
+import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
+import org.jetbrains.kotlin.types.KotlinType
+
+fun ClassDescriptor?.getter2Descriptor(methodName: Name) = this?.let {
+ this.unsubstitutedMemberScope.getContributedDescriptors{true}
+ .firstOrNull {
+ it.name == methodName
+ } ?.let {
+ return@let (it as? PropertyDescriptor)?.getter
+ }
+}
+
+fun ClassDescriptor?.signature2Descriptor(methodName: Name, signature:Array = emptyArray()) = this?.let {
+ this
+ .unsubstitutedMemberScope
+ .getContributedFunctions(methodName, NoLookupLocation.FROM_BACKEND)
+ .firstOrNull {
+ return@firstOrNull it.valueParameters.size == signature.size
+ && (signature.isEmpty() || it.valueParameters.any {
+ p -> val index = it.valueParameters.indexOf(p)
+ return@any p.type == signature[index]
+ })
+ }
+}
+
+val String.synthesizedName get() = Name.identifier(this.synthesizedString)
+
+val String.synthesizedString get() = "\$$this"
+
+val DeclarationDescriptor.propertyIfAccessor
+ get() = if (this is PropertyAccessorDescriptor)
+ this.correspondingProperty
+ else this
+
+val CallableMemberDescriptor.propertyIfAccessor
+ get() = if (this is PropertyAccessorDescriptor)
+ this.correspondingProperty
+ else this
+
+val FunctionDescriptor.deserializedPropertyIfAccessor: DeserializedCallableMemberDescriptor
+ get() {
+ val member = this.propertyIfAccessor
+ if (member is DeserializedCallableMemberDescriptor)
+ return member
+ else
+ error("Unexpected deserializable callable descriptor")
+ }
+
+val CallableMemberDescriptor.isDeserializableCallable
+ get () = (this.propertyIfAccessor is DeserializedCallableMemberDescriptor)
\ No newline at end of file
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt
new file mode 100644
index 00000000000..6c5d44343b4
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/Ir.kt
@@ -0,0 +1,236 @@
+package org.jetbrains.kotlin.backend.common.ir
+
+import org.jetbrains.kotlin.backend.common.CommonBackendContext
+import org.jetbrains.kotlin.builtins.KotlinBuiltIns
+import org.jetbrains.kotlin.builtins.PrimitiveType
+import org.jetbrains.kotlin.descriptors.ClassDescriptor
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.incremental.components.NoLookupLocation
+import org.jetbrains.kotlin.ir.declarations.IrFunction
+import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
+import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
+import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
+import org.jetbrains.kotlin.ir.util.SymbolTable
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.util.OperatorNameConventions
+
+// This is what Context collects about IR.
+abstract class Ir(val context: T, val irModule: IrModuleFragment) {
+
+ abstract val symbols: Symbols
+
+ val defaultParameterDeclarationsCache = mutableMapOf()
+
+ open fun shouldGenerateHandlerParameterForDefaultBodyFun() = false
+}
+
+open class Symbols(val context: T, private val symbolTable: SymbolTable) {
+
+ private val builtIns
+ get() = context.builtIns
+
+ private fun builtInsPackage(vararg packageNameSegments: String) =
+ context.builtIns.builtInsModule.getPackage(FqName.fromSegments(listOf(*packageNameSegments))).memberScope
+
+ val refClass = symbolTable.referenceClass(context.getInternalClass("Ref"))
+
+// val areEqualByValue = context.getInternalFunctions("areEqualByValue").map {
+// symbolTable.referenceSimpleFunction(it)
+// }
+
+ val areEqual = symbolTable.referenceSimpleFunction(context.getInternalFunctions("areEqual").single())
+
+ val ThrowNullPointerException = symbolTable.referenceSimpleFunction(
+ context.getInternalFunctions("ThrowNullPointerException").single())
+
+ val ThrowNoWhenBranchMatchedException = symbolTable.referenceSimpleFunction(
+ context.getInternalFunctions("ThrowNoWhenBranchMatchedException").single())
+
+ val ThrowTypeCastException = symbolTable.referenceSimpleFunction(
+ context.getInternalFunctions("ThrowTypeCastException").single())
+
+ val ThrowUninitializedPropertyAccessException = symbolTable.referenceSimpleFunction(
+ context.getInternalFunctions("ThrowUninitializedPropertyAccessException").single()
+ )
+
+ val stringBuilder = symbolTable.referenceClass(
+ context.getClass(FqName("java.lang.StringBuilder")) as ClassDescriptor
+ )
+
+ val iterator = symbolTable.referenceClass(
+ builtInsPackage("kotlin", "collections").getContributedClassifier(
+ Name.identifier("Iterator"), NoLookupLocation.FROM_BACKEND
+ ) as ClassDescriptor)
+
+ val asserts = builtInsPackage("kotlin")
+ .getContributedFunctions(Name.identifier("assert"), NoLookupLocation.FROM_BACKEND)
+ .map { symbolTable.referenceFunction(it) }
+
+ private fun progression(name: String) = symbolTable.referenceClass(
+ builtInsPackage("kotlin", "ranges").getContributedClassifier(
+ Name.identifier(name), NoLookupLocation.FROM_BACKEND
+ ) as ClassDescriptor
+ )
+
+ val charProgression = progression("CharProgression")
+ val intProgression = progression("IntProgression")
+ val longProgression = progression("LongProgression")
+ val progressionClasses = listOf(charProgression, intProgression, longProgression)
+ val progressionClassesTypes = progressionClasses.map { it.descriptor.defaultType }.toSet()
+
+ val checkProgressionStep = context.getInternalFunctions("checkProgressionStep")
+ .map { Pair(it.returnType, symbolTable.referenceSimpleFunction(it)) }.toMap()
+ val getProgressionLast = context.getInternalFunctions("getProgressionLast")
+ .map { Pair(it.returnType, symbolTable.referenceSimpleFunction(it)) }.toMap()
+
+ val defaultConstructorMarker = symbolTable.referenceClass(context.getInternalClass("DefaultConstructorMarker"))
+
+ val any = symbolTable.referenceClass(builtIns.any)
+ val unit = symbolTable.referenceClass(builtIns.unit)
+
+ val char = symbolTable.referenceClass(builtIns.char)
+
+ val byte = symbolTable.referenceClass(builtIns.byte)
+ val short = symbolTable.referenceClass(builtIns.short)
+ val int = symbolTable.referenceClass(builtIns.int)
+ val long = symbolTable.referenceClass(builtIns.long)
+
+ val integerClasses = listOf(byte, short, int, long)
+ val integerClassesTypes = integerClasses.map { it.descriptor.defaultType }
+
+ val arrayOf = symbolTable.referenceSimpleFunction(
+ builtInsPackage("kotlin").getContributedFunctions(
+ Name.identifier("arrayOf"), NoLookupLocation.FROM_BACKEND
+ ).single()
+ )
+
+ val array = symbolTable.referenceClass(builtIns.array)
+
+ private fun primitiveArrayClass(type: PrimitiveType) =
+ symbolTable.referenceClass(builtIns.getPrimitiveArrayClassDescriptor(type))
+
+ val byteArray = primitiveArrayClass(PrimitiveType.BYTE)
+ val charArray = primitiveArrayClass(PrimitiveType.CHAR)
+ val shortArray = primitiveArrayClass(PrimitiveType.SHORT)
+ val intArray = primitiveArrayClass(PrimitiveType.INT)
+ val longArray = primitiveArrayClass(PrimitiveType.LONG)
+ val floatArray = primitiveArrayClass(PrimitiveType.FLOAT)
+ val doubleArray = primitiveArrayClass(PrimitiveType.DOUBLE)
+ val booleanArray = primitiveArrayClass(PrimitiveType.BOOLEAN)
+
+ val arrays = PrimitiveType.values().map { primitiveArrayClass(it) } + array
+
+ private fun arrayExtensionFun(type: KotlinType, name: String): IrSimpleFunctionSymbol {
+ val descriptor = builtInsPackage("kotlin")
+ .getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND)
+ .singleOrNull { it.valueParameters.isEmpty()
+ && (it.extensionReceiverParameter?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.defaultType == type }
+ ?: throw Error(type.toString())
+ return symbolTable.referenceSimpleFunction(descriptor)
+ }
+
+
+ private val arrayTypes = arrayOf(
+ builtIns.getPrimitiveArrayKotlinType(PrimitiveType.BYTE),
+ builtIns.getPrimitiveArrayKotlinType(PrimitiveType.CHAR),
+ builtIns.getPrimitiveArrayKotlinType(PrimitiveType.SHORT),
+ builtIns.getPrimitiveArrayKotlinType(PrimitiveType.INT),
+ builtIns.getPrimitiveArrayKotlinType(PrimitiveType.LONG),
+ builtIns.getPrimitiveArrayKotlinType(PrimitiveType.FLOAT),
+ builtIns.getPrimitiveArrayKotlinType(PrimitiveType.DOUBLE),
+ builtIns.getPrimitiveArrayKotlinType(PrimitiveType.BOOLEAN),
+ builtIns.array.defaultType
+ )
+ val arrayContentToString = arrayTypes.associateBy({ it }, { arrayExtensionFun(it, "contentToString") })
+ val arrayContentHashCode = arrayTypes.associateBy({ it }, { arrayExtensionFun(it, "contentHashCode") })
+
+ val copyRangeTo = arrays.map { symbol ->
+ val packageViewDescriptor = builtIns.builtInsModule.getPackage(KotlinBuiltIns.COLLECTIONS_PACKAGE_FQ_NAME)
+ val functionDescriptor = packageViewDescriptor.memberScope
+ .getContributedFunctions(Name.identifier("copyRangeTo"), NoLookupLocation.FROM_BACKEND)
+ .first {
+ it.extensionReceiverParameter?.type?.constructor?.declarationDescriptor == symbol.descriptor
+ }
+ symbol.descriptor to symbolTable.referenceSimpleFunction(functionDescriptor)
+ }.toMap()
+
+ val intAnd = symbolTable.referenceFunction(
+ builtIns.intType.memberScope
+ .getContributedFunctions(OperatorNameConventions.AND, NoLookupLocation.FROM_BACKEND)
+ .single()
+ )
+
+ val intPlusInt = symbolTable.referenceFunction(
+ builtIns.intType.memberScope
+ .getContributedFunctions(OperatorNameConventions.PLUS, NoLookupLocation.FROM_BACKEND)
+ .single {
+ it.valueParameters.single().type == builtIns.intType
+ }
+ )
+
+
+
+ val valuesForEnum = symbolTable.referenceSimpleFunction(
+ context.getInternalFunctions("valuesForEnum").single())
+
+ val valueOfForEnum = symbolTable.referenceSimpleFunction(
+ context.getInternalFunctions("valueOfForEnum").single())
+
+ val getContinuation = symbolTable.referenceSimpleFunction(
+ context.getInternalFunctions("getContinuation").single())
+
+ val coroutineImpl = symbolTable.referenceClass(context.getInternalClass("CoroutineImpl"))
+
+ val coroutineSuspendedGetter = symbolTable.referenceSimpleFunction(
+ builtInsPackage("kotlin", "coroutines", "experimental", "intrinsics")
+ .getContributedVariables(Name.identifier("COROUTINE_SUSPENDED"), NoLookupLocation.FROM_BACKEND)
+ .single().getter!!
+ )
+
+ val kFunctionImpl = symbolTable.referenceClass(context.reflectionTypes.kFunctionImpl)
+
+ val kProperty0Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty0Impl)
+ val kProperty1Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty1Impl)
+ val kProperty2Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty2Impl)
+ val kMutableProperty0Impl = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty0Impl)
+ val kMutableProperty1Impl = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty1Impl)
+ val kMutableProperty2Impl = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty2Impl)
+ val kLocalDelegatedPropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedPropertyImpl)
+ val kLocalDelegatedMutablePropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedMutablePropertyImpl)
+
+ fun getFunction(name: Name, receiverType: KotlinType, vararg argTypes: KotlinType) =
+ symbolTable.referenceFunction(receiverType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND)
+ .single {
+ var i = 0
+ it.valueParameters.size == argTypes.size && it.valueParameters.all { type -> type == argTypes[i++] }
+ }
+ )
+
+ private val binaryOperatorCache = mutableMapOf, IrFunctionSymbol>()
+ fun getBinaryOperator(name: Name, lhsType: KotlinType, rhsType: KotlinType): IrFunctionSymbol {
+ val key = Triple(name, lhsType, rhsType)
+ var result = binaryOperatorCache[key]
+ if (result == null) {
+ result = symbolTable.referenceFunction(lhsType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND)
+ .single { it.valueParameters.size == 1 && it.valueParameters[0].type == rhsType }
+ )
+ binaryOperatorCache[key] = result
+ }
+ return result
+ }
+
+ private val unaryOperatorCache = mutableMapOf, IrFunctionSymbol>()
+ fun getUnaryOperator(name: Name, receiverType: KotlinType): IrFunctionSymbol {
+ val key = name to receiverType
+ var result = unaryOperatorCache[key]
+ if (result == null) {
+ result = symbolTable.referenceFunction(receiverType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND)
+ .single { it.valueParameters.isEmpty() }
+ )
+ unaryOperatorCache[key] = result
+ }
+ return result
+ }
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt
new file mode 100644
index 00000000000..0b71d4ca629
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.backend.common.ir
+
+import org.jetbrains.kotlin.backend.common.CommonBackendContext
+import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.descriptors.annotations.Annotations
+import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
+import org.jetbrains.kotlin.ir.IrElement
+import org.jetbrains.kotlin.ir.declarations.IrClass
+import org.jetbrains.kotlin.ir.declarations.IrConstructor
+import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
+import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
+import org.jetbrains.kotlin.ir.expressions.IrExpression
+import org.jetbrains.kotlin.ir.expressions.impl.*
+import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
+import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor
+import org.jetbrains.kotlin.ir.util.createParameterDeclarations
+import org.jetbrains.kotlin.types.KotlinType
+import org.jetbrains.kotlin.types.TypeProjectionImpl
+import org.jetbrains.kotlin.types.TypeSubstitutor
+import java.io.StringWriter
+
+
+fun ir2string(ir: IrElement?): String = ir2stringWhole(ir).takeWhile { it != '\n' }
+
+fun ir2stringWhole(ir: IrElement?, withDescriptors: Boolean = false): String {
+ val strWriter = StringWriter()
+
+ if (withDescriptors)
+ ir?.accept(DumpIrTreeWithDescriptorsVisitor(strWriter), "")
+ else
+ ir?.accept(DumpIrTreeVisitor(strWriter), "")
+ return strWriter.toString()
+}
+
+fun DeclarationDescriptor.createFakeOverrideDescriptor(owner: ClassDescriptor): DeclarationDescriptor? {
+ // We need to copy descriptors for vtable building, thus take only functions and properties.
+ return when (this) {
+ is CallableMemberDescriptor ->
+ copy(
+ /* newOwner = */ owner,
+ /* modality = */ modality,
+ /* visibility = */ visibility,
+ /* kind = */ CallableMemberDescriptor.Kind.FAKE_OVERRIDE,
+ /* copyOverrides = */ true).apply {
+ overriddenDescriptors += this@createFakeOverrideDescriptor
+ }
+ else -> null
+ }
+}
+
+internal fun FunctionDescriptor.createOverriddenDescriptor(owner: ClassDescriptor, final: Boolean = true): FunctionDescriptor {
+ return this.newCopyBuilder()
+ .setOwner(owner)
+ .setCopyOverrides(true)
+ .setModality(if (final) Modality.FINAL else Modality.OPEN)
+ .setDispatchReceiverParameter(owner.thisAsReceiverParameter)
+ .build()!!.apply {
+ overriddenDescriptors += this@createOverriddenDescriptor
+ }
+}
+
+internal fun ClassDescriptor.createSimpleDelegatingConstructorDescriptor(superConstructorDescriptor: ClassConstructorDescriptor, isPrimary: Boolean = false)
+ : ClassConstructorDescriptor {
+ val constructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
+ /* containingDeclaration = */ this,
+ /* annotations = */ Annotations.EMPTY,
+ /* isPrimary = */ isPrimary,
+ /* source = */ SourceElement.NO_SOURCE)
+ val valueParameters = superConstructorDescriptor.valueParameters.map {
+ it.copy(constructorDescriptor, it.name, it.index)
+ }
+ constructorDescriptor.initialize(valueParameters, superConstructorDescriptor.visibility)
+ constructorDescriptor.returnType = superConstructorDescriptor.returnType
+ return constructorDescriptor
+}
+
+internal fun IrClass.addSimpleDelegatingConstructor(superConstructorSymbol: IrConstructorSymbol,
+ constructorDescriptor: ClassConstructorDescriptor,
+ origin: IrDeclarationOrigin)
+ : IrConstructor {
+
+ return IrConstructorImpl(startOffset, endOffset, origin, constructorDescriptor).also { constructor ->
+ constructor.createParameterDeclarations()
+
+ constructor.body = IrBlockBodyImpl(startOffset, endOffset,
+ listOf(
+ IrDelegatingConstructorCallImpl(
+ startOffset, endOffset,
+ superConstructorSymbol, superConstructorSymbol.descriptor
+ ).apply {
+ constructor.valueParameters.forEachIndexed { idx, parameter ->
+ putValueArgument(idx, IrGetValueImpl(startOffset, endOffset, parameter.symbol))
+ }
+ },
+ IrInstanceInitializerCallImpl(startOffset, endOffset, this.symbol)
+ )
+ )
+
+ this.declarations.add(constructor)
+ }
+}
+
+internal fun CommonBackendContext.createArrayOfExpression(arrayElementType: KotlinType,
+ arrayElements: List,
+ startOffset: Int, endOffset: Int): IrExpression {
+
+ val genericArrayOfFunSymbol = ir.symbols.arrayOf
+ val genericArrayOfFun = genericArrayOfFunSymbol.descriptor
+ val typeParameter0 = genericArrayOfFun.typeParameters[0]
+ val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameter0.typeConstructor to TypeProjectionImpl(arrayElementType)))
+ val substitutedArrayOfFun = genericArrayOfFun.substitute(typeSubstitutor)!!
+
+ val typeArguments = mapOf(typeParameter0 to arrayElementType)
+
+ val valueParameter0 = substitutedArrayOfFun.valueParameters[0]
+ val arg0VarargType = valueParameter0.type
+ val arg0VarargElementType = valueParameter0.varargElementType!!
+ val arg0 = IrVarargImpl(startOffset, endOffset, arg0VarargType, arg0VarargElementType, arrayElements)
+
+ return IrCallImpl(startOffset, endOffset, genericArrayOfFunSymbol, substitutedArrayOfFun, typeArguments).apply {
+ putValueArgument(0, arg0)
+ }
+}
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/IrBuilders.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/IrBuilders.kt
new file mode 100644
index 00000000000..58f14aa16f8
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/builders/IrBuilders.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.ir.builders
+
+import org.jetbrains.kotlin.backend.common.descriptors.substitute
+import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
+import org.jetbrains.kotlin.ir.expressions.IrExpression
+import org.jetbrains.kotlin.ir.expressions.IrLoop
+import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
+import org.jetbrains.kotlin.ir.expressions.impl.*
+import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
+import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
+import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
+import org.jetbrains.kotlin.ir.util.defaultType
+import org.jetbrains.kotlin.types.KotlinType
+
+fun IrBuilderWithScope.irWhile(origin: IrStatementOrigin? = null) =
+ IrWhileLoopImpl(startOffset, endOffset, context.builtIns.unitType, origin)
+
+fun IrBuilderWithScope.irBreak(loop: IrLoop) =
+ IrBreakImpl(startOffset, endOffset, context.builtIns.nothingType, loop)
+
+fun IrBuilderWithScope.irContinue(loop: IrLoop) =
+ IrContinueImpl(startOffset, endOffset, context.builtIns.nothingType, loop)
+
+fun IrBuilderWithScope.irTrue() = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType, true)
+
+fun IrBuilderWithScope.irFalse() = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType, false)
+
+fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol, typeArguments: Map) =
+ IrCallImpl(this.startOffset, this.endOffset, symbol, symbol.descriptor.substitute(typeArguments), typeArguments)
+
+fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol, typeArguments: List) =
+ irCall(symbol, symbol.descriptor.typeParameters.zip(typeArguments).toMap())
+
+fun IrBuilderWithScope.irGetObject(classSymbol: IrClassSymbol) =
+ IrGetObjectValueImpl(startOffset, endOffset, classSymbol.owner.defaultType, classSymbol)
+
+fun IrBuilderWithScope.irGetField(receiver: IrExpression?, symbol: IrFieldSymbol) =
+ IrGetFieldImpl(startOffset, endOffset, symbol, receiver)
\ No newline at end of file
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrUtils.kt
new file mode 100644
index 00000000000..72631e12ad4
--- /dev/null
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrUtils.kt
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.ir.util
+
+import org.jetbrains.kotlin.backend.common.atMostOne
+import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.ir.IrElement
+import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
+import org.jetbrains.kotlin.ir.declarations.*
+import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
+import org.jetbrains.kotlin.ir.declarations.impl.IrPropertyImpl
+import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
+import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
+import org.jetbrains.kotlin.ir.expressions.*
+import org.jetbrains.kotlin.ir.symbols.*
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.psi.psiUtil.endOffset
+import org.jetbrains.kotlin.psi.psiUtil.startOffset
+import org.jetbrains.kotlin.resolve.source.PsiSourceElement
+import org.jetbrains.kotlin.types.KotlinType
+
+/**
+ * Binds the arguments explicitly represented in the IR to the parameters of the accessed function.
+ * The arguments are to be evaluated in the same order as they appear in the resulting list.
+ */
+fun IrMemberAccessExpression.getArguments(): List> {
+ val res = mutableListOf>()
+ val descriptor = descriptor
+
+ // TODO: ensure the order below corresponds to the one defined in Kotlin specs.
+
+ dispatchReceiver?.let {
+ res += (descriptor.dispatchReceiverParameter!! to it)
+ }
+
+ extensionReceiver?.let {
+ res += (descriptor.extensionReceiverParameter!! to it)
+ }
+
+ descriptor.valueParameters.forEach {
+ val arg = getValueArgument(it.index)
+ if (arg != null) {
+ res += (it to arg)
+ }
+ }
+
+ return res
+}
+
+/**
+ * Binds the arguments explicitly represented in the IR to the parameters of the accessed function.
+ * The arguments are to be evaluated in the same order as they appear in the resulting list.
+ */
+internal fun IrFunctionAccessExpression.getArgumentsWithSymbols(): List> {
+ val res = mutableListOf>()
+ val irFunction = symbol.owner as IrFunction
+
+ dispatchReceiver?.let {
+ res += (irFunction.dispatchReceiverParameter!!.symbol to it)
+ }
+
+ extensionReceiver?.let {
+ res += (irFunction.extensionReceiverParameter!!.symbol to it)
+ }
+
+ irFunction.valueParameters.forEach {
+ val arg = getValueArgument(it.descriptor as ValueParameterDescriptor)
+ if (arg != null) {
+ res += (it.symbol to arg)
+ }
+ }
+
+ return res
+}
+
+/**
+ * Sets arguments that are specified by given mapping of parameters.
+ */
+internal fun IrMemberAccessExpression.addArguments(args: Map) {
+ descriptor.dispatchReceiverParameter?.let {
+ val arg = args[it]
+ if (arg != null) {
+ this.dispatchReceiver = arg
+ }
+ }
+
+ descriptor.extensionReceiverParameter?.let {
+ val arg = args[it]
+ if (arg != null) {
+ this.extensionReceiver = arg
+ }
+ }
+
+ descriptor.valueParameters.forEach {
+ val arg = args[it]
+ if (arg != null) {
+ this.putValueArgument(it.index, arg)
+ }
+ }
+}
+
+internal fun IrMemberAccessExpression.addArguments(args: List>) =
+ this.addArguments(args.toMap())
+
+internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrConstKind.Null
+
+fun IrCall.usesDefaultArguments(): Boolean =
+ this.descriptor.valueParameters.any { this.getValueArgument(it) == null }
+
+fun IrElement.getCompilerMessageLocation(containingFile: IrFile): CompilerMessageLocation? {
+ val sourceRangeInfo = containingFile.fileEntry.getSourceRangeInfo(this.startOffset, this.endOffset)
+ return CompilerMessageLocation.create(
+ path = sourceRangeInfo.filePath,
+ line = sourceRangeInfo.startLineNumber,
+ column = sourceRangeInfo.startColumnNumber,
+ lineContent = null // TODO: retrieve the line content.
+ )
+}
+
+fun IrFunction.createParameterDeclarations() {
+ fun ParameterDescriptor.irValueParameter() = IrValueParameterImpl(
+ innerStartOffset(this), innerEndOffset(this),
+ IrDeclarationOrigin.DEFINED,
+ this
+ )
+
+ dispatchReceiverParameter = descriptor.dispatchReceiverParameter?.irValueParameter()
+ extensionReceiverParameter = descriptor.extensionReceiverParameter?.irValueParameter()
+
+ assert(valueParameters.isEmpty())
+ descriptor.valueParameters.mapTo(valueParameters) { it.irValueParameter() }
+
+ assert(typeParameters.isEmpty())
+ descriptor.typeParameters.mapTo(typeParameters) {
+ IrTypeParameterImpl(
+ innerStartOffset(it), innerEndOffset(it),
+ IrDeclarationOrigin.DEFINED,
+ it
+ )
+ }
+}
+
+fun IrClass.createParameterDeclarations() {
+ descriptor.thisAsReceiverParameter.let {
+ thisReceiver = IrValueParameterImpl(
+ innerStartOffset(it), innerEndOffset(it),
+ IrDeclarationOrigin.INSTANCE_RECEIVER,
+ it
+ )
+ }
+
+ assert(typeParameters.isEmpty())
+ descriptor.declaredTypeParameters.mapTo(typeParameters) {
+ IrTypeParameterImpl(
+ innerStartOffset(it), innerEndOffset(it),
+ IrDeclarationOrigin.DEFINED,
+ it
+ )
+ }
+}
+
+fun IrClass.addFakeOverrides() {
+
+ val startOffset = this.startOffset
+ val endOffset = this.endOffset
+
+ fun FunctionDescriptor.createFunction(): IrFunction = IrFunctionImpl(
+ startOffset, endOffset,
+ IrDeclarationOrigin.FAKE_OVERRIDE, this
+ ).apply {
+ createParameterDeclarations()
+ }
+
+ descriptor.unsubstitutedMemberScope.getContributedDescriptors()
+ .filterIsInstance()
+ .filter { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE }
+ .mapTo(this.declarations) {
+ when (it) {
+ is FunctionDescriptor -> it.createFunction()
+ is PropertyDescriptor ->
+ IrPropertyImpl(startOffset, endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, it).apply {
+ // TODO: add field if getter is missing?
+ getter = it.getter?.createFunction()
+ setter = it.setter?.createFunction()
+ }
+ else -> TODO(it.toString())
+ }
+ }
+}
+
+private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int =
+ descriptor.startOffset ?: this.startOffset
+
+private fun IrElement.innerEndOffset(descriptor: DeclarationDescriptorWithSource): Int =
+ descriptor.endOffset ?: this.endOffset
+
+val DeclarationDescriptorWithSource.startOffset: Int? get() = (this.source as? PsiSourceElement)?.psi?.startOffset
+val DeclarationDescriptorWithSource.endOffset: Int? get() = (this.source as? PsiSourceElement)?.psi?.endOffset
+
+val DeclarationDescriptorWithSource.startOffsetOrUndefined: Int get() = startOffset ?: UNDEFINED_OFFSET
+val DeclarationDescriptorWithSource.endOffsetOrUndefined: Int get() = endOffset ?: UNDEFINED_OFFSET
+
+val IrClassSymbol.functions: Sequence
+ get() = this.owner.declarations.asSequence().filterIsInstance().map { it.symbol }
+
+val IrClassSymbol.constructors: Sequence
+ get() = this.owner.declarations.asSequence().filterIsInstance().map { it.symbol }
+
+private fun IrClassSymbol.getPropertyDeclaration(name: String) =
+ this.owner.declarations.filterIsInstance()
+ .atMostOne { it.descriptor.name == Name.identifier(name) }
+
+fun IrClassSymbol.getPropertyGetter(name: String): IrFunctionSymbol? =
+ this.getPropertyDeclaration(name)?.getter?.symbol
+
+fun IrClassSymbol.getPropertySetter(name: String): IrFunctionSymbol? =
+ this.getPropertyDeclaration(name)?.setter?.symbol
+
+val IrFunction.explicitParameters: List
+ get() = (listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters).map { it.symbol }
+
+val IrValueParameter.type: KotlinType
+ get() = this.descriptor.type
+
+val IrClass.defaultType: KotlinType
+ get() = this.descriptor.defaultType
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt
index 7c2d4595b3d..52bedecc858 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrBlock.kt
@@ -16,6 +16,10 @@
package org.jetbrains.kotlin.ir.expressions
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
+import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
+
interface IrContainerExpression : IrExpression, IrStatementContainer {
val origin: IrStatementOrigin?
val isTransparentScope: Boolean
@@ -30,3 +34,9 @@ interface IrComposite : IrContainerExpression {
override val isTransparentScope: Boolean
get() = true
}
+
+interface IrReturnableBlock: IrBlock, IrSymbolOwner {
+ override val symbol: IrReturnableBlockSymbol
+ val descriptor: FunctionDescriptor
+ val sourceFileName: String
+}
\ No newline at end of file
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrBlockImpl.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrBlockImpl.kt
index dc62e92235b..7fe34ed05f5 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrBlockImpl.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/impl/IrBlockImpl.kt
@@ -16,9 +16,15 @@
package org.jetbrains.kotlin.ir.expressions.impl
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.expressions.IrBlock
+import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
+import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
+import org.jetbrains.kotlin.ir.symbols.impl.IrBindableSymbolBase
+import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
+import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.types.KotlinType
@@ -44,4 +50,44 @@ fun IrBlockImpl.inlineStatement(statement: IrStatement) {
else {
statements.add(statement)
}
+}
+
+
+class IrReturnableBlockImpl(startOffset: Int, endOffset: Int, type: KotlinType,
+ override val symbol: IrReturnableBlockSymbol, origin: IrStatementOrigin? = null, override val sourceFileName: String = "no source file")
+ : IrContainerExpressionBase(startOffset, endOffset, type, origin), IrReturnableBlock {
+ override val descriptor = symbol.descriptor
+
+ constructor(startOffset: Int, endOffset: Int, type: KotlinType,
+ symbol: IrReturnableBlockSymbol, origin: IrStatementOrigin?, statements: List, sourceFileName: String = "no source file") :
+ this(startOffset, endOffset, type, symbol, origin, sourceFileName) {
+ this.statements.addAll(statements)
+ }
+
+ constructor(startOffset: Int, endOffset: Int, type: KotlinType,
+ descriptor: FunctionDescriptor, origin: IrStatementOrigin? = null, sourceFileName: String = "no source file") :
+ this(startOffset, endOffset, type, IrReturnableBlockSymbolImpl(descriptor), origin, sourceFileName)
+
+ constructor(startOffset: Int, endOffset: Int, type: KotlinType,
+ descriptor: FunctionDescriptor, origin: IrStatementOrigin?, statements: List, sourceFileName: String = "no source file") :
+ this(startOffset, endOffset, type, descriptor, origin, sourceFileName) {
+ this.statements.addAll(statements)
+ }
+
+ init {
+ symbol.bind(this)
+ }
+
+ override fun accept(visitor: IrElementVisitor, data: D): R =
+ visitor.visitBlock(this, data)
+
+ override fun acceptChildren(visitor: IrElementVisitor, data: D) {
+ statements.forEach { it.accept(visitor, data) }
+ }
+
+ override fun transformChildren(transformer: IrElementTransformer, data: D) {
+ statements.forEachIndexed { i, irStatement ->
+ statements[i] = irStatement.transform(transformer, data)
+ }
+ }
}
\ No newline at end of file
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrSymbol.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrSymbol.kt
index 4889c5ddf25..d20fdd6c4fe 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrSymbol.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrSymbol.kt
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.ir.symbols
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
+import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
interface IrSymbol {
val owner : IrSymbolOwner
@@ -59,4 +60,6 @@ interface IrFunctionSymbol : IrSymbol {
override val descriptor: FunctionDescriptor
}
interface IrConstructorSymbol : IrFunctionSymbol, IrBindableSymbol
-interface IrSimpleFunctionSymbol : IrFunctionSymbol, IrBindableSymbol
\ No newline at end of file
+interface IrSimpleFunctionSymbol : IrFunctionSymbol, IrBindableSymbol
+
+interface IrReturnableBlockSymbol : IrFunctionSymbol, IrBindableSymbol
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/impl/IrSymbolBase.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/impl/IrSymbolBase.kt
index 4a3737e690d..454f99c77e6 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/impl/IrSymbolBase.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/impl/IrSymbolBase.kt
@@ -17,8 +17,15 @@
package org.jetbrains.kotlin.ir.symbols.impl
import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
+import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
+import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
+import org.jetbrains.kotlin.ir.expressions.impl.IrContainerExpressionBase
import org.jetbrains.kotlin.ir.symbols.*
+import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
+import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
+import org.jetbrains.kotlin.types.KotlinType
abstract class IrSymbolBase(override val descriptor: D) : IrSymbol
@@ -110,4 +117,8 @@ fun createFunctionSymbol(descriptor: CallableMemberDescriptor): IrFunctionSymbol
is ClassConstructorDescriptor -> IrConstructorSymbolImpl(descriptor.original)
is FunctionDescriptor -> IrSimpleFunctionSymbolImpl(descriptor.original)
else -> throw IllegalArgumentException("Unexpected descriptor kind: $descriptor")
- }
\ No newline at end of file
+ }
+
+class IrReturnableBlockSymbolImpl(descriptor: FunctionDescriptor) :
+ IrBindableSymbolBase(descriptor),
+ IrReturnableBlockSymbol
\ No newline at end of file