Access this through the dispatch parameter when available
This commit is contained in:
committed by
Georgy Bronnikov
parent
9b9236efcb
commit
b04dc69157
+10
-16
@@ -8,12 +8,14 @@ package org.jetbrains.kotlin.backend.common.lower
|
|||||||
import org.jetbrains.kotlin.backend.common.BackendContext
|
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
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.backend.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.ir.IrStatement
|
import org.jetbrains.kotlin.ir.IrStatement
|
||||||
import org.jetbrains.kotlin.ir.builders.irGet
|
import org.jetbrains.kotlin.ir.builders.irGet
|
||||||
import org.jetbrains.kotlin.ir.builders.irSetField
|
import org.jetbrains.kotlin.ir.builders.irSetField
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
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.declarations.IrValueParameter
|
||||||
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.*
|
||||||
@@ -28,6 +30,7 @@ import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat
|
|||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
|
||||||
|
// This pass has to run after LocalDeclarationsLowering, since we don't handle nested functions.
|
||||||
val innerClassesPhase = makeIrFilePhase(
|
val innerClassesPhase = makeIrFilePhase(
|
||||||
::InnerClassesLowering,
|
::InnerClassesLowering,
|
||||||
name = "InnerClasses",
|
name = "InnerClasses",
|
||||||
@@ -76,21 +79,10 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
|
|||||||
irClass.transformDeclarationsFlat { irMember -> (irMember as? IrConstructor)?.let { listOf(lowerConstructor(it)) } }
|
irClass.transformDeclarationsFlat { irMember -> (irMember as? IrConstructor)?.let { listOf(lowerConstructor(it)) } }
|
||||||
irClass.transformChildrenVoid(VariableRemapper(oldConstructorParameterToNew))
|
irClass.transformChildrenVoid(VariableRemapper(oldConstructorParameterToNew))
|
||||||
|
|
||||||
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
|
irClass.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||||
private var enclosingConstructor: IrConstructor? = null
|
override fun visitClassNew(declaration: IrClass): IrStatement =
|
||||||
|
|
||||||
// TODO: maybe add another transformer that skips specified elements
|
|
||||||
override fun visitClass(declaration: IrClass): IrStatement =
|
|
||||||
declaration
|
declaration
|
||||||
|
|
||||||
override fun visitConstructor(declaration: IrConstructor): IrStatement =
|
|
||||||
try {
|
|
||||||
enclosingConstructor = declaration
|
|
||||||
super.visitConstructor(declaration)
|
|
||||||
} finally {
|
|
||||||
enclosingConstructor = null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||||
expression.transformChildrenVoid(this)
|
expression.transformChildrenVoid(this)
|
||||||
|
|
||||||
@@ -100,8 +92,10 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
|
|||||||
val startOffset = expression.startOffset
|
val startOffset = expression.startOffset
|
||||||
val endOffset = expression.endOffset
|
val endOffset = expression.endOffset
|
||||||
val origin = expression.origin
|
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
|
var innerClass = irClass
|
||||||
while (innerClass != implicitThisClass) {
|
while (innerClass != implicitThisClass) {
|
||||||
if (!innerClass.isInner) {
|
if (!innerClass.isInner) {
|
||||||
@@ -110,10 +104,10 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
|
|||||||
return expression
|
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
|
// 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.
|
// 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 {
|
} else {
|
||||||
val outerThisField = context.declarationFactory.getOuterThisField(innerClass)
|
val outerThisField = context.declarationFactory.getOuterThisField(innerClass)
|
||||||
IrGetFieldImpl(startOffset, endOffset, outerThisField.symbol, outerThisField.type, irThis, origin)
|
IrGetFieldImpl(startOffset, endOffset, outerThisField.symbol, outerThisField.type, irThis, origin)
|
||||||
|
|||||||
+2
-2
@@ -234,7 +234,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
functionReferenceClass = buildClass {
|
functionReferenceClass = buildClass {
|
||||||
setSourceRange(irFunctionReference)
|
setSourceRange(irFunctionReference)
|
||||||
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
|
||||||
name = "${callee.name}\$${functionReferenceCount++}".synthesizedName
|
name = "${callee.name.safeName()}\$${functionReferenceCount++}".synthesizedName
|
||||||
kind = ClassKind.CLASS
|
kind = ClassKind.CLASS
|
||||||
visibility = Visibilities.PUBLIC
|
visibility = Visibilities.PUBLIC
|
||||||
modality = Modality.FINAL
|
modality = Modality.FINAL
|
||||||
@@ -403,7 +403,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
|
|||||||
val argument = when {
|
val argument = when {
|
||||||
!unboundArgsSet.contains(parameter) ->
|
!unboundArgsSet.contains(parameter) ->
|
||||||
// Bound parameter - read from field.
|
// Bound parameter - read from field.
|
||||||
irGetField(irGet(functionReferenceThis.owner), argumentToFieldMap[parameter]!!)
|
irGetField(irGet(dispatchReceiverParameter!!), argumentToFieldMap[parameter]!!)
|
||||||
function.isSuspend && unboundIndex == valueParameters.size ->
|
function.isSuspend && unboundIndex == valueParameters.size ->
|
||||||
// For suspend functions the last argument is continuation and it is implicit.
|
// For suspend functions the last argument is continuation and it is implicit.
|
||||||
TODO()
|
TODO()
|
||||||
|
|||||||
+1
-1
@@ -111,7 +111,7 @@ private class FunctionNVarargInvokeLowering(var context: JvmBackendContext) : Cl
|
|||||||
target.returnType,
|
target.returnType,
|
||||||
target.returnType.classifierOrFail,
|
target.returnType.classifierOrFail,
|
||||||
irCall(target).apply {
|
irCall(target).apply {
|
||||||
dispatchReceiver = irGet(irClass.thisReceiver!!)
|
dispatchReceiver = irGet(dispatchReceiverParameter!!)
|
||||||
target.valueParameters.forEachIndexed { i, irValueParameter ->
|
target.valueParameters.forEachIndexed { i, irValueParameter ->
|
||||||
val type = irValueParameter.type
|
val type = irValueParameter.type
|
||||||
putValueArgument(
|
putValueArgument(
|
||||||
|
|||||||
+38
-29
@@ -292,70 +292,79 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun buildOverride(method: IrSimpleFunction, build: IrBlockBodyBuilder.(List<IrValueParameter>) -> IrExpression) =
|
fun buildOverride(
|
||||||
buildFun {
|
method: IrSimpleFunction,
|
||||||
setSourceRange(expression)
|
build: IrBlockBodyBuilder.(IrValueParameter, List<IrValueParameter>) -> IrExpression
|
||||||
name = method.name
|
) = referenceClass.addFunction {
|
||||||
returnType = method.returnType
|
setSourceRange(expression)
|
||||||
visibility = method.visibility
|
name = method.name
|
||||||
origin = referenceClass.origin
|
returnType = method.returnType
|
||||||
}.apply {
|
visibility = method.visibility
|
||||||
parent = referenceClass
|
origin = referenceClass.origin
|
||||||
referenceClass.declarations.add(this)
|
}.apply {
|
||||||
|
overriddenSymbols.add(method.symbol)
|
||||||
overriddenSymbols.add(method.symbol)
|
val thisParameter = referenceThis.copyTo(this)
|
||||||
dispatchReceiverParameter = referenceThis.copyTo(this)
|
dispatchReceiverParameter = thisParameter
|
||||||
for (parameter in method.valueParameters)
|
for (parameter in method.valueParameters)
|
||||||
valueParameters.add(parameter.copyTo(this))
|
valueParameters.add(parameter.copyTo(this))
|
||||||
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
|
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
|
||||||
+irReturn(build(valueParameters))
|
+irReturn(build(thisParameter, valueParameters))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val receiverField = superClass.properties.single { it.name.asString() == "receiver" }.backingField!!
|
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
|
var index = 0
|
||||||
call.dispatchReceiver = call.symbol.owner.dispatchReceiverParameter?.let {
|
call.dispatchReceiver = call.symbol.owner.dispatchReceiverParameter?.let {
|
||||||
if (expression.dispatchReceiver != null)
|
if (expression.dispatchReceiver != null)
|
||||||
irGetField(irGet(referenceThis), receiverField)
|
irGetField(irGet(dispatchReceiverParameter), receiverField)
|
||||||
else
|
else
|
||||||
irImplicitCast(irGet(valueParameters[index++]), it.type)
|
irImplicitCast(irGet(valueParameters[index++]), it.type)
|
||||||
}
|
}
|
||||||
call.extensionReceiver = call.symbol.owner.extensionReceiverParameter?.let {
|
call.extensionReceiver = call.symbol.owner.extensionReceiverParameter?.let {
|
||||||
if (expression.extensionReceiver != null)
|
if (expression.extensionReceiver != null)
|
||||||
irGetField(irGet(referenceThis), receiverField)
|
irGetField(irGet(dispatchReceiverParameter), receiverField)
|
||||||
else
|
else
|
||||||
irImplicitCast(irGet(valueParameters[index++]), it.type)
|
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())
|
irString(expression.descriptor.name.asString())
|
||||||
}
|
}
|
||||||
|
|
||||||
buildOverride(superClass.functions.single { it.name.asString() == "getOwner" }) {
|
buildOverride(superClass.functions.single { it.name.asString() == "getOwner" }) { _, _ ->
|
||||||
buildReflectedContainerReference(expression)
|
buildReflectedContainerReference(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
buildOverride(superClass.functions.single { it.name.asString() == "getSignature" }) {
|
buildOverride(superClass.functions.single { it.name.asString() == "getSignature" }) { _, _ ->
|
||||||
irString(expression.signature)
|
irString(expression.signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
expression.getter?.owner?.let { getter ->
|
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 {
|
irGet(getter.returnType, null, getter.symbol).apply {
|
||||||
copyTypeArgumentsFrom(expression)
|
copyTypeArgumentsFrom(expression)
|
||||||
setReceiversOn(this, valueParameters)
|
setReceiversOn(
|
||||||
|
this,
|
||||||
|
dispatchReceiverParameter,
|
||||||
|
valueParameters
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expression.setter?.owner?.let { setter ->
|
expression.setter?.owner?.let { setter ->
|
||||||
buildOverride(superClass.functions.single { it.name.asString() == "set" }) { valueParameters ->
|
buildOverride(superClass.functions.single { it.name.asString() == "set" }) { dispatchReceiverParameter, valueParameters ->
|
||||||
val value = irGet(valueParameters.last())
|
val type = setter.valueParameters.last().type
|
||||||
|
val value = irImplicitCast(irGet(valueParameters.last()), type)
|
||||||
irSet(setter.returnType, null, setter.symbol, value).apply {
|
irSet(setter.returnType, null, setter.symbol, value).apply {
|
||||||
copyTypeArgumentsFrom(expression)
|
copyTypeArgumentsFrom(expression)
|
||||||
setReceiversOn(this, valueParameters)
|
setReceiversOn(this, dispatchReceiverParameter, valueParameters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user