diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/AbstractClosureRecorder.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/AbstractClosureAnnotator.kt similarity index 57% rename from backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/AbstractClosureRecorder.kt rename to backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/AbstractClosureAnnotator.kt index 7ba8096e676..251b1746b4d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/AbstractClosureRecorder.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/AbstractClosureAnnotator.kt @@ -1,38 +1,22 @@ -/* - * 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.common +package org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.descriptors.* 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.declarations.IrLocalDelegatedProperty -import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrValueAccessExpression import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.resolve.DescriptorUtils -import java.util.* -abstract class AbstractClosureRecorder : IrElementVisitorVoid { +// TODO: synchronize with JVM BE +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) { + private abstract class ClosureBuilder(open val owner: DeclarationDescriptor) { val capturedValues = mutableSetOf() fun buildClosure() = Closure(capturedValues.toList()) @@ -43,12 +27,39 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid { private fun fillInNestedClosure(destination: MutableSet, nested: List) { nested.filterTo(destination) { - it.containingDeclaration != owner + isExternal(it) } } + + abstract fun isExternal(valueDescriptor: T): Boolean } - private val closuresStack = ArrayDeque() + private class FunctionClosureBuilder(override val owner: FunctionDescriptor) : ClosureBuilder(owner) { + + override fun isExternal(valueDescriptor: T): Boolean = + valueDescriptor.containingDeclaration != owner && valueDescriptor != owner.dispatchReceiverParameter + } + + private class ClassClosureBuilder(override val owner: ClassDescriptor) : ClosureBuilder(owner) { + + override fun isExternal(valueDescriptor: T): Boolean { + // TODO: replace with 'return valueDescriptor.containingDeclaration != owner' after constructors lowering. + var declaration: DeclarationDescriptor? = valueDescriptor.containingDeclaration + while (declaration != null && declaration != owner) { + declaration = declaration.containingDeclaration + } + return declaration != owner + } + + } + + private val closuresStack = mutableListOf() + + private fun MutableList.push(element: E) = this.add(element) + + private fun MutableList.pop() = this.removeAt(size - 1) + + private fun MutableList.peek(): E? = if (size == 0) null else this[size - 1] override fun visitElement(element: IrElement) { element.acceptChildrenVoid(this) @@ -56,7 +67,7 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid { override fun visitClass(declaration: IrClass) { val classDescriptor = declaration.descriptor - val closureBuilder = ClosureBuilder(classDescriptor) + val closureBuilder = ClassClosureBuilder(classDescriptor) closuresStack.push(closureBuilder) declaration.acceptChildrenVoid(this) @@ -73,7 +84,7 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid { override fun visitFunction(declaration: IrFunction) { val functionDescriptor = declaration.descriptor - val closureBuilder = ClosureBuilder(functionDescriptor) + val closureBuilder = FunctionClosureBuilder(functionDescriptor) closuresStack.push(closureBuilder) declaration.acceptChildrenVoid(this) @@ -98,7 +109,7 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid { if (closureBuilder != null) { val variableDescriptor = expression.descriptor - if (variableDescriptor.containingDeclaration != closureBuilder.owner) { + if (closureBuilder.isExternal(variableDescriptor)) { closureBuilder.capturedValues.add(variableDescriptor) } } @@ -106,4 +117,4 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid { expression.acceptChildrenVoid(this) } -} +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt index 9c9ff1d29a9..a089e6b5fc2 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/common/lower/LocalDeclarationsLowering.kt @@ -16,28 +16,32 @@ package org.jetbrains.kotlin.backend.common.lower -import org.jetbrains.kotlin.backend.common.AbstractClosureRecorder import org.jetbrains.kotlin.backend.common.BackendContext -import org.jetbrains.kotlin.backend.common.Closure import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.impl.* +import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl +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.* -import org.jetbrains.kotlin.ir.declarations.impl.* +import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl +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.* import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny import org.jetbrains.kotlin.resolve.descriptorUtil.parents import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf import org.jetbrains.kotlin.types.KotlinType import java.util.* -class LocalDeclarationsLowering(val context: BackendContext): DeclarationContainerLoweringPass { +class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContainerLoweringPass { override fun lower(irDeclarationContainer: IrDeclarationContainer) { if (irDeclarationContainer is IrDeclaration && irDeclarationContainer.descriptor.parents.any { it is CallableDescriptor }) { @@ -51,10 +55,13 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain lambdasCount = 0 irDeclarationContainer.declarations.transformFlat { memberDeclaration -> - if (memberDeclaration is IrFunction) - LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations() - else - null + // 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 IrAnonymousInitializer -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations() + else -> null + } } } @@ -117,7 +124,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain val fieldDescriptor = capturedValueToField[descriptor] ?: return null return IrGetFieldImpl(startOffset, endOffset, fieldDescriptor, - receiver = IrGetValueImpl(startOffset, endOffset, this.descriptor.thisAsReceiverParameter) + receiver = IrGetValueImpl(startOffset, endOffset, this.descriptor.thisAsReceiverParameter) ) } @@ -125,7 +132,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain "LocalClassContext for ${descriptor}" } - private inner class LocalDeclarationsTransformer(val memberFunction: IrFunction) { + private inner class LocalDeclarationsTransformer(val memberDeclaration: IrDeclaration) { val localFunctions: MutableMap = LinkedHashMap() val localClasses: MutableMap = LinkedHashMap() val localClassConstructors: MutableMap = LinkedHashMap() @@ -155,7 +162,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain private fun collectRewrittenDeclarations(): ArrayList = ArrayList(localFunctions.size + localClasses.size + 1).apply { - add(memberFunction) + add(memberDeclaration) localFunctions.values.mapTo(this) { val original = it.declaration @@ -174,8 +181,12 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain private inner class FunctionBodiesRewriter(val localContext: LocalContext?) : IrElementTransformerVoid() { override fun visitClass(declaration: IrClass): IrStatement { - // Replace local class definition with an empty composite. - return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType) + 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 { @@ -183,18 +194,20 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain // Replace local function definition with an empty composite. return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType) } else { - declaration.transformChildrenVoid(this) - return declaration + return super.visitFunction(declaration) } } override fun visitConstructor(declaration: IrConstructor): IrStatement { // Body is transformed separately. - val transformedDescriptor = localClassConstructors[declaration.descriptor]!!.transformedDescriptor - - return IrConstructorImpl(declaration.startOffset, declaration.endOffset, declaration.origin, - transformedDescriptor, declaration.body!!) + val transformedDescriptor = localClassConstructors[declaration.descriptor]?.transformedDescriptor + if (transformedDescriptor != null) { + return IrConstructorImpl(declaration.startOffset, declaration.endOffset, declaration.origin, + transformedDescriptor, declaration.body!!) + } else { + return super.visitConstructor(declaration) + } } override fun visitGetValue(expression: IrGetValue): IrExpression { @@ -222,6 +235,21 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain return newCall } + override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { + expression.transformChildrenVoid(this) + + val oldCallee = expression.descriptor.original + val newCallee = transformedDescriptors[oldCallee] as ClassConstructorDescriptor? ?: return expression + + val newExpression = IrDelegatingConstructorCallImpl( + expression.startOffset, expression.endOffset, + newCallee, + remapTypeArguments(expression, newCallee) + ).fillArguments(expression) + + return newExpression + } + private fun T.fillArguments(oldExpression: IrMemberAccessExpression): T { mapValueParameters { newValueParameterDescriptor -> @@ -233,7 +261,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain // The callee expects captured value as argument. val capturedValueDescriptor = newParameterToCaptured[newValueParameterDescriptor] ?: - throw AssertionError("Non-mapped parameter $newValueParameterDescriptor") + throw AssertionError("Non-mapped parameter $newValueParameterDescriptor") localContext?.irGet( oldExpression.startOffset, oldExpression.endOffset, @@ -292,8 +320,8 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain } } - private fun rewriteFunctionBody(irFunction: IrFunction, localContext: LocalContext?) { - irFunction.transformChildrenVoid(FunctionBodiesRewriter(localContext)) + private fun rewriteFunctionBody(irDeclaration: IrDeclaration, localContext: LocalContext?) { + irDeclaration.transformChildrenVoid(FunctionBodiesRewriter(localContext)) } private object DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE : @@ -339,7 +367,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain rewriteClassMembers(it.declaration, it) } - rewriteFunctionBody(memberFunction, null) + rewriteFunctionBody(memberDeclaration, null) } private fun createNewCall(oldCall: IrCall, newCallee: CallableDescriptor) = @@ -395,12 +423,12 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain .toList().reversed() .map { suggestLocalName(it) } .joinToString(separator = "$") - ) + ) private fun createLiftedDescriptor(localFunctionContext: LocalFunctionContext) { val oldDescriptor = localFunctionContext.descriptor - val memberOwner = memberFunction.descriptor.containingDeclaration + val memberOwner = memberDeclaration.descriptor.containingDeclaration!! val newDescriptor = SimpleFunctionDescriptorImpl.create( memberOwner, oldDescriptor.annotations, @@ -480,7 +508,15 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain // Do not substitute type parameters for now. val newTypeParameters = oldDescriptor.typeParameters - val capturedValues = localClassContext.closure.capturedValues + val capturedValues = mutableListOf() + var classDescriptor = oldDescriptor.containingDeclaration + while (true) { + // Capture all values from the hierarchy since we need to call constructor of super class + // with his captured values. + val context = localClasses[classDescriptor] ?: break + capturedValues.addAll(context.closure.capturedValues) + classDescriptor = classDescriptor.getSuperClassOrAny() + } val newValueParameters = createTransformedValueParameters(localFunctionContext, capturedValues) @@ -560,8 +596,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain if (valueDescriptor.name.isSpecial) { val oldNameStr = valueDescriptor.name.asString() Name.identifier("$" + oldNameStr.substring(1, oldNameStr.length - 1)) - } - else + } else valueDescriptor.name private fun createUnsubstitutedCapturedValueParameter( @@ -586,7 +621,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain private fun collectClosures() { - memberFunction.acceptChildrenVoid(object : AbstractClosureRecorder() { + memberDeclaration.acceptChildrenVoid(object : AbstractClosureAnnotator() { override fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure) { localFunctions[functionDescriptor]?.closure = closure } @@ -598,16 +633,17 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain } private fun collectLocalDeclarations() { - memberFunction.acceptChildrenVoid(object : IrElementVisitorVoid { + memberDeclaration.acceptChildrenVoid(object : IrElementVisitorVoid { override fun visitElement(element: IrElement) { element.acceptChildrenVoid(this) } - private fun DeclarationDescriptor.isClassMember() = when (this.containingDeclaration) { - is CallableDescriptor -> false - is ClassDescriptor -> true - else -> TODO(this.toString()) + private fun DeclarationDescriptor.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) { @@ -615,7 +651,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain val descriptor = declaration.descriptor - if (!descriptor.isClassMember()) { + if (descriptor.declaredInFunction()) { val localFunctionContext = LocalFunctionContext(declaration) localFunctions[descriptor] = localFunctionContext @@ -631,7 +667,9 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain declaration.acceptChildrenVoid(this) val descriptor = declaration.descriptor - assert (descriptor.isClassMember()) + assert(!descriptor.declaredInFunction()) + + if (descriptor.constructedClass.isInner) return localClassConstructors[descriptor] = LocalClassConstructorContext(declaration) } @@ -641,12 +679,13 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain val descriptor = declaration.descriptor - if (descriptor.isClassMember()) { - assert (descriptor.isInner) - } else { - val localClassContext = LocalClassContext(declaration) - localClasses[descriptor] = localClassContext - } + if (descriptor.isInner) return + + // Local nested classes can only be inner. + assert(descriptor.declaredInFunction()) + + val localClassContext = LocalClassContext(declaration) + localClasses[descriptor] = localClassContext } }) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index e714e9ed2de..922283287cb 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -20,11 +20,6 @@ internal class KonanLower(val context: Context) { phaser.phase(KonanPhase.LOWER_ENUMS) { EnumClassLowering(context).run(irFile) } - - phaser.phase(KonanPhase.LOWER_INNER_CLASSES) { - InnerClassLowering(context).runOnFilePostfix(irFile) - } - phaser.phase(KonanPhase.LOWER_VARARG) { VarargInjectionLowering(context).runOnFilePostfix(irFile) } @@ -44,6 +39,9 @@ internal class KonanLower(val context: Context) { phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) { LocalDeclarationsLowering(context).runOnFilePostfix(irFile) } + phaser.phase(KonanPhase.LOWER_INNER_CLASSES) { + InnerClassLowering(context).runOnFilePostfix(irFile) + } phaser.phase(KonanPhase.LOWER_CALLABLES) { CallableReferenceLowering(context).runOnFilePostfix(irFile) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InnerClassLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InnerClassLowering.kt index fad21920b5f..7163609e1c4 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InnerClassLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InnerClassLowering.kt @@ -69,7 +69,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass { if (instanceInitializerIndex >= 0) { // Initializing constructor: initialize 'this.this$0' with '$outer'. blockBody.statements.add( - instanceInitializerIndex, + 0, IrSetFieldImpl( startOffset, endOffset, outerThisFieldDescriptor, IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter), @@ -117,7 +117,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass { val outerThisField = context.specialDescriptorsFactory.getOuterThisFieldDescriptor(innerClass) irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField, irThis, origin) - val outer = classDescriptor.containingDeclaration + val outer = innerClass.containingDeclaration innerClass = outer as? ClassDescriptor ?: throw AssertionError("Unexpected containing declaration for inner class $innerClass: $outer") } diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index 1d4794486dc..2a8091bfb5e 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -357,11 +357,46 @@ task innerClass_generic(type: RunKonanTest) { source = "codegen/innerClass/generic.kt" } +task innerClass_doubleInner(type: RunKonanTest) { + goldValue = "OK\n" + source = "codegen/innerClass/doubleInner.kt" +} + task innerClass_qualifiedThis(type: RunKonanTest) { goldValue = "OK\n" source = "codegen/innerClass/qualifiedThis.kt" } +task innerClass_superOuter(type: RunKonanTest) { + goldValue = "OK\n" + source = "codegen/innerClass/superOuter.kt" +} + +task localClass_localHierarchy(type: RunKonanTest) { + goldValue = "OK\n" + source = "codegen/localClass/localHierarchy.kt" +} + +task localClass_objectExpressionInProperty(type: RunKonanTest) { + goldValue = "OK\n" + source = "codegen/localClass/objectExpressionInProperty.kt" +} + +task localClass_objectExpressionInInitializer(type: RunKonanTest) { + goldValue = "OK\n" + source = "codegen/localClass/objectExpressionInInitializer.kt" +} + +task localClass_innerWithCapture(type: RunKonanTest) { + goldValue = "OK\n" + source = "codegen/localClass/innerWithCapture.kt" +} + +task localClass_innerTakesCapturedFromOuter(type: RunKonanTest) { + goldValue = "0\n1\n" + source = "codegen/localClass/innerTakesCapturedFromOuter.kt" +} + task array0(type: RunKonanTest) { goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n" source = "runtime/collections/array0.kt" diff --git a/backend.native/tests/codegen/innerClass/doubleInner.kt b/backend.native/tests/codegen/innerClass/doubleInner.kt new file mode 100644 index 00000000000..449b3a2e093 --- /dev/null +++ b/backend.native/tests/codegen/innerClass/doubleInner.kt @@ -0,0 +1,21 @@ +open class Father(val param: String) { + abstract inner class InClass { + fun work(): String { + return param + } + } + + inner class Child(p: String) : Father(p) { + inner class Child2 : Father.InClass { + constructor(): super() + } + } +} + +fun box(): String { + return Father("fail").Child("OK").Child2().work() +} + +fun main(args: Array) { + println(box()) +} \ No newline at end of file diff --git a/backend.native/tests/codegen/innerClass/superOuter.kt b/backend.native/tests/codegen/innerClass/superOuter.kt new file mode 100644 index 00000000000..4d92568ee23 --- /dev/null +++ b/backend.native/tests/codegen/innerClass/superOuter.kt @@ -0,0 +1,13 @@ +open class Outer(val outer: String) { + open inner class Inner(val inner: String): Outer(inner) { + fun foo() = outer + } + + fun value() = Inner("OK").foo() +} + +fun box() = Outer("Fail").value() + +fun main(args : Array) { + println(box()) +} \ No newline at end of file diff --git a/backend.native/tests/codegen/localClass/innerTakesCapturedFromOuter.kt b/backend.native/tests/codegen/localClass/innerTakesCapturedFromOuter.kt new file mode 100644 index 00000000000..464c3193a41 --- /dev/null +++ b/backend.native/tests/codegen/localClass/innerTakesCapturedFromOuter.kt @@ -0,0 +1,18 @@ +fun box() { + var previous: Any? = null + for (i in 0 .. 2) { + class Outer { + inner class Inner { + override fun toString() = i.toString() + } + + override fun toString() = Inner().toString() + } + if (previous != null) println(previous.toString()) + previous = Outer() + } +} + +fun main(args: Array) { + box() +} \ No newline at end of file diff --git a/backend.native/tests/codegen/localClass/innerWithCapture.kt b/backend.native/tests/codegen/localClass/innerWithCapture.kt new file mode 100644 index 00000000000..b030793a34a --- /dev/null +++ b/backend.native/tests/codegen/localClass/innerWithCapture.kt @@ -0,0 +1,13 @@ +fun box(s: String): String { + class Local { + open inner class Inner() { + open fun result() = s + } + } + + return Local().Inner().result() +} + +fun main(args : Array) { + println(box("OK")) +} \ No newline at end of file diff --git a/backend.native/tests/codegen/localClass/localHierarchy.kt b/backend.native/tests/codegen/localClass/localHierarchy.kt new file mode 100644 index 00000000000..6f77ff78e25 --- /dev/null +++ b/backend.native/tests/codegen/localClass/localHierarchy.kt @@ -0,0 +1,15 @@ +fun foo(s: String): String { + open class Local { + fun f() = s + } + + open class Derived: Local() { + fun g() = f() + } + + return Derived().g() +} + +fun main(args: Array) { + println(foo("OK")) +} \ No newline at end of file diff --git a/backend.native/tests/codegen/localClass/objectExpressionInInitializer.kt b/backend.native/tests/codegen/localClass/objectExpressionInInitializer.kt new file mode 100644 index 00000000000..653df8e98e7 --- /dev/null +++ b/backend.native/tests/codegen/localClass/objectExpressionInInitializer.kt @@ -0,0 +1,25 @@ +abstract class Father { + abstract inner class InClass { + abstract fun work(): String + } +} + +class Child : Father() { + val ChildInClass : InClass + + init { + ChildInClass = object : Father.InClass() { + override fun work(): String { + return "OK" + } + } + } +} + +fun box(): String { + return Child().ChildInClass.work() +} + +fun main(args: Array) { + println(box()) +} \ No newline at end of file diff --git a/backend.native/tests/codegen/localClass/objectExpressionInProperty.kt b/backend.native/tests/codegen/localClass/objectExpressionInProperty.kt new file mode 100644 index 00000000000..3683f7b0dd2 --- /dev/null +++ b/backend.native/tests/codegen/localClass/objectExpressionInProperty.kt @@ -0,0 +1,21 @@ +abstract class Father { + abstract inner class InClass { + abstract fun work(): String + } +} + +class Child : Father() { + val ChildInClass = object : Father.InClass() { + override fun work(): String { + return "OK" + } + } +} + +fun box(): String { + return Child().ChildInClass.work() +} + +fun main(args: Array) { + println(box()) +} \ No newline at end of file diff --git a/backend.native/tests/external/codegen/blackbox/innerNested/superConstructorCall/innerExtendsOuter.kt b/backend.native/tests/external/codegen/blackbox/innerNested/superConstructorCall/innerExtendsOuter.kt index 8db3bfa10ca..b368743c9d9 100644 --- a/backend.native/tests/external/codegen/blackbox/innerNested/superConstructorCall/innerExtendsOuter.kt +++ b/backend.native/tests/external/codegen/blackbox/innerNested/superConstructorCall/innerExtendsOuter.kt @@ -6,7 +6,7 @@ open class Outer(vararg val chars: Char) { open inner class Inner(val s: String): Outer(s[0], s[1]) { - fun concat() = java.lang.String.valueOf(chars) + fun concat() = fromCharArrays(chars, 0, chars.size) } fun value() = Inner("OK").concat() diff --git a/runtime/src/main/kotlin/konan/Annotations.kt b/runtime/src/main/kotlin/konan/Annotations.kt index c83a8807deb..c62c7c5649a 100644 --- a/runtime/src/main/kotlin/konan/Annotations.kt +++ b/runtime/src/main/kotlin/konan/Annotations.kt @@ -24,13 +24,6 @@ annotation class ExportTypeInfo(val name: String) public annotation class Used -// Following annotations can be used to mark functions that need to be fixed, -// once certain language feature is implemented. -/** - * Need to be fixed because of inner classes. - */ -public annotation class FixmeInner - /** * Need to be fixed because of reification support. */ diff --git a/runtime/src/main/kotlin/kotlin/collections/AbstractList.kt b/runtime/src/main/kotlin/kotlin/collections/AbstractList.kt index a841f7b174d..3268818e609 100644 --- a/runtime/src/main/kotlin/kotlin/collections/AbstractList.kt +++ b/runtime/src/main/kotlin/kotlin/collections/AbstractList.kt @@ -8,20 +8,15 @@ public abstract class AbstractList protected constructor() : AbstractColl abstract override val size: Int abstract override fun get(index: Int): E - // TODO: fix once have inner classes. - @FixmeInner - override fun iterator(): Iterator = TODO() // IteratorImpl() + override fun iterator(): Iterator = IteratorImpl() override fun indexOf(element: @UnsafeVariance E): Int = indexOfFirst { it == element } override fun lastIndexOf(element: @UnsafeVariance E): Int = indexOfLast { it == element } - // TODO: fix once have inner classes. - @FixmeInner - override fun listIterator(): ListIterator = TODO() // ListIteratorImpl(0) + override fun listIterator(): ListIterator = ListIteratorImpl(0) - @FixmeInner - override fun listIterator(index: Int): ListIterator = TODO() // ListIteratorImpl(index) + override fun listIterator(index: Int): ListIterator = ListIteratorImpl(index) override fun subList(fromIndex: Int, toIndex: Int): List = SubList(this, fromIndex, toIndex) @@ -52,8 +47,7 @@ public abstract class AbstractList protected constructor() : AbstractColl override fun hashCode(): Int = orderedHashCode(this) - // TODO: enable, once have inner classes. -/* + private open inner class IteratorImpl : Iterator { /** the index of the item that will be returned on the next call to [next]`()` */ protected var index = 0 @@ -86,7 +80,7 @@ public abstract class AbstractList protected constructor() : AbstractColl } override fun previousIndex(): Int = index - 1 - } */ + } internal companion object { internal fun checkElementIndex(index: Int, size: Int) { diff --git a/runtime/src/main/kotlin/kotlin/collections/ReversedViews.kt b/runtime/src/main/kotlin/kotlin/collections/ReversedViews.kt index 87eb9eb9d96..23365319b09 100644 --- a/runtime/src/main/kotlin/kotlin/collections/ReversedViews.kt +++ b/runtime/src/main/kotlin/kotlin/collections/ReversedViews.kt @@ -1,11 +1,11 @@ package kotlin.collections -/* + private open class ReversedListReadOnly(private val delegate: List) : AbstractList() { override val size: Int get() = delegate.size override fun get(index: Int): T = delegate[reverseElementIndex(index)] } - +/* private class ReversedList(private val delegate: MutableList) : AbstractMutableList() { override val size: Int get() = delegate.size override fun get(index: Int): T = delegate[reverseElementIndex(index)] @@ -17,7 +17,7 @@ private class ReversedList(private val delegate: MutableList) : AbstractMu override fun add(index: Int, element: T) { delegate.add(reversePositionIndex(index), element) } -} +}*/ private fun List<*>.reverseElementIndex(index: Int) = // TODO: Use AbstractList.checkElementIndex: run { AbstractList.checkElementIndex(index, size); lastIndex - index } if (index in 0..size - 1) size - index - 1 else throw IndexOutOfBoundsException("Index $index should be in range [${0..size - 1}].") @@ -30,7 +30,7 @@ private fun List<*>.reversePositionIndex(index: Int) = * All changes made in the original list will be reflected in the reversed one. */ public fun List.asReversed(): List = ReversedListReadOnly(this) - +/* /** * Returns a reversed mutable view of the original mutable List. * All changes made in the original list will be reflected in the reversed one and vice versa.