diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml
index c0cd70c05cd..9709eef0f2a 100644
--- a/.idea/codeStyleSettings.xml
+++ b/.idea/codeStyleSettings.xml
@@ -60,6 +60,9 @@
+
+
+
diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/AbstractClosureAnnotator.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/AbstractClosureAnnotator.kt
index 4d64e8d174b..ae8b5d6dc21 100644
--- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/AbstractClosureAnnotator.kt
+++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/AbstractClosureAnnotator.kt
@@ -28,57 +28,26 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.resolve.DescriptorUtils
import java.util.*
-class Closure(
- val capturedThisReferences: List,
- val capturedReceiverParameters: List,
- val capturedValues: List
-)
+class Closure(val capturedValues: List)
abstract class AbstractClosureAnnotator : IrElementVisitorVoid {
protected abstract fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure)
protected abstract fun recordClassClosure(classDescriptor: ClassDescriptor, closure: Closure)
private class ClosureBuilder(val owner: DeclarationDescriptor) {
- val capturedThisReferences = mutableSetOf()
- val capturedReceiverParameters = mutableSetOf()
val capturedValues = mutableSetOf()
- fun buildClosure() = Closure(
- capturedThisReferences.toList(),
- capturedReceiverParameters.toList(),
- capturedValues.toList()
- )
+ fun buildClosure() = Closure(capturedValues.toList())
fun addNested(closure: Closure) {
- fillInCapturedThisReferences(closure)
- fillInNestedClosure(capturedReceiverParameters, closure.capturedReceiverParameters)
fillInNestedClosure(capturedValues, closure.capturedValues)
}
- private fun fillInCapturedThisReferences(closure: Closure) {
- if (owner is ClassDescriptor) {
- closure.capturedThisReferences.filterTo(capturedThisReferences) { it != owner }
- }
- else if (owner is CallableMemberDescriptor && owner.dispatchReceiverParameter != null) {
- val ownerClass = owner.containingDeclaration as? ClassDescriptor
- closure.capturedThisReferences.filterTo(capturedThisReferences) { it != ownerClass }
- }
- }
-
private fun fillInNestedClosure(destination: MutableSet, nested: List) {
nested.filterTo(destination) {
it.containingDeclaration != owner
}
}
-
- fun addCapturedThis(classDescriptor: ClassDescriptor) {
- if (owner is ClassDescriptor && owner != classDescriptor) {
- capturedThisReferences.add(classDescriptor)
- }
- else if (owner is CallableMemberDescriptor && owner.containingDeclaration != classDescriptor) {
- capturedThisReferences.add(classDescriptor)
- }
- }
}
private val closuresStack = ArrayDeque()
@@ -127,7 +96,8 @@ abstract class AbstractClosureAnnotator : IrElementVisitorVoid {
}
override fun visitVariableAccess(expression: IrValueAccessExpression) {
- val closureBuilder = closuresStack.peek()
+ val closureBuilder = closuresStack.peek() ?: return
+
val variableDescriptor = expression.descriptor
if (variableDescriptor.containingDeclaration != closureBuilder.owner) {
closureBuilder.capturedValues.add(variableDescriptor)
diff --git a/compiler/ir/backend.jvm/backend.jvm.iml b/compiler/ir/backend.jvm/backend.jvm.iml
index fe10d927fa6..f62fe97c7c5 100644
--- a/compiler/ir/backend.jvm/backend.jvm.iml
+++ b/compiler/ir/backend.jvm/backend.jvm.iml
@@ -13,6 +13,7 @@
+
\ No newline at end of file
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt
index e00245e5649..c90afbdd58d 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt
@@ -33,6 +33,7 @@ class JvmLower(val context: JvmBackendContext) {
PropertiesLowering().lower(irFile)
InterfaceLowering(context.state).runOnFile(irFile)
InterfaceDelegationLowering(context.state).runOnFile(irFile)
+ LocalFunctionsLowering(context).runOnFile(irFile)
EnumClassLowering(context).runOnFile(irFile)
ObjectClassLowering(context).runOnFile(irFile)
InitializersLowering(context).runOnFile(irFile)
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt
index e75f8ac3fd4..8371e775160 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt
@@ -312,7 +312,10 @@ class ExpressionCodegen(
}
private fun generateLocal(descriptor: CallableDescriptor, type: Type): StackValue {
- StackValue.local(frame.getIndex(descriptor), type).put(type, mv)
+ val index = frame.getIndex(descriptor).apply {
+ if (this < 0) throw AssertionError("Non-mapped local variable descriptor: $descriptor")
+ }
+ StackValue.local(index, type).put(type, mv)
return onStack(type)
}
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt
index ada65b67cf8..1f5751b40dc 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.declarations.IrFunction
+import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/LocalFunctionsLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/LocalFunctionsLowering.kt
new file mode 100644
index 00000000000..e5244947de6
--- /dev/null
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/LocalFunctionsLowering.kt
@@ -0,0 +1,359 @@
+/*
+ * Copyright 2010-2016 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.jvm.lower
+
+import org.jetbrains.kotlin.backend.common.AbstractClosureAnnotator
+import org.jetbrains.kotlin.backend.common.Closure
+import org.jetbrains.kotlin.backend.jvm.ClassLoweringPass
+import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
+import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
+import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
+import org.jetbrains.kotlin.ir.IrElement
+import org.jetbrains.kotlin.ir.IrStatement
+import org.jetbrains.kotlin.ir.declarations.IrClass
+import org.jetbrains.kotlin.ir.declarations.IrDeclaration
+import org.jetbrains.kotlin.ir.declarations.IrFunction
+import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
+import org.jetbrains.kotlin.ir.expressions.*
+import org.jetbrains.kotlin.ir.expressions.impl.*
+import org.jetbrains.kotlin.ir.util.transformFlat
+import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
+import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
+import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
+import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
+import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.resolve.descriptorUtil.parents
+import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
+import org.jetbrains.kotlin.types.KotlinType
+import java.util.*
+
+class LocalFunctionsLowering(val context: JvmBackendContext): ClassLoweringPass {
+ override fun lower(irClass: IrClass) {
+ irClass.declarations.transformFlat { memberDeclaration ->
+ if (memberDeclaration is IrFunction)
+ LocalFunctionsTransformer(memberDeclaration).lowerLocalFunctions()
+ else
+ null
+ }
+ }
+
+ private class LocalFunctionContext(val declaration: IrFunction) {
+ lateinit var closure: Closure
+
+ val closureParametersCount: Int get() = closure.capturedValues.size
+
+ lateinit var transformedDescriptor: FunctionDescriptor
+
+ val old2new: MutableMap = HashMap()
+
+ var index: Int = -1
+
+ override fun toString(): String =
+ "LocalFunctionContext for ${declaration.descriptor}"
+ }
+
+ private inner class LocalFunctionsTransformer(val memberFunction: IrFunction) {
+ val localFunctions: MutableMap = LinkedHashMap()
+ val new2old: MutableMap = HashMap()
+
+ fun lowerLocalFunctions(): List? {
+ collectLocalFunctions()
+ if (localFunctions.isEmpty()) return null
+
+ collectClosures()
+
+ transformDescriptors()
+
+ rewriteBodies()
+
+ return collectRewrittenDeclarations()
+ }
+
+ private fun collectRewrittenDeclarations(): ArrayList =
+ ArrayList(localFunctions.size + 1).apply {
+ add(memberFunction)
+
+ localFunctions.values.mapTo(this) {
+ val original = it.declaration
+ IrFunctionImpl(
+ original.startOffset, original.endOffset, original.origin,
+ it.transformedDescriptor,
+ original.body
+ )
+ }
+ }
+
+ private inner class FunctionBodiesRewriter(val localFunctionContext: LocalFunctionContext?) : IrElementTransformerVoid() {
+
+ override fun visitClass(declaration: IrClass): IrStatement {
+ // ignore local classes for now
+ return declaration
+ }
+
+ override fun visitFunction(declaration: IrFunction): IrStatement {
+ // replace local function definition with an empty composite
+ return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
+ }
+
+ override fun visitGetValue(expression: IrGetValue): IrExpression {
+ val remapped = localFunctionContext?.let { it.old2new[expression.descriptor] }
+ return if (remapped == null)
+ expression
+ else
+ IrGetValueImpl(expression.startOffset, expression.endOffset, remapped, expression.origin)
+ }
+
+ override fun visitCall(expression: IrCall): IrExpression {
+ expression.transformChildrenVoid(this)
+
+ val oldCallee = expression.descriptor.original
+ val localFunctionData = localFunctions[oldCallee] ?: return expression
+
+ val newCallee = localFunctionData.transformedDescriptor
+
+ val newCall = createNewCall(expression, newCallee).fillArguments(localFunctionData, expression)
+
+ return newCall
+ }
+
+ private fun T.fillArguments(calleeContext: LocalFunctionContext, oldExpression: IrMemberAccessExpression): T {
+ val closureParametersCount = calleeContext.closureParametersCount
+
+ mapValueParametersIndexed { index, newValueParameterDescriptor ->
+ val capturedValueDescriptor = new2old[newValueParameterDescriptor] ?:
+ throw AssertionError("Non-mapped parameter $newValueParameterDescriptor")
+ if (index >= closureParametersCount)
+ oldExpression.getValueArgument(capturedValueDescriptor as ValueParameterDescriptor)
+ else {
+ val remappedValueDescriptor = localFunctionContext?.let { it.old2new[capturedValueDescriptor] }
+ IrGetValueImpl(oldExpression.startOffset, oldExpression.endOffset,
+ remappedValueDescriptor ?: capturedValueDescriptor)
+ }
+
+ }
+
+ dispatchReceiver = oldExpression.dispatchReceiver
+ extensionReceiver = oldExpression.extensionReceiver
+
+ return this
+ }
+
+ override fun visitCallableReference(expression: IrCallableReference): IrExpression {
+ expression.transformChildrenVoid(this)
+
+ val oldCallee = expression.descriptor.original
+ val localFunctionData = localFunctions[oldCallee] ?: return expression
+ val newCallee = localFunctionData.transformedDescriptor
+
+ val newCallableReference = IrCallableReferenceImpl(
+ expression.startOffset, expression.endOffset,
+ expression.type, // TODO functional type for transformed descriptor
+ newCallee,
+ remapTypeArguments(expression, newCallee),
+ expression.origin
+ ).fillArguments(localFunctionData, expression)
+
+ return newCallableReference
+ }
+
+ override fun visitReturn(expression: IrReturn): IrExpression {
+ expression.transformChildrenVoid(this)
+
+ val oldReturnTarget = expression.returnTarget
+ val localFunctionData = localFunctions[oldReturnTarget] ?: return expression
+ val newReturnTarget = localFunctionData.transformedDescriptor
+
+ return IrReturnImpl(expression.startOffset, expression.endOffset, newReturnTarget, expression.value)
+ }
+ }
+
+ private fun rewriteFunctionDeclaration(irFunction: IrFunction, localFunctionContext: LocalFunctionContext?) {
+ irFunction.transformChildrenVoid(FunctionBodiesRewriter(localFunctionContext))
+ }
+
+ private fun rewriteBodies() {
+ localFunctions.values.forEach {
+ rewriteFunctionDeclaration(it.declaration, it)
+ }
+
+ rewriteFunctionDeclaration(memberFunction, null)
+ }
+
+ private fun createNewCall(oldCall: IrCall, newCallee: FunctionDescriptor) =
+ if (oldCall is IrCallWithShallowCopy)
+ oldCall.shallowCopy(oldCall.origin, newCallee, oldCall.superQualifier)
+ else
+ IrCallImpl(
+ oldCall.startOffset, oldCall.endOffset,
+ newCallee,
+ remapTypeArguments(oldCall, newCallee),
+ oldCall.origin, oldCall.superQualifier
+ )
+
+ private fun remapTypeArguments(oldExpression: IrMemberAccessExpression, newCallee: FunctionDescriptor): Map? {
+ val oldCallee = oldExpression.descriptor
+
+ return if (oldCallee.typeParameters.isEmpty())
+ null
+ else oldCallee.typeParameters.associateBy(
+ { newCallee.typeParameters[it.index] },
+ { oldExpression.getTypeArgument(it)!! }
+ )
+ }
+
+ private fun transformDescriptors() {
+ localFunctions.values.forEach {
+ it.transformedDescriptor = createTransformedDescriptor(it)
+ }
+ }
+
+ private fun suggestLocalName(descriptor: DeclarationDescriptor): String {
+ val localFunctionContext = localFunctions[descriptor]
+ return if (localFunctionContext != null && localFunctionContext.index >= 0)
+ "lambda-${localFunctionContext.index}"
+ else
+ descriptor.name.asString()
+ }
+
+ private fun generateNameForLiftedFunction(functionDescriptor: FunctionDescriptor): Name =
+ Name.identifier(
+ functionDescriptor.parentsWithSelf
+ .takeWhile { it is FunctionDescriptor }
+ .toList().reversed()
+ .map { suggestLocalName(it) }
+ .joinToString(separator = "$")
+ )
+
+ private fun createTransformedDescriptor(localFunctionContext: LocalFunctionContext): FunctionDescriptor {
+ val oldDescriptor = localFunctionContext.declaration.descriptor
+
+ val memberOwner = memberFunction.descriptor.containingDeclaration
+ val newDescriptor = SimpleFunctionDescriptorImpl.create(
+ memberOwner,
+ oldDescriptor.annotations,
+ generateNameForLiftedFunction(oldDescriptor),
+ CallableMemberDescriptor.Kind.SYNTHESIZED,
+ oldDescriptor.source
+ )
+
+ val closureParametersCount = localFunctionContext.closureParametersCount
+ val newValueParametersCount = closureParametersCount + oldDescriptor.valueParameters.size
+
+ val newDispatchReceiverParameter =
+ if (memberOwner is ClassDescriptor && oldDescriptor.dispatchReceiverParameter != null)
+ memberOwner.thisAsReceiverParameter
+ else
+ null
+
+ // Do not substitute type parameters for now.
+ val newTypeParameters = oldDescriptor.typeParameters
+
+ val newValueParameters = ArrayList(newValueParametersCount).apply {
+ localFunctionContext.closure.capturedValues.mapIndexedTo(this) { i, capturedValueDescriptor ->
+ createUnsubstitutedCapturedValueParameter(newDescriptor, capturedValueDescriptor, i).apply {
+ localFunctionContext.recordRemapped(capturedValueDescriptor, this)
+ }
+ }
+
+ oldDescriptor.valueParameters.mapIndexedTo(this) { i, oldValueParameterDescriptor ->
+ createUnsubstitutedParameter(newDescriptor, oldValueParameterDescriptor, closureParametersCount + i).apply {
+ localFunctionContext.recordRemapped(oldValueParameterDescriptor, this)
+ }
+ }
+ }
+
+ newDescriptor.initialize(
+ oldDescriptor.extensionReceiverParameter?.type,
+ newDispatchReceiverParameter,
+ newTypeParameters,
+ newValueParameters,
+ oldDescriptor.returnType,
+ Modality.FINAL,
+ Visibilities.PRIVATE
+ )
+
+ return newDescriptor
+ }
+
+ private fun LocalFunctionContext.recordRemapped(oldDescriptor: ValueDescriptor, newDescriptor: ValueParameterDescriptor): ValueParameterDescriptor {
+ old2new[oldDescriptor] = newDescriptor
+ new2old[newDescriptor] = oldDescriptor
+ return newDescriptor
+ }
+
+ private fun createUnsubstitutedCapturedValueParameter(
+ newParameterOwner: CallableMemberDescriptor,
+ valueDescriptor: ValueDescriptor,
+ index: Int
+ ): ValueParameterDescriptor =
+ ValueParameterDescriptorImpl(
+ newParameterOwner, null, index,
+ valueDescriptor.annotations, valueDescriptor.name, valueDescriptor.type,
+ false, false, false, false, null, valueDescriptor.source
+ )
+
+ private fun createUnsubstitutedParameter(
+ newParameterOwner: CallableMemberDescriptor,
+ valueParameterDescriptor: ValueParameterDescriptor,
+ newIndex: Int
+ ): ValueParameterDescriptor =
+ valueParameterDescriptor.copy(newParameterOwner, valueParameterDescriptor.name, newIndex)
+
+
+ private fun collectClosures() {
+ memberFunction.acceptChildrenVoid(object : AbstractClosureAnnotator() {
+ override fun visitClass(declaration: IrClass) {
+ // ignore local classes for now
+ return
+ }
+
+ override fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure) {
+ localFunctions[functionDescriptor]?.closure = closure
+ }
+
+ override fun recordClassClosure(classDescriptor: ClassDescriptor, closure: Closure) {
+ // ignore local classes for now
+ }
+ })
+ }
+
+ private fun collectLocalFunctions() {
+ memberFunction.acceptChildrenVoid(object : IrElementVisitorVoid {
+ var lambdasCount = 0
+
+ override fun visitElement(element: IrElement) {
+ element.acceptChildrenVoid(this)
+ }
+
+ override fun visitFunction(declaration: IrFunction) {
+ declaration.acceptChildrenVoid(this)
+ val localFunctionContext = LocalFunctionContext(declaration)
+ localFunctions[declaration.descriptor] = localFunctionContext
+ if (declaration.descriptor.name.isSpecial) {
+ localFunctionContext.index = lambdasCount++
+ }
+ }
+
+ override fun visitClass(declaration: IrClass) {
+ // ignore local classes for now
+ }
+ })
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalFunctionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalFunctionGenerator.kt
index 3be5da340da..d60e21f035a 100644
--- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalFunctionGenerator.kt
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LocalFunctionGenerator.kt
@@ -41,7 +41,7 @@ class LocalFunctionGenerator(statementGenerator: StatementGenerator) : Statement
irBlock.statements.add(irFun)
irBlock.statements.add(IrCallableReferenceImpl(ktLambda.startOffset, ktLambda.endOffset, lambdaExpressionType,
- lambdaDescriptor, null, IrStatementOrigin.LAMBDA))
+ lambdaDescriptor, null, IrStatementOrigin.LAMBDA))
return irBlock
}
@@ -59,7 +59,7 @@ class LocalFunctionGenerator(statementGenerator: StatementGenerator) : Statement
irBlock.statements.add(irFun)
irBlock.statements.add(IrCallableReferenceImpl(ktFun.startOffset, ktFun.endOffset, funExpressionType,
- irFun.descriptor, null, IrStatementOrigin.ANONYMOUS_FUNCTION))
+ irFun.descriptor, null, IrStatementOrigin.ANONYMOUS_FUNCTION))
irBlock
}
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrMemberAccessExpression.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrMemberAccessExpression.kt
index 90893fb7594..c8279900ecf 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrMemberAccessExpression.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/expressions/IrMemberAccessExpression.kt
@@ -54,3 +54,10 @@ inline fun T.mapValueParameters(transform: (Value
return this
}
+inline fun T.mapValueParametersIndexed(transform: (Int, ValueParameterDescriptor) -> IrExpression?): T {
+ descriptor.valueParameters.forEach {
+ putValueArgument(it.index, transform(it.index, it))
+ }
+ return this
+}
+
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTree.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTree.kt
index f78956d7c88..56050e1e28b 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTree.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTree.kt
@@ -51,7 +51,6 @@ open class DeepCopyIrTree : IrElementTransformerVoid() {
protected open fun mapValueReference(descriptor: ValueDescriptor) = descriptor
protected open fun mapVariableReference(descriptor: VariableDescriptor) = descriptor
protected open fun mapPropertyReference(descriptor: PropertyDescriptor) = descriptor
- protected open fun mapReceiverParameterReference(descriptor: ReceiverParameterDescriptor) = descriptor
protected open fun mapCallee(descriptor: CallableDescriptor) = descriptor
protected open fun mapDelegatedConstructorCallee(descriptor: ClassConstructorDescriptor) = descriptor
protected open fun mapEnumConstructorCallee(descriptor: ClassConstructorDescriptor) = descriptor
diff --git a/compiler/testData/ir/box/closureConversion1.kt b/compiler/testData/ir/box/closureConversion1.kt
new file mode 100644
index 00000000000..486df9872db
--- /dev/null
+++ b/compiler/testData/ir/box/closureConversion1.kt
@@ -0,0 +1,6 @@
+fun foo(x: String): String {
+ fun bar(y: String) = x + y
+ return bar("K")
+}
+
+fun box() = foo("O")
\ No newline at end of file
diff --git a/compiler/testData/ir/box/closureConversion2.kt b/compiler/testData/ir/box/closureConversion2.kt
new file mode 100644
index 00000000000..806aad1fa65
--- /dev/null
+++ b/compiler/testData/ir/box/closureConversion2.kt
@@ -0,0 +1,8 @@
+fun foo(x: X): String {
+ fun bar(y: Y) =
+ x.toString() + y.toString()
+
+ return bar("K")
+}
+
+fun box() = foo("O")
\ No newline at end of file
diff --git a/compiler/testData/ir/box/closureConversion3.kt b/compiler/testData/ir/box/closureConversion3.kt
new file mode 100644
index 00000000000..7f0e7d4647b
--- /dev/null
+++ b/compiler/testData/ir/box/closureConversion3.kt
@@ -0,0 +1,11 @@
+fun foo(x: String): String {
+ fun bar(y: String): String {
+ fun qux(z: String): String =
+ x + y + z
+ return qux("")
+ }
+ return bar("K")
+}
+
+fun box(): String =
+ foo("O")
\ No newline at end of file
diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrOnlyBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrOnlyBoxCodegenTestGenerated.java
index 2b01f478f7e..66f033ee55f 100644
--- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrOnlyBoxCodegenTestGenerated.java
+++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrOnlyBoxCodegenTestGenerated.java
@@ -41,6 +41,24 @@ public class IrOnlyBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTest
doTest(fileName);
}
+ @TestMetadata("closureConversion1.kt")
+ public void testClosureConversion1() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/closureConversion1.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("closureConversion2.kt")
+ public void testClosureConversion2() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/closureConversion2.kt");
+ doTest(fileName);
+ }
+
+ @TestMetadata("closureConversion3.kt")
+ public void testClosureConversion3() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/closureConversion3.kt");
+ doTest(fileName);
+ }
+
@TestMetadata("enumClass.kt")
public void testEnumClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/enumClass.kt");
diff --git a/compiler/tests/org/jetbrains/kotlin/ir/AbstractClosureAnnotatorTestCase.kt b/compiler/tests/org/jetbrains/kotlin/ir/AbstractClosureAnnotatorTestCase.kt
index b639cfeb1d1..471bbcd3aa4 100644
--- a/compiler/tests/org/jetbrains/kotlin/ir/AbstractClosureAnnotatorTestCase.kt
+++ b/compiler/tests/org/jetbrains/kotlin/ir/AbstractClosureAnnotatorTestCase.kt
@@ -66,12 +66,6 @@ abstract class AbstractClosureAnnotatorTestCase : AbstractIrGeneratorTestCase()
}
private fun printClosure(closure: Closure) {
- closure.capturedThisReferences.forEach {
- actualOut.println(" 'this' for ${it.name}")
- }
- closure.capturedReceiverParameters.forEach {
- actualOut.println(" receiver for ${it.containingDeclaration.name}")
- }
closure.capturedValues.forEach {
actualOut.println(" variable ${it.name}")
}