Local objects (#215)
* bug fix * bug fix with nested inner classes * - fixed FixMeInner - support of inner classes in local classes - support of object expressions in initializers * comments * merged modification * - review fixes - tests * review fixes * review fixes
This commit is contained in:
+40
-29
@@ -1,38 +1,22 @@
|
|||||||
/*
|
package org.jetbrains.kotlin.backend.common.lower
|
||||||
* 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
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.expressions.IrValueAccessExpression
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrLocalDelegatedProperty
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
abstract class AbstractClosureRecorder : IrElementVisitorVoid {
|
// TODO: synchronize with JVM BE
|
||||||
|
class Closure(val capturedValues: List<ValueDescriptor>)
|
||||||
|
|
||||||
|
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 abstract class ClosureBuilder(open val owner: DeclarationDescriptor) {
|
||||||
val capturedValues = mutableSetOf<ValueDescriptor>()
|
val capturedValues = mutableSetOf<ValueDescriptor>()
|
||||||
|
|
||||||
fun buildClosure() = Closure(capturedValues.toList())
|
fun buildClosure() = Closure(capturedValues.toList())
|
||||||
@@ -43,12 +27,39 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid {
|
|||||||
|
|
||||||
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
|
isExternal(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract fun <T : CallableDescriptor> isExternal(valueDescriptor: T): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
private val closuresStack = ArrayDeque<ClosureBuilder>()
|
private class FunctionClosureBuilder(override val owner: FunctionDescriptor) : ClosureBuilder(owner) {
|
||||||
|
|
||||||
|
override fun <T : CallableDescriptor> isExternal(valueDescriptor: T): Boolean =
|
||||||
|
valueDescriptor.containingDeclaration != owner && valueDescriptor != owner.dispatchReceiverParameter
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ClassClosureBuilder(override val owner: ClassDescriptor) : ClosureBuilder(owner) {
|
||||||
|
|
||||||
|
override fun <T : CallableDescriptor> 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<ClosureBuilder>()
|
||||||
|
|
||||||
|
private fun <E> MutableList<E>.push(element: E) = this.add(element)
|
||||||
|
|
||||||
|
private fun <E> MutableList<E>.pop() = this.removeAt(size - 1)
|
||||||
|
|
||||||
|
private fun <E> MutableList<E>.peek(): E? = if (size == 0) null else this[size - 1]
|
||||||
|
|
||||||
override fun visitElement(element: IrElement) {
|
override fun visitElement(element: IrElement) {
|
||||||
element.acceptChildrenVoid(this)
|
element.acceptChildrenVoid(this)
|
||||||
@@ -56,7 +67,7 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid {
|
|||||||
|
|
||||||
override fun visitClass(declaration: IrClass) {
|
override fun visitClass(declaration: IrClass) {
|
||||||
val classDescriptor = declaration.descriptor
|
val classDescriptor = declaration.descriptor
|
||||||
val closureBuilder = ClosureBuilder(classDescriptor)
|
val closureBuilder = ClassClosureBuilder(classDescriptor)
|
||||||
|
|
||||||
closuresStack.push(closureBuilder)
|
closuresStack.push(closureBuilder)
|
||||||
declaration.acceptChildrenVoid(this)
|
declaration.acceptChildrenVoid(this)
|
||||||
@@ -73,7 +84,7 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid {
|
|||||||
|
|
||||||
override fun visitFunction(declaration: IrFunction) {
|
override fun visitFunction(declaration: IrFunction) {
|
||||||
val functionDescriptor = declaration.descriptor
|
val functionDescriptor = declaration.descriptor
|
||||||
val closureBuilder = ClosureBuilder(functionDescriptor)
|
val closureBuilder = FunctionClosureBuilder(functionDescriptor)
|
||||||
|
|
||||||
closuresStack.push(closureBuilder)
|
closuresStack.push(closureBuilder)
|
||||||
declaration.acceptChildrenVoid(this)
|
declaration.acceptChildrenVoid(this)
|
||||||
@@ -98,7 +109,7 @@ abstract class AbstractClosureRecorder : IrElementVisitorVoid {
|
|||||||
|
|
||||||
if (closureBuilder != null) {
|
if (closureBuilder != null) {
|
||||||
val variableDescriptor = expression.descriptor
|
val variableDescriptor = expression.descriptor
|
||||||
if (variableDescriptor.containingDeclaration != closureBuilder.owner) {
|
if (closureBuilder.isExternal(variableDescriptor)) {
|
||||||
closureBuilder.capturedValues.add(variableDescriptor)
|
closureBuilder.capturedValues.add(variableDescriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+82
-43
@@ -16,28 +16,32 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.backend.common.lower
|
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.BackendContext
|
||||||
import org.jetbrains.kotlin.backend.common.Closure
|
|
||||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
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.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
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.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||||
import org.jetbrains.kotlin.ir.visitors.*
|
import org.jetbrains.kotlin.ir.visitors.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
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.parents
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class LocalDeclarationsLowering(val context: BackendContext): DeclarationContainerLoweringPass {
|
class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContainerLoweringPass {
|
||||||
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
||||||
if (irDeclarationContainer is IrDeclaration &&
|
if (irDeclarationContainer is IrDeclaration &&
|
||||||
irDeclarationContainer.descriptor.parents.any { it is CallableDescriptor }) {
|
irDeclarationContainer.descriptor.parents.any { it is CallableDescriptor }) {
|
||||||
@@ -51,10 +55,13 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
lambdasCount = 0
|
lambdasCount = 0
|
||||||
|
|
||||||
irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
|
irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
|
||||||
if (memberDeclaration is IrFunction)
|
// TODO: may be do the opposite - specify the list of IR elements which need not to be transformed
|
||||||
LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
|
when (memberDeclaration) {
|
||||||
else
|
is IrFunction -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
|
||||||
null
|
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
|
val fieldDescriptor = capturedValueToField[descriptor] ?: return null
|
||||||
|
|
||||||
return IrGetFieldImpl(startOffset, endOffset, fieldDescriptor,
|
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}"
|
"LocalClassContext for ${descriptor}"
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class LocalDeclarationsTransformer(val memberFunction: IrFunction) {
|
private inner class LocalDeclarationsTransformer(val memberDeclaration: IrDeclaration) {
|
||||||
val localFunctions: MutableMap<FunctionDescriptor, LocalFunctionContext> = LinkedHashMap()
|
val localFunctions: MutableMap<FunctionDescriptor, LocalFunctionContext> = LinkedHashMap()
|
||||||
val localClasses: MutableMap<ClassDescriptor, LocalClassContext> = LinkedHashMap()
|
val localClasses: MutableMap<ClassDescriptor, LocalClassContext> = LinkedHashMap()
|
||||||
val localClassConstructors: MutableMap<ClassConstructorDescriptor, LocalClassConstructorContext> = LinkedHashMap()
|
val localClassConstructors: MutableMap<ClassConstructorDescriptor, LocalClassConstructorContext> = LinkedHashMap()
|
||||||
@@ -155,7 +162,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
|
|
||||||
private fun collectRewrittenDeclarations(): ArrayList<IrDeclaration> =
|
private fun collectRewrittenDeclarations(): ArrayList<IrDeclaration> =
|
||||||
ArrayList<IrDeclaration>(localFunctions.size + localClasses.size + 1).apply {
|
ArrayList<IrDeclaration>(localFunctions.size + localClasses.size + 1).apply {
|
||||||
add(memberFunction)
|
add(memberDeclaration)
|
||||||
|
|
||||||
localFunctions.values.mapTo(this) {
|
localFunctions.values.mapTo(this) {
|
||||||
val original = it.declaration
|
val original = it.declaration
|
||||||
@@ -174,8 +181,12 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
private inner class FunctionBodiesRewriter(val localContext: LocalContext?) : IrElementTransformerVoid() {
|
private inner class FunctionBodiesRewriter(val localContext: LocalContext?) : IrElementTransformerVoid() {
|
||||||
|
|
||||||
override fun visitClass(declaration: IrClass): IrStatement {
|
override fun visitClass(declaration: IrClass): IrStatement {
|
||||||
// Replace local class definition with an empty composite.
|
if (declaration.descriptor in localClasses) {
|
||||||
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
|
// 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 {
|
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||||
@@ -183,18 +194,20 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
// Replace local function definition with an empty composite.
|
// Replace local function definition with an empty composite.
|
||||||
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
|
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.builtIns.unitType)
|
||||||
} else {
|
} else {
|
||||||
declaration.transformChildrenVoid(this)
|
return super.visitFunction(declaration)
|
||||||
return declaration
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitConstructor(declaration: IrConstructor): IrStatement {
|
override fun visitConstructor(declaration: IrConstructor): IrStatement {
|
||||||
// Body is transformed separately.
|
// Body is transformed separately.
|
||||||
|
|
||||||
val transformedDescriptor = localClassConstructors[declaration.descriptor]!!.transformedDescriptor
|
val transformedDescriptor = localClassConstructors[declaration.descriptor]?.transformedDescriptor
|
||||||
|
if (transformedDescriptor != null) {
|
||||||
return IrConstructorImpl(declaration.startOffset, declaration.endOffset, declaration.origin,
|
return IrConstructorImpl(declaration.startOffset, declaration.endOffset, declaration.origin,
|
||||||
transformedDescriptor, declaration.body!!)
|
transformedDescriptor, declaration.body!!)
|
||||||
|
} else {
|
||||||
|
return super.visitConstructor(declaration)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
@@ -222,6 +235,21 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
return newCall
|
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 : IrMemberAccessExpression> T.fillArguments(oldExpression: IrMemberAccessExpression): T {
|
private fun <T : IrMemberAccessExpression> T.fillArguments(oldExpression: IrMemberAccessExpression): T {
|
||||||
|
|
||||||
mapValueParameters { newValueParameterDescriptor ->
|
mapValueParameters { newValueParameterDescriptor ->
|
||||||
@@ -233,7 +261,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
// The callee expects captured value as argument.
|
// The callee expects captured value as argument.
|
||||||
val capturedValueDescriptor =
|
val capturedValueDescriptor =
|
||||||
newParameterToCaptured[newValueParameterDescriptor] ?:
|
newParameterToCaptured[newValueParameterDescriptor] ?:
|
||||||
throw AssertionError("Non-mapped parameter $newValueParameterDescriptor")
|
throw AssertionError("Non-mapped parameter $newValueParameterDescriptor")
|
||||||
|
|
||||||
localContext?.irGet(
|
localContext?.irGet(
|
||||||
oldExpression.startOffset, oldExpression.endOffset,
|
oldExpression.startOffset, oldExpression.endOffset,
|
||||||
@@ -292,8 +320,8 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun rewriteFunctionBody(irFunction: IrFunction, localContext: LocalContext?) {
|
private fun rewriteFunctionBody(irDeclaration: IrDeclaration, localContext: LocalContext?) {
|
||||||
irFunction.transformChildrenVoid(FunctionBodiesRewriter(localContext))
|
irDeclaration.transformChildrenVoid(FunctionBodiesRewriter(localContext))
|
||||||
}
|
}
|
||||||
|
|
||||||
private object DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE :
|
private object DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE :
|
||||||
@@ -339,7 +367,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
rewriteClassMembers(it.declaration, it)
|
rewriteClassMembers(it.declaration, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
rewriteFunctionBody(memberFunction, null)
|
rewriteFunctionBody(memberDeclaration, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createNewCall(oldCall: IrCall, newCallee: CallableDescriptor) =
|
private fun createNewCall(oldCall: IrCall, newCallee: CallableDescriptor) =
|
||||||
@@ -395,12 +423,12 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
.toList().reversed()
|
.toList().reversed()
|
||||||
.map { suggestLocalName(it) }
|
.map { suggestLocalName(it) }
|
||||||
.joinToString(separator = "$")
|
.joinToString(separator = "$")
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun createLiftedDescriptor(localFunctionContext: LocalFunctionContext) {
|
private fun createLiftedDescriptor(localFunctionContext: LocalFunctionContext) {
|
||||||
val oldDescriptor = localFunctionContext.descriptor
|
val oldDescriptor = localFunctionContext.descriptor
|
||||||
|
|
||||||
val memberOwner = memberFunction.descriptor.containingDeclaration
|
val memberOwner = memberDeclaration.descriptor.containingDeclaration!!
|
||||||
val newDescriptor = SimpleFunctionDescriptorImpl.create(
|
val newDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||||
memberOwner,
|
memberOwner,
|
||||||
oldDescriptor.annotations,
|
oldDescriptor.annotations,
|
||||||
@@ -480,7 +508,15 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
// Do not substitute type parameters for now.
|
// Do not substitute type parameters for now.
|
||||||
val newTypeParameters = oldDescriptor.typeParameters
|
val newTypeParameters = oldDescriptor.typeParameters
|
||||||
|
|
||||||
val capturedValues = localClassContext.closure.capturedValues
|
val capturedValues = mutableListOf<ValueDescriptor>()
|
||||||
|
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)
|
val newValueParameters = createTransformedValueParameters(localFunctionContext, capturedValues)
|
||||||
|
|
||||||
@@ -560,8 +596,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
if (valueDescriptor.name.isSpecial) {
|
if (valueDescriptor.name.isSpecial) {
|
||||||
val oldNameStr = valueDescriptor.name.asString()
|
val oldNameStr = valueDescriptor.name.asString()
|
||||||
Name.identifier("$" + oldNameStr.substring(1, oldNameStr.length - 1))
|
Name.identifier("$" + oldNameStr.substring(1, oldNameStr.length - 1))
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
valueDescriptor.name
|
valueDescriptor.name
|
||||||
|
|
||||||
private fun createUnsubstitutedCapturedValueParameter(
|
private fun createUnsubstitutedCapturedValueParameter(
|
||||||
@@ -586,7 +621,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
|
|
||||||
|
|
||||||
private fun collectClosures() {
|
private fun collectClosures() {
|
||||||
memberFunction.acceptChildrenVoid(object : AbstractClosureRecorder() {
|
memberDeclaration.acceptChildrenVoid(object : AbstractClosureAnnotator() {
|
||||||
override fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure) {
|
override fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure) {
|
||||||
localFunctions[functionDescriptor]?.closure = closure
|
localFunctions[functionDescriptor]?.closure = closure
|
||||||
}
|
}
|
||||||
@@ -598,16 +633,17 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun collectLocalDeclarations() {
|
private fun collectLocalDeclarations() {
|
||||||
memberFunction.acceptChildrenVoid(object : IrElementVisitorVoid {
|
memberDeclaration.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||||
|
|
||||||
override fun visitElement(element: IrElement) {
|
override fun visitElement(element: IrElement) {
|
||||||
element.acceptChildrenVoid(this)
|
element.acceptChildrenVoid(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DeclarationDescriptor.isClassMember() = when (this.containingDeclaration) {
|
private fun DeclarationDescriptor.declaredInFunction() = when (this.containingDeclaration) {
|
||||||
is CallableDescriptor -> false
|
is CallableDescriptor -> true
|
||||||
is ClassDescriptor -> true
|
is ClassDescriptor -> false
|
||||||
else -> TODO(this.toString())
|
is PackageFragmentDescriptor -> false
|
||||||
|
else -> TODO(this.toString() + "\n" + this.containingDeclaration.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFunction(declaration: IrFunction) {
|
override fun visitFunction(declaration: IrFunction) {
|
||||||
@@ -615,7 +651,7 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
|
|
||||||
val descriptor = declaration.descriptor
|
val descriptor = declaration.descriptor
|
||||||
|
|
||||||
if (!descriptor.isClassMember()) {
|
if (descriptor.declaredInFunction()) {
|
||||||
val localFunctionContext = LocalFunctionContext(declaration)
|
val localFunctionContext = LocalFunctionContext(declaration)
|
||||||
|
|
||||||
localFunctions[descriptor] = localFunctionContext
|
localFunctions[descriptor] = localFunctionContext
|
||||||
@@ -631,7 +667,9 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
declaration.acceptChildrenVoid(this)
|
declaration.acceptChildrenVoid(this)
|
||||||
|
|
||||||
val descriptor = declaration.descriptor
|
val descriptor = declaration.descriptor
|
||||||
assert (descriptor.isClassMember())
|
assert(!descriptor.declaredInFunction())
|
||||||
|
|
||||||
|
if (descriptor.constructedClass.isInner) return
|
||||||
|
|
||||||
localClassConstructors[descriptor] = LocalClassConstructorContext(declaration)
|
localClassConstructors[descriptor] = LocalClassConstructorContext(declaration)
|
||||||
}
|
}
|
||||||
@@ -641,12 +679,13 @@ class LocalDeclarationsLowering(val context: BackendContext): DeclarationContain
|
|||||||
|
|
||||||
val descriptor = declaration.descriptor
|
val descriptor = declaration.descriptor
|
||||||
|
|
||||||
if (descriptor.isClassMember()) {
|
if (descriptor.isInner) return
|
||||||
assert (descriptor.isInner)
|
|
||||||
} else {
|
// Local nested classes can only be inner.
|
||||||
val localClassContext = LocalClassContext(declaration)
|
assert(descriptor.declaredInFunction())
|
||||||
localClasses[descriptor] = localClassContext
|
|
||||||
}
|
val localClassContext = LocalClassContext(declaration)
|
||||||
|
localClasses[descriptor] = localClassContext
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-5
@@ -20,11 +20,6 @@ internal class KonanLower(val context: Context) {
|
|||||||
phaser.phase(KonanPhase.LOWER_ENUMS) {
|
phaser.phase(KonanPhase.LOWER_ENUMS) {
|
||||||
EnumClassLowering(context).run(irFile)
|
EnumClassLowering(context).run(irFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
phaser.phase(KonanPhase.LOWER_INNER_CLASSES) {
|
|
||||||
InnerClassLowering(context).runOnFilePostfix(irFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
phaser.phase(KonanPhase.LOWER_VARARG) {
|
phaser.phase(KonanPhase.LOWER_VARARG) {
|
||||||
VarargInjectionLowering(context).runOnFilePostfix(irFile)
|
VarargInjectionLowering(context).runOnFilePostfix(irFile)
|
||||||
}
|
}
|
||||||
@@ -44,6 +39,9 @@ internal class KonanLower(val context: Context) {
|
|||||||
phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) {
|
phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) {
|
||||||
LocalDeclarationsLowering(context).runOnFilePostfix(irFile)
|
LocalDeclarationsLowering(context).runOnFilePostfix(irFile)
|
||||||
}
|
}
|
||||||
|
phaser.phase(KonanPhase.LOWER_INNER_CLASSES) {
|
||||||
|
InnerClassLowering(context).runOnFilePostfix(irFile)
|
||||||
|
}
|
||||||
phaser.phase(KonanPhase.LOWER_CALLABLES) {
|
phaser.phase(KonanPhase.LOWER_CALLABLES) {
|
||||||
CallableReferenceLowering(context).runOnFilePostfix(irFile)
|
CallableReferenceLowering(context).runOnFilePostfix(irFile)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -69,7 +69,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
|
|||||||
if (instanceInitializerIndex >= 0) {
|
if (instanceInitializerIndex >= 0) {
|
||||||
// Initializing constructor: initialize 'this.this$0' with '$outer'.
|
// Initializing constructor: initialize 'this.this$0' with '$outer'.
|
||||||
blockBody.statements.add(
|
blockBody.statements.add(
|
||||||
instanceInitializerIndex,
|
0,
|
||||||
IrSetFieldImpl(
|
IrSetFieldImpl(
|
||||||
startOffset, endOffset, outerThisFieldDescriptor,
|
startOffset, endOffset, outerThisFieldDescriptor,
|
||||||
IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter),
|
IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter),
|
||||||
@@ -117,7 +117,7 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
|
|||||||
val outerThisField = context.specialDescriptorsFactory.getOuterThisFieldDescriptor(innerClass)
|
val outerThisField = context.specialDescriptorsFactory.getOuterThisFieldDescriptor(innerClass)
|
||||||
irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField, irThis, origin)
|
irThis = IrGetFieldImpl(startOffset, endOffset, outerThisField, irThis, origin)
|
||||||
|
|
||||||
val outer = classDescriptor.containingDeclaration
|
val outer = innerClass.containingDeclaration
|
||||||
innerClass = outer as? ClassDescriptor ?:
|
innerClass = outer as? ClassDescriptor ?:
|
||||||
throw AssertionError("Unexpected containing declaration for inner class $innerClass: $outer")
|
throw AssertionError("Unexpected containing declaration for inner class $innerClass: $outer")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -357,11 +357,46 @@ task innerClass_generic(type: RunKonanTest) {
|
|||||||
source = "codegen/innerClass/generic.kt"
|
source = "codegen/innerClass/generic.kt"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task innerClass_doubleInner(type: RunKonanTest) {
|
||||||
|
goldValue = "OK\n"
|
||||||
|
source = "codegen/innerClass/doubleInner.kt"
|
||||||
|
}
|
||||||
|
|
||||||
task innerClass_qualifiedThis(type: RunKonanTest) {
|
task innerClass_qualifiedThis(type: RunKonanTest) {
|
||||||
goldValue = "OK\n"
|
goldValue = "OK\n"
|
||||||
source = "codegen/innerClass/qualifiedThis.kt"
|
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) {
|
task array0(type: RunKonanTest) {
|
||||||
goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n"
|
goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n"
|
||||||
source = "runtime/collections/array0.kt"
|
source = "runtime/collections/array0.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<String>) {
|
||||||
|
println(box())
|
||||||
|
}
|
||||||
@@ -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<String>) {
|
||||||
|
println(box())
|
||||||
|
}
|
||||||
@@ -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<String>) {
|
||||||
|
box()
|
||||||
|
}
|
||||||
@@ -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<String>) {
|
||||||
|
println(box("OK"))
|
||||||
|
}
|
||||||
@@ -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<String>) {
|
||||||
|
println(foo("OK"))
|
||||||
|
}
|
||||||
@@ -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<String>) {
|
||||||
|
println(box())
|
||||||
|
}
|
||||||
@@ -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<String>) {
|
||||||
|
println(box())
|
||||||
|
}
|
||||||
backend.native/tests/external/codegen/blackbox/innerNested/superConstructorCall/innerExtendsOuter.kt
Vendored
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
open class Outer(vararg val chars: Char) {
|
open class Outer(vararg val chars: Char) {
|
||||||
open inner class Inner(val s: String): Outer(s[0], s[1]) {
|
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()
|
fun value() = Inner("OK").concat()
|
||||||
|
|||||||
@@ -24,13 +24,6 @@ annotation class ExportTypeInfo(val name: String)
|
|||||||
public annotation class Used
|
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.
|
* Need to be fixed because of reification support.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -8,20 +8,15 @@ public abstract class AbstractList<out E> protected constructor() : AbstractColl
|
|||||||
abstract override val size: Int
|
abstract override val size: Int
|
||||||
abstract override fun get(index: Int): E
|
abstract override fun get(index: Int): E
|
||||||
|
|
||||||
// TODO: fix once have inner classes.
|
override fun iterator(): Iterator<E> = IteratorImpl()
|
||||||
@FixmeInner
|
|
||||||
override fun iterator(): Iterator<E> = TODO() // IteratorImpl()
|
|
||||||
|
|
||||||
override fun indexOf(element: @UnsafeVariance E): Int = indexOfFirst { it == element }
|
override fun indexOf(element: @UnsafeVariance E): Int = indexOfFirst { it == element }
|
||||||
|
|
||||||
override fun lastIndexOf(element: @UnsafeVariance E): Int = indexOfLast { it == element }
|
override fun lastIndexOf(element: @UnsafeVariance E): Int = indexOfLast { it == element }
|
||||||
|
|
||||||
// TODO: fix once have inner classes.
|
override fun listIterator(): ListIterator<E> = ListIteratorImpl(0)
|
||||||
@FixmeInner
|
|
||||||
override fun listIterator(): ListIterator<E> = TODO() // ListIteratorImpl(0)
|
|
||||||
|
|
||||||
@FixmeInner
|
override fun listIterator(index: Int): ListIterator<E> = ListIteratorImpl(index)
|
||||||
override fun listIterator(index: Int): ListIterator<E> = TODO() // ListIteratorImpl(index)
|
|
||||||
|
|
||||||
override fun subList(fromIndex: Int, toIndex: Int): List<E> = SubList(this, fromIndex, toIndex)
|
override fun subList(fromIndex: Int, toIndex: Int): List<E> = SubList(this, fromIndex, toIndex)
|
||||||
|
|
||||||
@@ -52,8 +47,7 @@ public abstract class AbstractList<out E> protected constructor() : AbstractColl
|
|||||||
|
|
||||||
override fun hashCode(): Int = orderedHashCode(this)
|
override fun hashCode(): Int = orderedHashCode(this)
|
||||||
|
|
||||||
// TODO: enable, once have inner classes.
|
|
||||||
/*
|
|
||||||
private open inner class IteratorImpl : Iterator<E> {
|
private open inner class IteratorImpl : Iterator<E> {
|
||||||
/** the index of the item that will be returned on the next call to [next]`()` */
|
/** the index of the item that will be returned on the next call to [next]`()` */
|
||||||
protected var index = 0
|
protected var index = 0
|
||||||
@@ -86,7 +80,7 @@ public abstract class AbstractList<out E> protected constructor() : AbstractColl
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun previousIndex(): Int = index - 1
|
override fun previousIndex(): Int = index - 1
|
||||||
} */
|
}
|
||||||
|
|
||||||
internal companion object {
|
internal companion object {
|
||||||
internal fun checkElementIndex(index: Int, size: Int) {
|
internal fun checkElementIndex(index: Int, size: Int) {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package kotlin.collections
|
package kotlin.collections
|
||||||
/*
|
|
||||||
private open class ReversedListReadOnly<out T>(private val delegate: List<T>) : AbstractList<T>() {
|
private open class ReversedListReadOnly<out T>(private val delegate: List<T>) : AbstractList<T>() {
|
||||||
override val size: Int get() = delegate.size
|
override val size: Int get() = delegate.size
|
||||||
override fun get(index: Int): T = delegate[reverseElementIndex(index)]
|
override fun get(index: Int): T = delegate[reverseElementIndex(index)]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
private class ReversedList<T>(private val delegate: MutableList<T>) : AbstractMutableList<T>() {
|
private class ReversedList<T>(private val delegate: MutableList<T>) : AbstractMutableList<T>() {
|
||||||
override val size: Int get() = delegate.size
|
override val size: Int get() = delegate.size
|
||||||
override fun get(index: Int): T = delegate[reverseElementIndex(index)]
|
override fun get(index: Int): T = delegate[reverseElementIndex(index)]
|
||||||
@@ -17,7 +17,7 @@ private class ReversedList<T>(private val delegate: MutableList<T>) : AbstractMu
|
|||||||
override fun add(index: Int, element: T) {
|
override fun add(index: Int, element: T) {
|
||||||
delegate.add(reversePositionIndex(index), element)
|
delegate.add(reversePositionIndex(index), element)
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
private fun List<*>.reverseElementIndex(index: Int) = // TODO: Use AbstractList.checkElementIndex: run { AbstractList.checkElementIndex(index, size); lastIndex - index }
|
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}].")
|
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.
|
* All changes made in the original list will be reflected in the reversed one.
|
||||||
*/
|
*/
|
||||||
public fun <T> List<T>.asReversed(): List<T> = ReversedListReadOnly(this)
|
public fun <T> List<T>.asReversed(): List<T> = ReversedListReadOnly(this)
|
||||||
|
/*
|
||||||
/**
|
/**
|
||||||
* Returns a reversed mutable view of the original mutable List.
|
* 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.
|
* All changes made in the original list will be reflected in the reversed one and vice versa.
|
||||||
|
|||||||
Reference in New Issue
Block a user