Fixed bug in LocalDeclarationsLowering + test

Bug was in determining whether a function was locally defined
This commit is contained in:
Igor Chevdar
2018-01-18 13:23:56 +03:00
parent b2098088ec
commit f218e2676e
4 changed files with 756 additions and 0 deletions
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.validateIrFile
import org.jetbrains.kotlin.backend.common.validateIrModule
import org.jetbrains.kotlin.backend.konan.lower.*
import org.jetbrains.kotlin.backend.konan.lower.LocalDeclarationsLowering
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.replaceUnboundSymbols
@@ -0,0 +1,733 @@
/*
* 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.konan.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.common.lower.Closure
import org.jetbrains.kotlin.backend.common.lower.ClosureAnnotator
import org.jetbrains.kotlin.backend.common.lower.callsSuper
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.*
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.*
// TODO: Remove as soon as its version is fixed in common code.
class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContainerLoweringPass {
private object DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE :
IrDeclarationOriginImpl("FIELD_FOR_CAPTURED_VALUE") {}
private object STATEMENT_ORIGIN_INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE :
IrStatementOriginImpl("INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE") {}
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
if (irDeclarationContainer is IrDeclaration &&
irDeclarationContainer.descriptor.parents.any { it is CallableDescriptor }) {
// Lowering of non-local declarations handles all local declarations inside.
// This declaration is local and shouldn't be considered.
return
}
// Continuous numbering across all declarations in the container.
lambdasCount = 0
irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
// TODO: may be do the opposite - specify the list of IR elements which need not to be transformed
when (memberDeclaration) {
is IrFunction -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
is IrProperty -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
is IrField -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
is IrAnonymousInitializer -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
else -> null
}
}
}
private var lambdasCount = 0
private abstract class LocalContext {
/**
* @return the expression to get the value for given descriptor, or `null` if [IrGetValue] should be used.
*/
abstract fun irGet(startOffset: Int, endOffset: Int, descriptor: ValueDescriptor): IrExpression?
}
private abstract class LocalContextWithClosureAsParameters : LocalContext() {
abstract val declaration: IrFunction
open val descriptor: FunctionDescriptor
get() = declaration.descriptor
abstract val transformedDescriptor: FunctionDescriptor
abstract val transformedDeclaration: IrFunction
val capturedValueToParameter: MutableMap<ValueDescriptor, IrValueParameterSymbol> = HashMap()
override fun irGet(startOffset: Int, endOffset: Int, descriptor: ValueDescriptor): IrExpression? {
val newSymbol = capturedValueToParameter[descriptor] ?: return null
return IrGetValueImpl(startOffset, endOffset, newSymbol)
}
}
private class LocalFunctionContext(override val declaration: IrFunction) : LocalContextWithClosureAsParameters() {
lateinit var closure: Closure
override lateinit var transformedDescriptor: FunctionDescriptor
override lateinit var transformedDeclaration: IrSimpleFunction
var index: Int = -1
override fun toString(): String =
"LocalFunctionContext for $descriptor"
}
private class LocalClassConstructorContext(override val declaration: IrConstructor) : LocalContextWithClosureAsParameters() {
override val descriptor: ClassConstructorDescriptor
get() = declaration.descriptor
override lateinit var transformedDescriptor: ClassConstructorDescriptor
override lateinit var transformedDeclaration: IrConstructor
override fun toString(): String =
"LocalClassConstructorContext for $descriptor"
}
private class LocalClassContext(val declaration: IrClass) : LocalContext() {
val descriptor: ClassDescriptor
get() = declaration.descriptor
lateinit var closure: Closure
val capturedValueToField: MutableMap<ValueDescriptor, IrField> = HashMap()
override fun irGet(startOffset: Int, endOffset: Int, descriptor: ValueDescriptor): IrExpression? {
val field = capturedValueToField[descriptor] ?: return null
return IrGetFieldImpl(startOffset, endOffset, field.symbol,
receiver = IrGetValueImpl(startOffset, endOffset, declaration.thisReceiver!!.symbol)
)
}
override fun toString(): String =
"LocalClassContext for ${descriptor}"
}
private inner class LocalDeclarationsTransformer(val memberDeclaration: IrDeclaration) {
val localFunctions: MutableMap<FunctionDescriptor, LocalFunctionContext> = LinkedHashMap()
val localClasses: MutableMap<ClassDescriptor, LocalClassContext> = LinkedHashMap()
val localClassConstructors: MutableMap<ClassConstructorDescriptor, LocalClassConstructorContext> = LinkedHashMap()
val transformedDeclarations = mutableMapOf<DeclarationDescriptor, IrSymbol>()
val FunctionDescriptor.transformed: IrFunctionSymbol?
get() = transformedDeclarations[this] as IrFunctionSymbol?
val oldParameterToNew: MutableMap<ParameterDescriptor, IrValueParameterSymbol> = HashMap()
val newParameterToOld: MutableMap<ParameterDescriptor, ParameterDescriptor> = HashMap()
val newParameterToCaptured: MutableMap<ValueParameterDescriptor, IrValueSymbol> = HashMap()
fun lowerLocalDeclarations(): List<IrDeclaration>? {
collectLocalDeclarations()
if (localFunctions.isEmpty() && localClasses.isEmpty()) return null
collectClosures()
transformDescriptors()
rewriteDeclarations()
val result = collectRewrittenDeclarations()
return result
}
private fun collectRewrittenDeclarations(): ArrayList<IrDeclaration> =
ArrayList<IrDeclaration>(localFunctions.size + localClasses.size + 1).apply {
add(memberDeclaration)
localFunctions.values.mapTo(this) {
val original = it.declaration
it.transformedDeclaration.apply {
this.body = original.body
original.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument ->
val body = original.getDefault(argument)!!
oldParameterToNew[argument]!!.owner.defaultValue = body
}
}
}
localClasses.values.mapTo(this) {
it.declaration
}
}
private inner class FunctionBodiesRewriter(val localContext: LocalContext?) : IrElementTransformerVoid() {
override fun visitClass(declaration: IrClass): IrStatement {
if (declaration.descriptor in localClasses) {
// Replace local class definition with an empty composite.
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
} else {
return super.visitClass(declaration)
}
}
override fun visitFunction(declaration: IrFunction): IrStatement {
if (declaration.descriptor in localFunctions) {
// Replace local function definition with an empty composite.
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
} else {
return super.visitFunction(declaration)
}
}
override fun visitConstructor(declaration: IrConstructor): IrStatement {
// Body is transformed separately. See loop over constructors in rewriteDeclarations().
val constructorContext = localClassConstructors[declaration.descriptor]
if (constructorContext != null) {
return constructorContext.transformedDeclaration.apply {
this.body = declaration.body!!
declaration.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument ->
val body = declaration.getDefault(argument)!!
oldParameterToNew[argument]!!.owner.defaultValue = body
}
}
} else {
return super.visitConstructor(declaration)
}
}
override fun visitGetValue(expression: IrGetValue): IrExpression {
val descriptor = expression.descriptor
localContext?.irGet(expression.startOffset, expression.endOffset, descriptor)?.let {
return it
}
oldParameterToNew[descriptor]?.let {
return IrGetValueImpl(expression.startOffset, expression.endOffset, it)
}
return expression
}
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
val oldCallee = expression.descriptor.original
val newCallee = oldCallee.transformed ?: return expression
val newCall = createNewCall(expression, newCallee).fillArguments(expression)
return newCall
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.transformChildrenVoid(this)
val oldCallee = expression.descriptor.original
val newCallee = transformedDeclarations[oldCallee] as IrConstructorSymbol? ?: return expression
val newExpression = IrDelegatingConstructorCallImpl(
expression.startOffset, expression.endOffset,
newCallee,
newCallee.descriptor,
remapTypeArguments(expression, newCallee.descriptor)
).fillArguments(expression)
return newExpression
}
private fun <T : IrMemberAccessExpression> T.fillArguments(oldExpression: IrMemberAccessExpression): T {
mapValueParameters { newValueParameterDescriptor ->
val oldParameter = newParameterToOld[newValueParameterDescriptor]
if (oldParameter != null) {
oldExpression.getValueArgument(oldParameter as ValueParameterDescriptor)
} else {
// The callee expects captured value as argument.
val capturedValueSymbol =
newParameterToCaptured[newValueParameterDescriptor] ?:
throw AssertionError("Non-mapped parameter $newValueParameterDescriptor")
val capturedValueDescriptor = capturedValueSymbol.descriptor
localContext?.irGet(
oldExpression.startOffset, oldExpression.endOffset,
capturedValueDescriptor
) ?:
// Captured value is directly available for the caller.
IrGetValueImpl(oldExpression.startOffset, oldExpression.endOffset,
oldParameterToNew[capturedValueDescriptor] ?: capturedValueSymbol)
}
}
dispatchReceiver = oldExpression.dispatchReceiver
extensionReceiver = oldExpression.extensionReceiver
return this
}
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
expression.transformChildrenVoid(this)
val oldCallee = expression.descriptor.original
val newCallee = oldCallee.transformed ?: return expression
val newCallableReference = IrFunctionReferenceImpl(
expression.startOffset, expression.endOffset,
expression.type, // TODO functional type for transformed descriptor
newCallee,
newCallee.descriptor,
remapTypeArguments(expression, newCallee.descriptor),
expression.origin
).fillArguments(expression)
return newCallableReference
}
override fun visitReturn(expression: IrReturn): IrExpression {
expression.transformChildrenVoid(this)
val oldReturnTarget = expression.returnTarget
val newReturnTarget = oldReturnTarget.transformed ?: return expression
return IrReturnImpl(expression.startOffset, expression.endOffset, newReturnTarget, expression.value)
}
override fun visitDeclarationReference(expression: IrDeclarationReference): IrExpression {
if (expression.descriptor in transformedDeclarations) {
TODO()
}
return super.visitDeclarationReference(expression)
}
override fun visitDeclaration(declaration: IrDeclaration): IrStatement {
if (declaration.descriptor in transformedDeclarations) {
TODO()
}
return super.visitDeclaration(declaration)
}
}
private fun rewriteFunctionBody(irDeclaration: IrDeclaration, localContext: LocalContext?) {
irDeclaration.transformChildrenVoid(FunctionBodiesRewriter(localContext))
}
private fun rewriteClassMembers(irClass: IrClass, localClassContext: LocalClassContext) {
irClass.transformChildrenVoid(FunctionBodiesRewriter(localClassContext))
val classDescriptor = irClass.descriptor
val constructorsCallingSuper = classDescriptor.constructors
.map { localClassConstructors[it]!! }
.filter { it.declaration.callsSuper() }
assert(constructorsCallingSuper.any(), { "Expected at least one constructor calling super; class: $classDescriptor" })
localClassContext.capturedValueToField.forEach { capturedValue, field ->
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
irClass.declarations.add(field)
for (constructorContext in constructorsCallingSuper) {
val blockBody = constructorContext.declaration.body as? IrBlockBody
?: throw AssertionError("Unexpected constructor body: ${constructorContext.declaration.body}")
val capturedValueExpression = constructorContext.irGet(startOffset, endOffset, capturedValue)!!
blockBody.statements.add(0,
IrSetFieldImpl(startOffset, endOffset, field.symbol,
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol),
capturedValueExpression, STATEMENT_ORIGIN_INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE))
}
}
}
private fun rewriteDeclarations() {
localFunctions.values.forEach {
rewriteFunctionBody(it.declaration, it)
}
localClassConstructors.values.forEach {
rewriteFunctionBody(it.declaration, it)
}
localClasses.values.forEach {
rewriteClassMembers(it.declaration, it)
}
rewriteFunctionBody(memberDeclaration, null)
}
private fun createNewCall(oldCall: IrCall, newCallee: IrFunctionSymbol) =
if (oldCall is IrCallWithShallowCopy)
oldCall.shallowCopy(oldCall.origin, newCallee, oldCall.superQualifierSymbol)
else
IrCallImpl(
oldCall.startOffset, oldCall.endOffset,
newCallee,
newCallee.descriptor,
remapTypeArguments(oldCall, newCallee.descriptor),
oldCall.origin, oldCall.superQualifierSymbol
)
private fun remapTypeArguments(oldExpression: IrMemberAccessExpression, newCallee: CallableDescriptor): Map<TypeParameterDescriptor, KotlinType>? {
val oldCallee = oldExpression.descriptor.original
return if (oldCallee.typeParameters.isEmpty())
null
else oldCallee.typeParameters.associateBy(
{ newCallee.typeParameters[it.index] },
{ oldExpression.getTypeArgumentOrDefault(it) }
)
}
private fun transformDescriptors() {
localFunctions.values.forEach {
createLiftedDescriptor(it)
}
localClasses.values.forEach {
createFieldsForCapturedValues(it)
}
localClassConstructors.values.forEach {
createTransformedConstructorDescriptor(it)
}
}
private fun suggestLocalName(descriptor: DeclarationDescriptor): String {
localFunctions[descriptor]?.let {
if (it.index >= 0)
return "lambda-${it.index}"
}
return descriptor.name.asString()
}
private fun generateNameForLiftedDeclaration(descriptor: DeclarationDescriptor,
newOwner: DeclarationDescriptor): Name =
Name.identifier(
descriptor.parentsWithSelf
.takeWhile { it != newOwner }
.toList().reversed()
.map { suggestLocalName(it) }
.joinToString(separator = "$")
)
private fun createLiftedDescriptor(localFunctionContext: LocalFunctionContext) {
val oldDescriptor = localFunctionContext.descriptor
val memberOwner = memberDeclaration.descriptor.containingDeclaration!!
val newDescriptor = SimpleFunctionDescriptorImpl.create(
memberOwner,
oldDescriptor.annotations,
generateNameForLiftedDeclaration(oldDescriptor, memberOwner),
CallableMemberDescriptor.Kind.SYNTHESIZED,
oldDescriptor.source
).apply {
isTailrec = oldDescriptor.isTailrec
isSuspend = oldDescriptor.isSuspend
// TODO: copy other properties or consider using `FunctionDescriptor.CopyBuilder`.
}
localFunctionContext.transformedDescriptor = newDescriptor
if (oldDescriptor.dispatchReceiverParameter != null) {
throw AssertionError("local functions must not have dispatch receiver")
}
val newDispatchReceiverParameter = null
// Do not substitute type parameters for now.
val newTypeParameters = oldDescriptor.typeParameters
// TODO: consider using fields to access the closure of enclosing class.
val capturedValues = localFunctionContext.closure.capturedValues
val newValueParameters = createTransformedValueParameters(localFunctionContext, capturedValues)
newDescriptor.initialize(
oldDescriptor.extensionReceiverParameter?.type,
newDispatchReceiverParameter,
newTypeParameters,
newValueParameters,
oldDescriptor.returnType,
Modality.FINAL,
Visibilities.PRIVATE
)
oldDescriptor.extensionReceiverParameter?.let {
newParameterToOld.putAbsentOrSame(newDescriptor.extensionReceiverParameter!!, it)
}
localFunctionContext.transformedDeclaration = with(localFunctionContext.declaration) {
IrFunctionImpl(startOffset, endOffset, origin, newDescriptor)
}.apply {
createParameterDeclarations()
recordTransformedValueParameters(localFunctionContext)
transformedDeclarations[oldDescriptor] = this.symbol
}
}
private fun createTransformedValueParameters(localContext: LocalContextWithClosureAsParameters,
capturedValues: List<IrValueSymbol>)
: List<ValueParameterDescriptor> {
val oldDescriptor = localContext.descriptor
val newDescriptor = localContext.transformedDescriptor
val closureParametersCount = capturedValues.size
val newValueParametersCount = closureParametersCount + oldDescriptor.valueParameters.size
val newValueParameters = ArrayList<ValueParameterDescriptor>(newValueParametersCount).apply {
capturedValues.mapIndexedTo(this) { i, capturedValue ->
createUnsubstitutedCapturedValueParameter(newDescriptor, capturedValue.descriptor, i).apply {
newParameterToCaptured[this] = capturedValue
}
}
oldDescriptor.valueParameters.mapIndexedTo(this) { i, oldValueParameterDescriptor ->
createUnsubstitutedParameter(newDescriptor, oldValueParameterDescriptor, closureParametersCount + i).apply {
newParameterToOld.putAbsentOrSame(this, oldValueParameterDescriptor)
}
}
}
return newValueParameters
}
private fun IrFunction.recordTransformedValueParameters(localContext: LocalContextWithClosureAsParameters) {
valueParameters.forEach {
val capturedValue = newParameterToCaptured[it.descriptor]
if (capturedValue != null) {
localContext.capturedValueToParameter[capturedValue.descriptor] = it.symbol
}
}
(listOfNotNull(dispatchReceiverParameter, extensionReceiverParameter) + valueParameters).forEach {
val oldParameter = newParameterToOld[it.descriptor]
if (oldParameter != null) {
oldParameterToNew.putAbsentOrSame(oldParameter, it.symbol)
}
}
}
private fun createTransformedConstructorDescriptor(constructorContext: LocalClassConstructorContext) {
val oldDescriptor = constructorContext.descriptor
val localClassContext = localClasses[oldDescriptor.containingDeclaration]!!
val newDescriptor = ClassConstructorDescriptorImpl.create(
localClassContext.descriptor,
Annotations.EMPTY, oldDescriptor.isPrimary, oldDescriptor.source)
constructorContext.transformedDescriptor = newDescriptor
// Do not substitute type parameters for now.
val newTypeParameters = oldDescriptor.typeParameters
val capturedValues = localClasses[oldDescriptor.containingDeclaration]!!.closure.capturedValues
val newValueParameters = createTransformedValueParameters(constructorContext, capturedValues)
newDescriptor.initialize(
newValueParameters,
Visibilities.PRIVATE,
newTypeParameters
)
newDescriptor.returnType = oldDescriptor.returnType
oldDescriptor.dispatchReceiverParameter?.let {
newParameterToOld.putAbsentOrSame(newDescriptor.dispatchReceiverParameter!!, it)
}
oldDescriptor.extensionReceiverParameter?.let {
throw AssertionError("constructors can't have extension receiver")
}
constructorContext.transformedDeclaration = with(constructorContext.declaration) {
IrConstructorImpl(startOffset, endOffset, origin, newDescriptor)
}.apply {
createParameterDeclarations()
recordTransformedValueParameters(constructorContext)
transformedDeclarations[oldDescriptor] = this.symbol
}
}
private fun createFieldsForCapturedValues(localClassContext: LocalClassContext) {
val classDescriptor = localClassContext.descriptor
localClassContext.closure.capturedValues.forEach { capturedValue ->
val fieldDescriptor = PropertyDescriptorImpl.create(
classDescriptor,
Annotations.EMPTY,
Modality.FINAL,
Visibilities.PRIVATE,
/* isVar = */ false,
suggestNameForCapturedValue(capturedValue.descriptor),
CallableMemberDescriptor.Kind.SYNTHESIZED,
SourceElement.NO_SOURCE,
/* lateInit = */ false,
/* isConst = */ false,
/* isExpect = */ false,
/* isActual = */ false,
/* isExternal = */ false,
/* isDelegated = */ false)
fieldDescriptor.initialize(/* getter = */ null, /* setter = */ null)
val extensionReceiverParameter: ReceiverParameterDescriptor? = null
fieldDescriptor.setType(
capturedValue.descriptor.type,
emptyList<TypeParameterDescriptor>(),
classDescriptor.thisAsReceiverParameter,
extensionReceiverParameter)
localClassContext.capturedValueToField[capturedValue.descriptor] = IrFieldImpl(
localClassContext.declaration.startOffset, localClassContext.declaration.endOffset,
DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE,
fieldDescriptor
)
}
}
private fun <K, V> MutableMap<K, V>.putAbsentOrSame(key: K, value: V) {
val current = this.getOrPut(key, { value })
if (current != value) {
error("$current != $value")
}
}
private fun suggestNameForCapturedValue(valueDescriptor: ValueDescriptor): Name =
if (valueDescriptor.name.isSpecial) {
val oldNameStr = valueDescriptor.name.asString()
oldNameStr.substring(1, oldNameStr.length - 1).synthesizedName
} else
valueDescriptor.name
private fun createUnsubstitutedCapturedValueParameter(
newParameterOwner: CallableMemberDescriptor,
valueDescriptor: ValueDescriptor,
index: Int
): ValueParameterDescriptor =
ValueParameterDescriptorImpl(
newParameterOwner, null, index,
valueDescriptor.annotations,
suggestNameForCapturedValue(valueDescriptor),
valueDescriptor.type,
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() {
val annotator = ClosureAnnotator(memberDeclaration)
localFunctions.forEach { descriptor, context ->
context.closure = annotator.getFunctionClosure(descriptor)
}
localClasses.forEach { descriptor, context ->
context.closure = annotator.getClassClosure(descriptor)
}
}
private fun collectLocalDeclarations() {
memberDeclaration.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
private fun ClassDescriptor.declaredInFunction() = when (this.containingDeclaration) {
is CallableDescriptor -> true
is ClassDescriptor -> false
is PackageFragmentDescriptor -> false
else -> TODO(this.toString() + "\n" + this.containingDeclaration.toString())
}
override fun visitFunction(declaration: IrFunction) {
declaration.acceptChildrenVoid(this)
val descriptor = declaration.descriptor
if (descriptor.visibility == Visibilities.LOCAL) {
val localFunctionContext = LocalFunctionContext(declaration)
localFunctions[descriptor] = localFunctionContext
if (descriptor.name.isSpecial) {
localFunctionContext.index = lambdasCount++
}
}
}
override fun visitConstructor(declaration: IrConstructor) {
declaration.acceptChildrenVoid(this)
val descriptor = declaration.descriptor
assert(descriptor.visibility != Visibilities.LOCAL)
if (descriptor.constructedClass.isInner) return
localClassConstructors[descriptor] = LocalClassConstructorContext(declaration)
}
override fun visitClass(declaration: IrClass) {
declaration.acceptChildrenVoid(this)
val descriptor = declaration.descriptor
if (descriptor.isInner) return
// Local nested classes can only be inner.
assert(descriptor.declaredInFunction())
val localClassContext = LocalClassContext(declaration)
localClasses[descriptor] = localClassContext
}
})
}
}
}
+5
View File
@@ -2091,6 +2091,11 @@ task inline_type_substitution_in_fake_override(type: RunKonanTest) {
source = "codegen/inline/typeSubstitutionInFakeOverride.kt"
}
task inline_localFunctionInInitializerBlock(type: RunKonanTest) {
goldValue = "Ok\n"
source = "codegen/inline/localFunctionInInitializerBlock.kt"
}
task deserialized_inline0(type: RunKonanTest) {
source = "serialization/deserialized_inline0.kt"
}
@@ -0,0 +1,17 @@
package codegen.inline.localFunctionInInitializerBlock
import kotlin.test.*
class Foo {
init {
bar()
}
}
inline fun bar() {
println({ "Ok" }())
}
@Test fun runTest() {
Foo()
}