JVM_IR: support references to Java fields
This commit is contained in:
+89
-119
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
@@ -20,12 +20,8 @@ import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.createType
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
@@ -48,10 +44,10 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
||||
private val localPropertyIndices = mutableMapOf<IrSymbol, Int>()
|
||||
|
||||
// TODO: join IrLocalDelegatedPropertyReference and IrPropertyReference via the class hierarchy?
|
||||
private val IrMemberAccessExpression.getter: IrFunctionSymbol?
|
||||
private val IrMemberAccessExpression.getter: IrSimpleFunctionSymbol?
|
||||
get() = (this as? IrPropertyReference)?.getter ?: (this as? IrLocalDelegatedPropertyReference)?.getter
|
||||
|
||||
private val IrMemberAccessExpression.setter: IrFunctionSymbol?
|
||||
private val IrMemberAccessExpression.setter: IrSimpleFunctionSymbol?
|
||||
get() = (this as? IrPropertyReference)?.setter ?: (this as? IrLocalDelegatedPropertyReference)?.setter
|
||||
|
||||
private val IrMemberAccessExpression.field: IrFieldSymbol?
|
||||
@@ -60,12 +56,13 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
||||
private val IrSimpleFunction.signature: String
|
||||
get() = context.state.typeMapper.mapSignatureSkipGeneric(collectRealOverrides().first().descriptor).toString()
|
||||
|
||||
// Plain Java fields do not have a getter, but can be referenced nonetheless. The signature should be the one
|
||||
// that a getter would have, if it existed.
|
||||
private val IrField.signature: String
|
||||
get() = "${JvmAbi.getterName(name.asString())}()${context.state.typeMapper.mapReturnType(descriptor)}"
|
||||
|
||||
private val IrMemberAccessExpression.signature: String
|
||||
get() = localPropertyIndices[getter]?.let { "<v#$it>" }
|
||||
?: (getter?.owner as? IrSimpleFunction)?.signature
|
||||
// Plain Java fields do not have a getter, but can be referenced nonetheless. The signature should be
|
||||
// the one that a getter would have, if it existed.
|
||||
?: TODO("plain Java field signature")
|
||||
get() = localPropertyIndices[getter]?.let { "<v#$it>" } ?: getter?.owner?.signature ?: field!!.owner.signature
|
||||
|
||||
private val IrMemberAccessExpression.symbol: IrSymbol
|
||||
get() = getter?.owner?.symbol ?: field!!.owner.symbol
|
||||
@@ -85,8 +82,8 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
||||
|
||||
// Return some declaration the parent of which is the containing class/package for the referenced property. This is
|
||||
// a bit of a hack, as the reason for not returning the container itself is the `mapImplementationOwner` call below.
|
||||
// TODO: move after LocalDeclarationsLowering and always use the getter/field? (not possible right now:
|
||||
// need Java field support to move below PropertiesToFieldsLowering)
|
||||
// TODO: move after LocalDeclarationsLowering and always use the getter/field? Can't move below ConstLowering
|
||||
// right now -- get() would not be optimized.
|
||||
private val IrMemberAccessExpression.propertyContainerChild: IrDeclaration?
|
||||
get() {
|
||||
var current: IrDeclaration? = getter?.owner ?: field?.owner
|
||||
@@ -102,7 +99,7 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
||||
context.ir.symbols.javaLangClass.typeWith(),
|
||||
context.ir.symbols.javaLangClass,
|
||||
// TODO: when the parent is an interface, this should map to DefaultImpls. However, that requires
|
||||
// moving this lowering below InterfaceLowering; see another TODO above.
|
||||
// moving this lowering below InterfaceLowering; see comment about the ordering above, though.
|
||||
CrIrType(context.state.typeMapper.mapImplementationOwner(propertyContainerChild!!.descriptor))
|
||||
)
|
||||
|
||||
@@ -126,6 +123,23 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrClass.addOverride(method: IrSimpleFunction, buildBody: IrBuilderWithScope.(List<IrValueParameter>) -> IrExpression) =
|
||||
addFunction {
|
||||
setSourceRange(this@addOverride)
|
||||
name = method.name
|
||||
returnType = method.returnType
|
||||
visibility = method.visibility
|
||||
origin = this@addOverride.origin
|
||||
}.apply {
|
||||
overriddenSymbols.add(method.symbol)
|
||||
dispatchReceiverParameter = thisReceiver!!.copyTo(this)
|
||||
for (parameter in method.valueParameters)
|
||||
valueParameters.add(parameter.copyTo(this))
|
||||
body = context.createIrBuilder(symbol, startOffset, endOffset).run {
|
||||
irExprBody(buildBody(listOf(dispatchReceiverParameter!!) + valueParameters))
|
||||
}
|
||||
}
|
||||
|
||||
private class PropertyReferenceKind(
|
||||
val interfaceSymbol: IrClassSymbol,
|
||||
val reflectedSymbol: IrClassSymbol,
|
||||
@@ -258,119 +272,75 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
||||
superTypes += IrSimpleTypeImpl(superClass.symbol, false, listOf(), listOf())
|
||||
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||
}
|
||||
val referenceThis = referenceClass.thisReceiver!!
|
||||
|
||||
buildConstructor {
|
||||
setSourceRange(expression)
|
||||
returnType = referenceClass.defaultType
|
||||
origin = referenceClass.origin
|
||||
isPrimary = true
|
||||
}.apply {
|
||||
parent = referenceClass
|
||||
referenceClass.declarations.add(this)
|
||||
|
||||
val constructor = this
|
||||
// See propertyReferenceKindFor -- only one of them could ever be present.
|
||||
val parameter = (expression.dispatchReceiver ?: expression.extensionReceiver)?.let {
|
||||
buildValueParameter {
|
||||
setSourceRange(expression)
|
||||
name = Name.identifier("receiver")
|
||||
type = it.type
|
||||
index = valueParameters.size
|
||||
origin = referenceClass.origin
|
||||
}.apply {
|
||||
parent = constructor
|
||||
valueParameters.add(this)
|
||||
}
|
||||
}
|
||||
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
|
||||
val superArgs = if (parameter == null) 0 else 1
|
||||
+irDelegatingConstructorCall(superClass.constructors.single { it.valueParameters.size == superArgs }).apply {
|
||||
parameter?.let { putValueArgument(0, irGet(parameter)) }
|
||||
}
|
||||
+IrInstanceInitializerCallImpl(startOffset, endOffset, referenceClass.symbol, context.irBuiltIns.unitType)
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
// See propertyReferenceKindFor -- only one of them could ever be present.
|
||||
val numOfSuperArgs = if (expression.dispatchReceiver != null || expression.extensionReceiver != null) 1 else 0
|
||||
val superConstructor = superClass.constructors.single { it.valueParameters.size == numOfSuperArgs }
|
||||
val receiverField = superClass.properties.single { it.name.asString() == "receiver" }.backingField!!
|
||||
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(dispatchReceiverParameter), receiverField)
|
||||
else
|
||||
irImplicitCast(irGet(valueParameters[index++]), it.type)
|
||||
}
|
||||
call.extensionReceiver = call.symbol.owner.extensionReceiverParameter?.let {
|
||||
if (expression.extensionReceiver != null)
|
||||
irGetField(irGet(dispatchReceiverParameter), receiverField)
|
||||
else
|
||||
irImplicitCast(irGet(valueParameters[index++]), it.type)
|
||||
}
|
||||
}
|
||||
val getName = superClass.functions.single { it.name.asString() == "getName" }
|
||||
val getOwner = superClass.functions.single { it.name.asString() == "getOwner" }
|
||||
val getSignature = superClass.functions.single { it.name.asString() == "getSignature" }
|
||||
val get = superClass.functions.find { it.name.asString() == "get" }
|
||||
val set = superClass.functions.find { it.name.asString() == "set" }
|
||||
|
||||
buildOverride(superClass.functions.single { it.name.asString() == "getName" }) { _, _ ->
|
||||
irString(expression.descriptor.name.asString())
|
||||
}
|
||||
referenceClass.addSimpleDelegatingConstructor(superConstructor, context.irBuiltIns, isPrimary = true)
|
||||
referenceClass.addOverride(getName) { irString(expression.descriptor.name.asString()) }
|
||||
referenceClass.addOverride(getOwner) { buildReflectedContainerReference(expression) }
|
||||
referenceClass.addOverride(getSignature) { irString(expression.signature) }
|
||||
|
||||
buildOverride(superClass.functions.single { it.name.asString() == "getOwner" }) { _, _ ->
|
||||
buildReflectedContainerReference(expression)
|
||||
}
|
||||
|
||||
buildOverride(superClass.functions.single { it.name.asString() == "getSignature" }) { _, _ ->
|
||||
irString(expression.signature)
|
||||
}
|
||||
|
||||
expression.getter?.owner?.let { getter ->
|
||||
buildOverride(superClass.functions.single { it.name.asString() == "get" }) { dispatchReceiverParameter, valueParameters ->
|
||||
irGet(getter.returnType, null, getter.symbol).apply {
|
||||
copyTypeArgumentsFrom(expression)
|
||||
setReceiversOn(
|
||||
this,
|
||||
dispatchReceiverParameter,
|
||||
valueParameters
|
||||
)
|
||||
val field = expression.field?.owner
|
||||
if (field == null) {
|
||||
fun IrBuilderWithScope.setCallArguments(call: IrCall, arguments: List<IrValueParameter>) {
|
||||
var index = 1
|
||||
call.copyTypeArgumentsFrom(expression)
|
||||
call.dispatchReceiver = call.symbol.owner.dispatchReceiverParameter?.let {
|
||||
if (expression.dispatchReceiver != null)
|
||||
irImplicitCast(irGetField(irGet(arguments[0]), receiverField), it.type)
|
||||
else
|
||||
irImplicitCast(irGet(arguments[index++]), it.type)
|
||||
}
|
||||
call.extensionReceiver = call.symbol.owner.extensionReceiverParameter?.let {
|
||||
if (expression.extensionReceiver != null)
|
||||
irImplicitCast(irGetField(irGet(arguments[0]), receiverField), it.type)
|
||||
else
|
||||
irImplicitCast(irGet(arguments[index++]), it.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expression.setter?.owner?.let { setter ->
|
||||
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, dispatchReceiverParameter, valueParameters)
|
||||
expression.getter?.owner?.let { getter ->
|
||||
referenceClass.addOverride(get!!) { arguments ->
|
||||
irGet(getter.returnType, null, getter.symbol).apply {
|
||||
setCallArguments(this, arguments)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expression.field?.owner?.let {
|
||||
TODO("plain Java property reference") // no accessors, should generate direct field read/write instead
|
||||
expression.setter?.owner?.let { setter ->
|
||||
referenceClass.addOverride(set!!) { arguments ->
|
||||
irSet(setter.returnType, null, setter.symbol, irGet(arguments.last())).apply {
|
||||
setCallArguments(this, arguments)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fun IrBuilderWithScope.fieldReceiver(arguments: List<IrValueParameter>) = when {
|
||||
field.isStatic ->
|
||||
null
|
||||
expression.dispatchReceiver != null ->
|
||||
irImplicitCast(irGetField(irGet(arguments[0]), receiverField), field.parentAsClass.defaultType)
|
||||
else ->
|
||||
irImplicitCast(irGet(arguments[1]), field.parentAsClass.defaultType)
|
||||
}
|
||||
|
||||
referenceClass.addOverride(get!!) { arguments ->
|
||||
irGetField(fieldReceiver(arguments), field)
|
||||
}
|
||||
|
||||
if (!field.isFinal) {
|
||||
referenceClass.addOverride(set!!) { arguments ->
|
||||
irSetField(fieldReceiver(arguments), field, irGet(arguments.last()))
|
||||
}
|
||||
}
|
||||
}
|
||||
return referenceClass
|
||||
}
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// WITH_REFLECT
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// WITH_REFLECT
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// FILE: J.java
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// WITH_REFLECT
|
||||
|
||||
Vendored
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// WITH_REFLECT
|
||||
|
||||
Vendored
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// FILE: J.java
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FILE: A.java
|
||||
|
||||
public class A {
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// FILE: A.java
|
||||
|
||||
public class A {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// WITH_REFLECT
|
||||
// FULL_JDK
|
||||
// FILE: J.java
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// WITH_REFLECT
|
||||
// FILE: test/J.java
|
||||
|
||||
|
||||
Reference in New Issue
Block a user