Access this through the dispatch parameter when available

This commit is contained in:
Steven Schäfer
2019-04-30 13:15:12 +02:00
committed by Georgy Bronnikov
parent 9b9236efcb
commit b04dc69157
4 changed files with 51 additions and 48 deletions
@@ -8,12 +8,14 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irSetField
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
@@ -28,6 +30,7 @@ import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
// This pass has to run after LocalDeclarationsLowering, since we don't handle nested functions.
val innerClassesPhase = makeIrFilePhase(
::InnerClassesLowering,
name = "InnerClasses",
@@ -76,21 +79,10 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
irClass.transformDeclarationsFlat { irMember -> (irMember as? IrConstructor)?.let { listOf(lowerConstructor(it)) } }
irClass.transformChildrenVoid(VariableRemapper(oldConstructorParameterToNew))
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
private var enclosingConstructor: IrConstructor? = null
// TODO: maybe add another transformer that skips specified elements
override fun visitClass(declaration: IrClass): IrStatement =
irClass.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
override fun visitClassNew(declaration: IrClass): IrStatement =
declaration
override fun visitConstructor(declaration: IrConstructor): IrStatement =
try {
enclosingConstructor = declaration
super.visitConstructor(declaration)
} finally {
enclosingConstructor = null
}
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this)
@@ -100,8 +92,10 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
val startOffset = expression.startOffset
val endOffset = expression.endOffset
val origin = expression.origin
val function = currentFunction?.irElement as? IrFunction
val enclosingThisReceiver = function?.dispatchReceiverParameter ?: irClass.thisReceiver!!
var irThis: IrExpression = IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol, origin)
var irThis: IrExpression = IrGetValueImpl(startOffset, endOffset, enclosingThisReceiver.symbol, origin)
var innerClass = irClass
while (innerClass != implicitThisClass) {
if (!innerClass.isInner) {
@@ -110,10 +104,10 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
return expression
}
irThis = if (enclosingConstructor != null && irClass == innerClass) {
irThis = if (function is IrConstructor && irClass == innerClass) {
// Might be before a super() call (e.g. an argument to one), in which case the JVM bytecode verifier will reject
// an attempt to access the field. Good thing we have a local variable as well.
IrGetValueImpl(startOffset, endOffset, enclosingConstructor!!.valueParameters[0].symbol, origin)
IrGetValueImpl(startOffset, endOffset, function.valueParameters[0].symbol, origin)
} else {
val outerThisField = context.declarationFactory.getOuterThisField(innerClass)
IrGetFieldImpl(startOffset, endOffset, outerThisField.symbol, outerThisField.type, irThis, origin)
@@ -234,7 +234,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
functionReferenceClass = buildClass {
setSourceRange(irFunctionReference)
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
name = "${callee.name}\$${functionReferenceCount++}".synthesizedName
name = "${callee.name.safeName()}\$${functionReferenceCount++}".synthesizedName
kind = ClassKind.CLASS
visibility = Visibilities.PUBLIC
modality = Modality.FINAL
@@ -403,7 +403,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
val argument = when {
!unboundArgsSet.contains(parameter) ->
// Bound parameter - read from field.
irGetField(irGet(functionReferenceThis.owner), argumentToFieldMap[parameter]!!)
irGetField(irGet(dispatchReceiverParameter!!), argumentToFieldMap[parameter]!!)
function.isSuspend && unboundIndex == valueParameters.size ->
// For suspend functions the last argument is continuation and it is implicit.
TODO()
@@ -111,7 +111,7 @@ private class FunctionNVarargInvokeLowering(var context: JvmBackendContext) : Cl
target.returnType,
target.returnType.classifierOrFail,
irCall(target).apply {
dispatchReceiver = irGet(irClass.thisReceiver!!)
dispatchReceiver = irGet(dispatchReceiverParameter!!)
target.valueParameters.forEachIndexed { i, irValueParameter ->
val type = irValueParameter.type
putValueArgument(
@@ -292,70 +292,79 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
}
}
fun buildOverride(method: IrSimpleFunction, build: IrBlockBodyBuilder.(List<IrValueParameter>) -> IrExpression) =
buildFun {
setSourceRange(expression)
name = method.name
returnType = method.returnType
visibility = method.visibility
origin = referenceClass.origin
}.apply {
parent = referenceClass
referenceClass.declarations.add(this)
overriddenSymbols.add(method.symbol)
dispatchReceiverParameter = referenceThis.copyTo(this)
for (parameter in method.valueParameters)
valueParameters.add(parameter.copyTo(this))
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
+irReturn(build(valueParameters))
}
fun buildOverride(
method: IrSimpleFunction,
build: IrBlockBodyBuilder.(IrValueParameter, List<IrValueParameter>) -> IrExpression
) = referenceClass.addFunction {
setSourceRange(expression)
name = method.name
returnType = method.returnType
visibility = method.visibility
origin = referenceClass.origin
}.apply {
overriddenSymbols.add(method.symbol)
val thisParameter = referenceThis.copyTo(this)
dispatchReceiverParameter = thisParameter
for (parameter in method.valueParameters)
valueParameters.add(parameter.copyTo(this))
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
+irReturn(build(thisParameter, valueParameters))
}
}
val receiverField = superClass.properties.single { it.name.asString() == "receiver" }.backingField!!
fun IrBuilderWithScope.setReceiversOn(call: IrCall, valueParameters: List<IrValueParameter>) {
fun IrBuilderWithScope.setReceiversOn(
call: IrCall,
dispatchReceiverParameter: IrValueParameter,
valueParameters: List<IrValueParameter>
) {
var index = 0
call.dispatchReceiver = call.symbol.owner.dispatchReceiverParameter?.let {
if (expression.dispatchReceiver != null)
irGetField(irGet(referenceThis), receiverField)
irGetField(irGet(dispatchReceiverParameter), receiverField)
else
irImplicitCast(irGet(valueParameters[index++]), it.type)
}
call.extensionReceiver = call.symbol.owner.extensionReceiverParameter?.let {
if (expression.extensionReceiver != null)
irGetField(irGet(referenceThis), receiverField)
irGetField(irGet(dispatchReceiverParameter), receiverField)
else
irImplicitCast(irGet(valueParameters[index++]), it.type)
}
}
buildOverride(superClass.functions.single { it.name.asString() == "getName" }) {
buildOverride(superClass.functions.single { it.name.asString() == "getName" }) { _, _ ->
irString(expression.descriptor.name.asString())
}
buildOverride(superClass.functions.single { it.name.asString() == "getOwner" }) {
buildOverride(superClass.functions.single { it.name.asString() == "getOwner" }) { _, _ ->
buildReflectedContainerReference(expression)
}
buildOverride(superClass.functions.single { it.name.asString() == "getSignature" }) {
buildOverride(superClass.functions.single { it.name.asString() == "getSignature" }) { _, _ ->
irString(expression.signature)
}
expression.getter?.owner?.let { getter ->
buildOverride(superClass.functions.single { it.name.asString() == "get" }) { valueParameters ->
buildOverride(superClass.functions.single { it.name.asString() == "get" }) { dispatchReceiverParameter, valueParameters ->
irGet(getter.returnType, null, getter.symbol).apply {
copyTypeArgumentsFrom(expression)
setReceiversOn(this, valueParameters)
setReceiversOn(
this,
dispatchReceiverParameter,
valueParameters
)
}
}
}
expression.setter?.owner?.let { setter ->
buildOverride(superClass.functions.single { it.name.asString() == "set" }) { valueParameters ->
val value = irGet(valueParameters.last())
buildOverride(superClass.functions.single { it.name.asString() == "set" }) { dispatchReceiverParameter, valueParameters ->
val type = setter.valueParameters.last().type
val value = irImplicitCast(irGet(valueParameters.last()), type)
irSet(setter.returnType, null, setter.symbol, value).apply {
copyTypeArgumentsFrom(expression)
setReceiversOn(this, valueParameters)
setReceiversOn(this, dispatchReceiverParameter, valueParameters)
}
}
}