Closure conversion: simple tests work.
This commit is contained in:
Generated
+3
@@ -60,6 +60,9 @@
|
|||||||
<option name="WHILE_BRACE_FORCE" value="1" />
|
<option name="WHILE_BRACE_FORCE" value="1" />
|
||||||
<option name="FOR_BRACE_FORCE" value="1" />
|
<option name="FOR_BRACE_FORCE" value="1" />
|
||||||
<option name="FIELD_ANNOTATION_WRAP" value="0" />
|
<option name="FIELD_ANNOTATION_WRAP" value="0" />
|
||||||
|
<MarkdownNavigatorCodeStyleSettings>
|
||||||
|
<option name="RIGHT_MARGIN" value="72" />
|
||||||
|
</MarkdownNavigatorCodeStyleSettings>
|
||||||
<XML>
|
<XML>
|
||||||
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
|
||||||
</XML>
|
</XML>
|
||||||
|
|||||||
+4
-34
@@ -28,57 +28,26 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
|||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class Closure(
|
class Closure(val capturedValues: List<ValueDescriptor>)
|
||||||
val capturedThisReferences: List<ClassDescriptor>,
|
|
||||||
val capturedReceiverParameters: List<ReceiverParameterDescriptor>,
|
|
||||||
val capturedValues: List<ValueDescriptor>
|
|
||||||
)
|
|
||||||
|
|
||||||
abstract class AbstractClosureAnnotator : IrElementVisitorVoid {
|
abstract class AbstractClosureAnnotator : IrElementVisitorVoid {
|
||||||
protected abstract fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure)
|
protected abstract fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure)
|
||||||
protected abstract fun recordClassClosure(classDescriptor: ClassDescriptor, closure: Closure)
|
protected abstract fun recordClassClosure(classDescriptor: ClassDescriptor, closure: Closure)
|
||||||
|
|
||||||
private class ClosureBuilder(val owner: DeclarationDescriptor) {
|
private class ClosureBuilder(val owner: DeclarationDescriptor) {
|
||||||
val capturedThisReferences = mutableSetOf<ClassDescriptor>()
|
|
||||||
val capturedReceiverParameters = mutableSetOf<ReceiverParameterDescriptor>()
|
|
||||||
val capturedValues = mutableSetOf<ValueDescriptor>()
|
val capturedValues = mutableSetOf<ValueDescriptor>()
|
||||||
|
|
||||||
fun buildClosure() = Closure(
|
fun buildClosure() = Closure(capturedValues.toList())
|
||||||
capturedThisReferences.toList(),
|
|
||||||
capturedReceiverParameters.toList(),
|
|
||||||
capturedValues.toList()
|
|
||||||
)
|
|
||||||
|
|
||||||
fun addNested(closure: Closure) {
|
fun addNested(closure: Closure) {
|
||||||
fillInCapturedThisReferences(closure)
|
|
||||||
fillInNestedClosure(capturedReceiverParameters, closure.capturedReceiverParameters)
|
|
||||||
fillInNestedClosure(capturedValues, closure.capturedValues)
|
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 <T : CallableDescriptor> fillInNestedClosure(destination: MutableSet<T>, nested: List<T>) {
|
private fun <T : CallableDescriptor> fillInNestedClosure(destination: MutableSet<T>, nested: List<T>) {
|
||||||
nested.filterTo(destination) {
|
nested.filterTo(destination) {
|
||||||
it.containingDeclaration != owner
|
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<ClosureBuilder>()
|
private val closuresStack = ArrayDeque<ClosureBuilder>()
|
||||||
@@ -127,7 +96,8 @@ abstract class AbstractClosureAnnotator : IrElementVisitorVoid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitVariableAccess(expression: IrValueAccessExpression) {
|
override fun visitVariableAccess(expression: IrValueAccessExpression) {
|
||||||
val closureBuilder = closuresStack.peek()
|
val closureBuilder = closuresStack.peek() ?: return
|
||||||
|
|
||||||
val variableDescriptor = expression.descriptor
|
val variableDescriptor = expression.descriptor
|
||||||
if (variableDescriptor.containingDeclaration != closureBuilder.owner) {
|
if (variableDescriptor.containingDeclaration != closureBuilder.owner) {
|
||||||
closureBuilder.capturedValues.add(variableDescriptor)
|
closureBuilder.capturedValues.add(variableDescriptor)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<orderEntry type="module" module-name="descriptors" />
|
<orderEntry type="module" module-name="descriptors" />
|
||||||
<orderEntry type="module" module-name="backend" />
|
<orderEntry type="module" module-name="backend" />
|
||||||
<orderEntry type="module" module-name="ir.psi2ir" />
|
<orderEntry type="module" module-name="ir.psi2ir" />
|
||||||
|
<orderEntry type="module" module-name="backend.common" />
|
||||||
<orderEntry type="module" module-name="frontend.java" />
|
<orderEntry type="module" module-name="frontend.java" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
@@ -33,6 +33,7 @@ class JvmLower(val context: JvmBackendContext) {
|
|||||||
PropertiesLowering().lower(irFile)
|
PropertiesLowering().lower(irFile)
|
||||||
InterfaceLowering(context.state).runOnFile(irFile)
|
InterfaceLowering(context.state).runOnFile(irFile)
|
||||||
InterfaceDelegationLowering(context.state).runOnFile(irFile)
|
InterfaceDelegationLowering(context.state).runOnFile(irFile)
|
||||||
|
LocalFunctionsLowering(context).runOnFile(irFile)
|
||||||
EnumClassLowering(context).runOnFile(irFile)
|
EnumClassLowering(context).runOnFile(irFile)
|
||||||
ObjectClassLowering(context).runOnFile(irFile)
|
ObjectClassLowering(context).runOnFile(irFile)
|
||||||
InitializersLowering(context).runOnFile(irFile)
|
InitializersLowering(context).runOnFile(irFile)
|
||||||
|
|||||||
+4
-1
@@ -312,7 +312,10 @@ class ExpressionCodegen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateLocal(descriptor: CallableDescriptor, type: Type): StackValue {
|
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)
|
return onStack(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
|
|||||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
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.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
|
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
|
||||||
|
|||||||
+359
@@ -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<ValueDescriptor, ValueParameterDescriptor> = HashMap()
|
||||||
|
|
||||||
|
var index: Int = -1
|
||||||
|
|
||||||
|
override fun toString(): String =
|
||||||
|
"LocalFunctionContext for ${declaration.descriptor}"
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class LocalFunctionsTransformer(val memberFunction: IrFunction) {
|
||||||
|
val localFunctions: MutableMap<FunctionDescriptor, LocalFunctionContext> = LinkedHashMap()
|
||||||
|
val new2old: MutableMap<ValueParameterDescriptor, ValueDescriptor> = HashMap()
|
||||||
|
|
||||||
|
fun lowerLocalFunctions(): List<IrDeclaration>? {
|
||||||
|
collectLocalFunctions()
|
||||||
|
if (localFunctions.isEmpty()) return null
|
||||||
|
|
||||||
|
collectClosures()
|
||||||
|
|
||||||
|
transformDescriptors()
|
||||||
|
|
||||||
|
rewriteBodies()
|
||||||
|
|
||||||
|
return collectRewrittenDeclarations()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun collectRewrittenDeclarations(): ArrayList<IrDeclaration> =
|
||||||
|
ArrayList<IrDeclaration>(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 : IrMemberAccessExpression> 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<TypeParameterDescriptor, KotlinType>? {
|
||||||
|
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<ValueParameterDescriptor>(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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+2
-2
@@ -41,7 +41,7 @@ class LocalFunctionGenerator(statementGenerator: StatementGenerator) : Statement
|
|||||||
irBlock.statements.add(irFun)
|
irBlock.statements.add(irFun)
|
||||||
|
|
||||||
irBlock.statements.add(IrCallableReferenceImpl(ktLambda.startOffset, ktLambda.endOffset, lambdaExpressionType,
|
irBlock.statements.add(IrCallableReferenceImpl(ktLambda.startOffset, ktLambda.endOffset, lambdaExpressionType,
|
||||||
lambdaDescriptor, null, IrStatementOrigin.LAMBDA))
|
lambdaDescriptor, null, IrStatementOrigin.LAMBDA))
|
||||||
|
|
||||||
return irBlock
|
return irBlock
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ class LocalFunctionGenerator(statementGenerator: StatementGenerator) : Statement
|
|||||||
irBlock.statements.add(irFun)
|
irBlock.statements.add(irFun)
|
||||||
|
|
||||||
irBlock.statements.add(IrCallableReferenceImpl(ktFun.startOffset, ktFun.endOffset, funExpressionType,
|
irBlock.statements.add(IrCallableReferenceImpl(ktFun.startOffset, ktFun.endOffset, funExpressionType,
|
||||||
irFun.descriptor, null, IrStatementOrigin.ANONYMOUS_FUNCTION))
|
irFun.descriptor, null, IrStatementOrigin.ANONYMOUS_FUNCTION))
|
||||||
|
|
||||||
irBlock
|
irBlock
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -54,3 +54,10 @@ inline fun <T : IrMemberAccessExpression> T.mapValueParameters(transform: (Value
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <T : IrMemberAccessExpression> T.mapValueParametersIndexed(transform: (Int, ValueParameterDescriptor) -> IrExpression?): T {
|
||||||
|
descriptor.valueParameters.forEach {
|
||||||
|
putValueArgument(it.index, transform(it.index, it))
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ open class DeepCopyIrTree : IrElementTransformerVoid() {
|
|||||||
protected open fun mapValueReference(descriptor: ValueDescriptor) = descriptor
|
protected open fun mapValueReference(descriptor: ValueDescriptor) = descriptor
|
||||||
protected open fun mapVariableReference(descriptor: VariableDescriptor) = descriptor
|
protected open fun mapVariableReference(descriptor: VariableDescriptor) = descriptor
|
||||||
protected open fun mapPropertyReference(descriptor: PropertyDescriptor) = 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 mapCallee(descriptor: CallableDescriptor) = descriptor
|
||||||
protected open fun mapDelegatedConstructorCallee(descriptor: ClassConstructorDescriptor) = descriptor
|
protected open fun mapDelegatedConstructorCallee(descriptor: ClassConstructorDescriptor) = descriptor
|
||||||
protected open fun mapEnumConstructorCallee(descriptor: ClassConstructorDescriptor) = descriptor
|
protected open fun mapEnumConstructorCallee(descriptor: ClassConstructorDescriptor) = descriptor
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
fun foo(x: String): String {
|
||||||
|
fun bar(y: String) = x + y
|
||||||
|
return bar("K")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = foo("O")
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fun <X : Any> foo(x: X): String {
|
||||||
|
fun <Y : Any> bar(y: Y) =
|
||||||
|
x.toString() + y.toString()
|
||||||
|
|
||||||
|
return bar("K")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = foo("O")
|
||||||
+11
@@ -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")
|
||||||
@@ -41,6 +41,24 @@ public class IrOnlyBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTest
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("enumClass.kt")
|
||||||
public void testEnumClass() throws Exception {
|
public void testEnumClass() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/enumClass.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/box/enumClass.kt");
|
||||||
|
|||||||
@@ -66,12 +66,6 @@ abstract class AbstractClosureAnnotatorTestCase : AbstractIrGeneratorTestCase()
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun printClosure(closure: Closure) {
|
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 {
|
closure.capturedValues.forEach {
|
||||||
actualOut.println(" variable ${it.name}")
|
actualOut.println(" variable ${it.name}")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user