Containing declaration elimination (#225)
* rewrote AbstractClosureAnnotator not using containingDeclaration * bug fix * bug fix * review fixes + tests * review fixes * refactoring * fix
This commit is contained in:
+43
-35
@@ -10,6 +10,7 @@ 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 org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
|
||||
// TODO: synchronize with JVM BE
|
||||
class Closure(val capturedValues: List<ValueDescriptor>)
|
||||
@@ -18,8 +19,9 @@ abstract class AbstractClosureAnnotator : IrElementVisitorVoid {
|
||||
protected abstract fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure)
|
||||
protected abstract fun recordClassClosure(classDescriptor: ClassDescriptor, closure: Closure)
|
||||
|
||||
private abstract class ClosureBuilder(open val owner: DeclarationDescriptor) {
|
||||
private class ClosureBuilder {
|
||||
val capturedValues = mutableSetOf<ValueDescriptor>()
|
||||
private val declaredValues = mutableSetOf<ValueDescriptor>()
|
||||
|
||||
fun buildClosure() = Closure(capturedValues.toList())
|
||||
|
||||
@@ -27,34 +29,26 @@ abstract class AbstractClosureAnnotator : IrElementVisitorVoid {
|
||||
fillInNestedClosure(capturedValues, closure.capturedValues)
|
||||
}
|
||||
|
||||
private fun <T : CallableDescriptor> fillInNestedClosure(destination: MutableSet<T>, nested: List<T>) {
|
||||
nested.filterTo(destination) {
|
||||
isExternal(it)
|
||||
}
|
||||
private fun fillInNestedClosure(destination: MutableSet<ValueDescriptor>, nested: List<ValueDescriptor>) {
|
||||
nested.filterTo(destination) { isExternal(it) }
|
||||
}
|
||||
|
||||
abstract fun <T : CallableDescriptor> isExternal(valueDescriptor: T): Boolean
|
||||
}
|
||||
|
||||
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
|
||||
fun declareVariable(valueDescriptor: ValueDescriptor?) {
|
||||
if (valueDescriptor != null)
|
||||
declaredValues.add(valueDescriptor)
|
||||
}
|
||||
|
||||
fun seeVariable(valueDescriptor: ValueDescriptor) {
|
||||
if (isExternal(valueDescriptor))
|
||||
capturedValues.add(valueDescriptor)
|
||||
}
|
||||
|
||||
fun isExternal(valueDescriptor: ValueDescriptor): Boolean {
|
||||
return !declaredValues.contains(valueDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
private val classClosures = mutableMapOf<ClassDescriptor, Closure>()
|
||||
private val closuresStack = mutableListOf<ClosureBuilder>()
|
||||
|
||||
private fun <E> MutableList<E>.push(element: E) = this.add(element)
|
||||
@@ -69,16 +63,28 @@ abstract class AbstractClosureAnnotator : IrElementVisitorVoid {
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
val classDescriptor = declaration.descriptor
|
||||
val closureBuilder = ClassClosureBuilder(classDescriptor)
|
||||
val closureBuilder = ClosureBuilder()
|
||||
|
||||
closureBuilder.declareVariable(classDescriptor.thisAsReceiverParameter)
|
||||
if (classDescriptor.isInner)
|
||||
closureBuilder.declareVariable((classDescriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter)
|
||||
|
||||
closuresStack.push(closureBuilder)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
closuresStack.pop()
|
||||
|
||||
val superClassClosure = classClosures[classDescriptor.getSuperClassOrAny()]
|
||||
if (superClassClosure != null) {
|
||||
// Capture all values from the super class since we need to call constructor of super class
|
||||
// with its captured values.
|
||||
closureBuilder.addNested(superClassClosure)
|
||||
}
|
||||
|
||||
val closure = closureBuilder.buildClosure()
|
||||
|
||||
if (DescriptorUtils.isLocal(classDescriptor)) {
|
||||
recordClassClosure(classDescriptor, closure)
|
||||
classClosures[classDescriptor] = closure
|
||||
}
|
||||
|
||||
closuresStack.peek()?.addNested(closure)
|
||||
@@ -86,7 +92,13 @@ abstract class AbstractClosureAnnotator : IrElementVisitorVoid {
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
val functionDescriptor = declaration.descriptor
|
||||
val closureBuilder = FunctionClosureBuilder(functionDescriptor)
|
||||
val closureBuilder = ClosureBuilder()
|
||||
|
||||
functionDescriptor.valueParameters.forEach { closureBuilder.declareVariable(it) }
|
||||
closureBuilder.declareVariable(functionDescriptor.dispatchReceiverParameter)
|
||||
closureBuilder.declareVariable(functionDescriptor.extensionReceiverParameter)
|
||||
if (functionDescriptor is ConstructorDescriptor)
|
||||
closureBuilder.declareVariable(functionDescriptor.constructedClass.thisAsReceiverParameter)
|
||||
|
||||
closuresStack.push(closureBuilder)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
@@ -107,16 +119,12 @@ abstract class AbstractClosureAnnotator : IrElementVisitorVoid {
|
||||
}
|
||||
|
||||
override fun visitVariableAccess(expression: IrValueAccessExpression) {
|
||||
val closureBuilder = closuresStack.peek()
|
||||
|
||||
if (closureBuilder != null) {
|
||||
val variableDescriptor = expression.descriptor
|
||||
if (closureBuilder.isExternal(variableDescriptor)) {
|
||||
closureBuilder.capturedValues.add(variableDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
expression.acceptChildrenVoid(this)
|
||||
closuresStack.peek()?.seeVariable(expression.descriptor)
|
||||
super.visitVariableAccess(expression)
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable) {
|
||||
closuresStack.peek()?.declareVariable(declaration.descriptor)
|
||||
super.visitVariable(declaration)
|
||||
}
|
||||
}
|
||||
+17
-21
@@ -269,7 +269,8 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
|
||||
capturedValueDescriptor
|
||||
) ?:
|
||||
// Captured value is directly available for the caller.
|
||||
IrGetValueImpl(oldExpression.startOffset, oldExpression.endOffset, capturedValueDescriptor)
|
||||
IrGetValueImpl(oldExpression.startOffset, oldExpression.endOffset,
|
||||
oldParameterToNew[capturedValueDescriptor] ?: capturedValueDescriptor)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -334,12 +335,11 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
|
||||
private fun rewriteClassMembers(irClass: IrClass, localClassContext: LocalClassContext) {
|
||||
irClass.transformChildrenVoid(FunctionBodiesRewriter(localClassContext))
|
||||
|
||||
val primaryConstructor = irClass.descriptor.unsubstitutedPrimaryConstructor ?:
|
||||
TODO("local classes without primary constructor")
|
||||
|
||||
val primaryConstructorContext = localClassConstructors[primaryConstructor]!!
|
||||
val primaryConstructorBody = primaryConstructorContext.declaration.body as? IrBlockBody
|
||||
?: throw AssertionError("Unexpected constructor body: ${primaryConstructorContext.declaration.body}")
|
||||
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, fieldDescriptor ->
|
||||
val startOffset = irClass.startOffset
|
||||
@@ -352,11 +352,15 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
|
||||
)
|
||||
)
|
||||
|
||||
val capturedValueExpression = primaryConstructorContext.irGet(startOffset, endOffset, capturedValue)!!
|
||||
val capturedValueInitializer = IrSetFieldImpl(startOffset, endOffset, fieldDescriptor,
|
||||
IrGetValueImpl(startOffset, endOffset, irClass.descriptor.thisAsReceiverParameter),
|
||||
capturedValueExpression, STATEMENT_ORIGIN_INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE)
|
||||
primaryConstructorBody.statements.add(0, capturedValueInitializer)
|
||||
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, fieldDescriptor,
|
||||
IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter),
|
||||
capturedValueExpression, STATEMENT_ORIGIN_INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,15 +518,7 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
|
||||
// Do not substitute type parameters for now.
|
||||
val newTypeParameters = oldDescriptor.typeParameters
|
||||
|
||||
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 capturedValues = localClasses[oldDescriptor.containingDeclaration]!!.closure.capturedValues
|
||||
|
||||
val newValueParameters = createTransformedValueParameters(localFunctionContext, capturedValues)
|
||||
|
||||
|
||||
+33
@@ -6,11 +6,17 @@ import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.NonReportingOverrideStrategy
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -91,4 +97,31 @@ class SimpleMemberScope(val members: List<DeclarationDescriptor>) : MemberScopeI
|
||||
|
||||
override fun printScopeStructure(p: Printer) = TODO("not implemented")
|
||||
|
||||
}
|
||||
|
||||
fun IrConstructor.callsSuper(): Boolean {
|
||||
val constructedClass = descriptor.constructedClass
|
||||
val superClass = constructedClass.getSuperClassOrAny()
|
||||
var callsSuper = false
|
||||
var numberOfCalls = 0
|
||||
acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
// Skip nested
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
|
||||
assert(++numberOfCalls == 1, { "More than one delegating constructor call: $descriptor" })
|
||||
if (expression.descriptor.constructedClass == superClass)
|
||||
callsSuper = true
|
||||
else if (expression.descriptor.constructedClass != constructedClass)
|
||||
throw AssertionError("Expected either call to another constructor of the class being constructed or" +
|
||||
" call to super class constructor. But was: ${expression.descriptor.constructedClass}")
|
||||
}
|
||||
})
|
||||
assert(numberOfCalls == 1, { "Expected exactly one delegating constructor call but none encountered: $descriptor" })
|
||||
return callsSuper
|
||||
}
|
||||
+3
-3
@@ -43,15 +43,15 @@ internal class KonanLower(val context: Context) {
|
||||
phaser.phase(KonanPhase.LOWER_SHARED_VARIABLES) {
|
||||
SharedVariablesLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
|
||||
InitializersLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) {
|
||||
LocalDeclarationsLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_INNER_CLASSES) {
|
||||
InnerClassLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
|
||||
InitializersLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
phaser.phase(KonanPhase.LOWER_CALLABLES) {
|
||||
CallableReferenceLowering(context).runOnFilePostfix(irFile)
|
||||
}
|
||||
|
||||
+11
-20
@@ -1,8 +1,10 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.callsSuper
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
|
||||
@@ -12,7 +14,10 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||
|
||||
@@ -57,35 +62,21 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
|
||||
}
|
||||
|
||||
private fun lowerConstructor(irConstructor: IrConstructor): IrConstructor {
|
||||
val descriptor = irConstructor.descriptor
|
||||
val startOffset = irConstructor.startOffset
|
||||
val endOffset = irConstructor.endOffset
|
||||
|
||||
val dispatchReceiver = descriptor.dispatchReceiverParameter!!
|
||||
|
||||
val blockBody = irConstructor.body as? IrBlockBody ?: throw AssertionError("Unexpected constructor body: ${irConstructor.body}")
|
||||
|
||||
val instanceInitializerIndex = blockBody.statements.indexOfFirst { it is IrInstanceInitializerCall }
|
||||
if (instanceInitializerIndex >= 0) {
|
||||
if (irConstructor.callsSuper()) {
|
||||
// Initializing constructor: initialize 'this.this$0' with '$outer'.
|
||||
val blockBody = irConstructor.body as? IrBlockBody
|
||||
?: throw AssertionError("Unexpected constructor body: ${irConstructor.body}")
|
||||
val startOffset = irConstructor.startOffset
|
||||
val endOffset = irConstructor.endOffset
|
||||
blockBody.statements.add(
|
||||
0,
|
||||
IrSetFieldImpl(
|
||||
startOffset, endOffset, outerThisFieldDescriptor,
|
||||
IrGetValueImpl(startOffset, endOffset, classDescriptor.thisAsReceiverParameter),
|
||||
IrGetValueImpl(startOffset, endOffset, dispatchReceiver)
|
||||
IrGetValueImpl(startOffset, endOffset, irConstructor.descriptor.dispatchReceiverParameter!!)
|
||||
)
|
||||
)
|
||||
}
|
||||
else {
|
||||
// Delegating constructor: invoke old constructor with dispatch receiver '$outer'.
|
||||
val delegatingConstructorCall = (blockBody.statements.find { it is IrDelegatingConstructorCall } ?:
|
||||
throw AssertionError("Delegating constructor call expected: ${irConstructor.dump()}")
|
||||
) as IrDelegatingConstructorCall
|
||||
delegatingConstructorCall.dispatchReceiver = IrGetValueImpl(
|
||||
delegatingConstructorCall.startOffset, delegatingConstructorCall.endOffset, dispatchReceiver
|
||||
)
|
||||
}
|
||||
|
||||
return irConstructor
|
||||
}
|
||||
|
||||
@@ -128,7 +128,6 @@ task objectInitialization(type: RunKonanTest) {
|
||||
}
|
||||
|
||||
task objectInitialization1(type: RunKonanTest) {
|
||||
disabled = true
|
||||
goldValue = "init\nfield\nconstructor1\ninit\nfield\nconstructor1\nconstructor2\n"
|
||||
source = "codegen/object/initialization1.kt"
|
||||
}
|
||||
@@ -379,6 +378,11 @@ task innerClass_superOuter(type: RunKonanTest) {
|
||||
source = "codegen/innerClass/superOuter.kt"
|
||||
}
|
||||
|
||||
task innerClass_noPrimaryConstructor(type: RunKonanTest) {
|
||||
goldValue = "OK\nOK\n"
|
||||
source = "codegen/innerClass/noPrimaryConstructor.kt"
|
||||
}
|
||||
|
||||
task localClass_localHierarchy(type: RunKonanTest) {
|
||||
goldValue = "OK\n"
|
||||
source = "codegen/localClass/localHierarchy.kt"
|
||||
@@ -409,6 +413,11 @@ task localClass_virtualCallFromConstructor(type: RunKonanTest) {
|
||||
source = "codegen/localClass/virtualCallFromConstructor.kt"
|
||||
}
|
||||
|
||||
task localClass_noPrimaryConstructor(type: RunKonanTest) {
|
||||
goldValue = "OKOK\n"
|
||||
source = "codegen/localClass/noPrimaryConstructor.kt"
|
||||
}
|
||||
|
||||
task initializers_correctOrder1(type: RunKonanTest) {
|
||||
goldValue = "42\n"
|
||||
source = "codegen/initializers/correctOrder1.kt"
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
class Outer(val s: String) {
|
||||
inner class Inner {
|
||||
constructor(x: Int) {
|
||||
this.x = x
|
||||
}
|
||||
|
||||
constructor(z: String) {
|
||||
x = z.length
|
||||
}
|
||||
|
||||
val x: Int
|
||||
|
||||
fun foo() = s
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(Outer("OK").Inner(42).foo())
|
||||
println(Outer("OK").Inner("zzz").foo())
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
fun box(s: String): String {
|
||||
class Local {
|
||||
constructor(x: Int) {
|
||||
this.x = x
|
||||
}
|
||||
|
||||
constructor(z: String) {
|
||||
x = z.length
|
||||
}
|
||||
|
||||
val x: Int
|
||||
|
||||
fun result() = s
|
||||
}
|
||||
|
||||
return Local(42).result() + Local("zzz").result()
|
||||
}
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
println(box("OK"))
|
||||
}
|
||||
Reference in New Issue
Block a user