Adjust receivers for possibly synthetic properties access
Synthetic property accessors are treated as extension functions on Java classes by the front-end. However, underlying Java accessor methods are proper members.
This commit is contained in:
@@ -140,18 +140,17 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
|
||||
endOffset: Int,
|
||||
call: CallBuilder
|
||||
): IrExpression {
|
||||
return call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val superQualifierSymbol = call.superQualifier?.let { context.symbolTable.referenceClass(it) }
|
||||
val getMethodDescriptor = descriptor.unwrappedGetMethod
|
||||
val superQualifierSymbol = call.superQualifier?.let { context.symbolTable.referenceClass(it) }
|
||||
|
||||
val getterDescriptor = descriptor.unwrappedGetMethod
|
||||
|
||||
if (getterDescriptor != null) {
|
||||
val getterSymbol = context.symbolTable.referenceFunction(getterDescriptor.original)
|
||||
return if (getMethodDescriptor != null) {
|
||||
call.callReceiver.adjustForCallee(getMethodDescriptor).call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val getterSymbol = context.symbolTable.referenceFunction(getMethodDescriptor.original)
|
||||
IrGetterCallImpl(
|
||||
startOffset, endOffset,
|
||||
descriptor.type.toIrType(),
|
||||
getterSymbol,
|
||||
getterDescriptor,
|
||||
getMethodDescriptor,
|
||||
descriptor.typeParametersCount,
|
||||
dispatchReceiverValue?.load(),
|
||||
extensionReceiverValue?.load(),
|
||||
@@ -160,8 +159,9 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
|
||||
).apply {
|
||||
putTypeArguments(call.typeArguments) { it.toIrType() }
|
||||
}
|
||||
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val fieldSymbol = context.symbolTable.referenceField(descriptor.original)
|
||||
IrGetFieldImpl(
|
||||
startOffset, endOffset,
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
@@ -23,3 +24,27 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
fun IrVariable.defaultLoad(): IrExpression =
|
||||
IrGetValueImpl(startOffset, endOffset, type, symbol)
|
||||
|
||||
fun CallReceiver.adjustForCallee(callee: CallableMemberDescriptor): CallReceiver =
|
||||
object : CallReceiver {
|
||||
override fun call(withDispatchAndExtensionReceivers: (IntermediateValue?, IntermediateValue?) -> IrExpression): IrExpression =
|
||||
this@adjustForCallee.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val numReceiversPresent = listOfNotNull(dispatchReceiverValue, extensionReceiverValue).size
|
||||
val numReceiversExpected = listOfNotNull(callee.dispatchReceiverParameter, callee.extensionReceiverParameter).size
|
||||
if (numReceiversPresent != numReceiversExpected)
|
||||
throw AssertionError("Mismatching receivers for $callee: $numReceiversPresent, expected: $numReceiversExpected")
|
||||
|
||||
val newDispatchReceiverValue =
|
||||
when {
|
||||
callee.dispatchReceiverParameter == null -> null
|
||||
dispatchReceiverValue != null -> dispatchReceiverValue
|
||||
else -> extensionReceiverValue
|
||||
}
|
||||
val newExtensionReceiverValue =
|
||||
when {
|
||||
callee.extensionReceiverParameter == null -> null
|
||||
dispatchReceiverValue != null && callee.dispatchReceiverParameter == null -> dispatchReceiverValue
|
||||
else -> extensionReceiverValue
|
||||
}
|
||||
withDispatchAndExtensionReceivers(newDispatchReceiverValue, newExtensionReceiverValue)
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -141,11 +141,11 @@ class AccessorPropertyLValue(
|
||||
}
|
||||
|
||||
override fun load(): IrExpression =
|
||||
callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
callReceiver.adjustForCallee(getterDescriptor!!).call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
IrGetterCallImpl(
|
||||
startOffset, endOffset,
|
||||
type,
|
||||
getter!!, getterDescriptor!!,
|
||||
getter!!, getterDescriptor,
|
||||
typeArgumentsCount,
|
||||
dispatchReceiverValue?.load(),
|
||||
extensionReceiverValue?.load(),
|
||||
@@ -157,11 +157,11 @@ class AccessorPropertyLValue(
|
||||
}
|
||||
|
||||
override fun store(irExpression: IrExpression) =
|
||||
callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
callReceiver.adjustForCallee(setterDescriptor!!).call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
IrSetterCallImpl(
|
||||
startOffset, endOffset,
|
||||
context.irBuiltIns.unitType,
|
||||
setter!!, setterDescriptor!!,
|
||||
setter!!, setterDescriptor,
|
||||
typeArgumentsCount,
|
||||
dispatchReceiverValue?.load(),
|
||||
extensionReceiverValue?.load(),
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// FILE: javaSyntheticPropertyAccess.kt
|
||||
fun test(j: J) {
|
||||
j.foo
|
||||
j.foo = 1
|
||||
j.foo++
|
||||
j.foo += 1
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,33 @@ FILE fqName:<root> fileName:/javaSyntheticPropertyAccess.kt
|
||||
FUN name:test visibility:public modality:FINAL <> (j:J) returnType:kotlin.Unit flags:
|
||||
VALUE_PARAMETER name:j index:0 type:J flags:
|
||||
BLOCK_BODY
|
||||
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
|
||||
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public flags: superTypes:[kotlin.Any]
|
||||
CALL 'getFoo(): Int' type=kotlin.Int origin=GET_PROPERTY
|
||||
$this: GET_VAR 'value-parameter j: J' type=J origin=null
|
||||
CALL 'setFoo(Int): Unit' type=kotlin.Unit origin=EQ
|
||||
$this: GET_VAR 'value-parameter j: J' type=J origin=null
|
||||
x: CONST Int type=kotlin.Int value=1
|
||||
TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit
|
||||
typeOperand: CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public flags: superTypes:[kotlin.Any]
|
||||
BLOCK type=kotlin.Int origin=POSTFIX_INCR
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_receiver type:J flags:val
|
||||
GET_VAR 'value-parameter j: J' type=J origin=null
|
||||
BLOCK type=kotlin.Int origin=POSTFIX_INCR
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp1 type:kotlin.Int flags:val
|
||||
CALL 'getFoo(): Int' type=kotlin.Int origin=POSTFIX_INCR
|
||||
$this: GET_VAR 'tmp0_receiver: J' type=J origin=null
|
||||
CALL 'setFoo(Int): Unit' type=kotlin.Unit origin=POSTFIX_INCR
|
||||
$this: GET_VAR 'tmp0_receiver: J' type=J origin=null
|
||||
x: CALL 'inc(): Int' type=kotlin.Int origin=POSTFIX_INCR
|
||||
$this: GET_VAR 'tmp1: Int' type=kotlin.Int origin=null
|
||||
GET_VAR 'tmp1: Int' type=kotlin.Int origin=null
|
||||
BLOCK type=kotlin.Unit origin=PLUSEQ
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_receiver type:J flags:val
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp2_receiver type:J flags:val
|
||||
GET_VAR 'value-parameter j: J' type=J origin=null
|
||||
CALL 'setFoo(Int): Unit' type=kotlin.Unit origin=PLUSEQ
|
||||
$receiver: GET_VAR 'tmp0_receiver: J' type=J origin=null
|
||||
$this: GET_VAR 'tmp2_receiver: J' type=J origin=null
|
||||
x: CALL 'plus(Int): Int' type=kotlin.Int origin=PLUSEQ
|
||||
$this: CALL 'getFoo(): Int' type=kotlin.Int origin=PLUSEQ
|
||||
$receiver: GET_VAR 'tmp0_receiver: J' type=J origin=null
|
||||
$this: GET_VAR 'tmp2_receiver: J' type=J origin=null
|
||||
other: CONST Int type=kotlin.Int value=1
|
||||
|
||||
@@ -3,7 +3,7 @@ FILE fqName:<root> fileName:/javaSyntheticProperty.kt
|
||||
FIELD PROPERTY_BACKING_FIELD name:test type:kotlin.String? visibility:public flags:final
|
||||
EXPRESSION_BODY
|
||||
CALL 'getFoo(): String!' type=kotlin.String? origin=GET_PROPERTY
|
||||
$receiver: CALL 'constructor J()' type=J origin=null
|
||||
$this: CALL 'constructor J()' type=J origin=null
|
||||
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-test> visibility:public modality:FINAL <> () returnType:kotlin.String? flags:
|
||||
correspondingProperty: PROPERTY name:test visibility:public modality:FINAL flags:val
|
||||
BLOCK_BODY
|
||||
|
||||
@@ -7,4 +7,4 @@ FILE fqName:<root> fileName:/jdkClassSyntheticProperty.kt
|
||||
RETURN type=kotlin.Nothing from='<get-test>() on Class<*>: Array<(out) Field!>!'
|
||||
CALL 'getDeclaredFields(): Array<(out) Field!>!' type=kotlin.Array<out java.lang.reflect.Field!>? origin=GET_PROPERTY
|
||||
<`0>: kotlin.Any?
|
||||
$receiver: GET_VAR 'this@test: Class<*>' type=java.lang.Class<*> origin=null
|
||||
$this: GET_VAR 'this@test: Class<*>' type=java.lang.Class<*> origin=null
|
||||
|
||||
Reference in New Issue
Block a user