psi2ir: dynamic member access ('d.x', 'd?.x')
This commit is contained in:
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.psi2ir.intermediate.*
|
||||
import org.jetbrains.kotlin.psi2ir.unwrappedGetMethod
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.isDynamic
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
|
||||
@@ -165,36 +166,53 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
|
||||
): IrExpression {
|
||||
val getMethodDescriptor = descriptor.unwrappedGetMethod
|
||||
val superQualifierSymbol = call.superQualifier?.let { context.symbolTable.referenceClass(it) }
|
||||
val irType = descriptor.type.toIrType()
|
||||
|
||||
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,
|
||||
getMethodDescriptor,
|
||||
descriptor.typeParametersCount,
|
||||
dispatchReceiverValue?.load(),
|
||||
extensionReceiverValue?.load(),
|
||||
IrStatementOrigin.GET_PROPERTY,
|
||||
superQualifierSymbol
|
||||
).apply {
|
||||
putTypeArguments(call.typeArguments) { it.toIrType() }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return if (getMethodDescriptor == null) {
|
||||
call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val fieldSymbol = context.symbolTable.referenceField(descriptor.original)
|
||||
IrGetFieldImpl(
|
||||
startOffset, endOffset,
|
||||
fieldSymbol,
|
||||
descriptor.type.toIrType(),
|
||||
irType,
|
||||
dispatchReceiverValue?.load(),
|
||||
IrStatementOrigin.GET_PROPERTY,
|
||||
superQualifierSymbol
|
||||
)
|
||||
}
|
||||
} else {
|
||||
call.callReceiver.adjustForCallee(getMethodDescriptor).call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
if (descriptor.isDynamic()) {
|
||||
val dispatchReceiver = dispatchReceiverValue?.load()
|
||||
?: throw AssertionError("Dynamic member reference $descriptor should have a dispatch receiver")
|
||||
|
||||
if (extensionReceiverValue != null) {
|
||||
throw AssertionError("Dynamic member reference $descriptor should have no extension receiver")
|
||||
}
|
||||
|
||||
IrDynamicMemberExpressionImpl(
|
||||
startOffset, endOffset,
|
||||
irType,
|
||||
descriptor.name.asString(),
|
||||
dispatchReceiver
|
||||
)
|
||||
} else {
|
||||
val getterSymbol = context.symbolTable.referenceFunction(getMethodDescriptor.original)
|
||||
IrGetterCallImpl(
|
||||
startOffset, endOffset,
|
||||
irType,
|
||||
getterSymbol,
|
||||
getMethodDescriptor,
|
||||
descriptor.typeParametersCount,
|
||||
dispatchReceiverValue?.load(),
|
||||
extensionReceiverValue?.load(),
|
||||
IrStatementOrigin.GET_PROPERTY,
|
||||
superQualifierSymbol
|
||||
).apply {
|
||||
putTypeArguments(call.typeArguments) { it.toIrType() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fun test1(d: dynamic) = d.member
|
||||
|
||||
fun test2(d: dynamic) = d?.member
|
||||
@@ -0,0 +1,24 @@
|
||||
FILE fqName:<root> fileName:/dynamicMemberAccess.kt
|
||||
FUN name:test1 visibility:public modality:FINAL <> (d:dynamic) returnType:dynamic flags:
|
||||
VALUE_PARAMETER name:d index:0 type:dynamic flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='test1(dynamic): dynamic'
|
||||
DYN_MEMBER memberName='member' type=dynamic
|
||||
GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
|
||||
FUN name:test2 visibility:public modality:FINAL <> (d:dynamic) returnType:dynamic flags:
|
||||
VALUE_PARAMETER name:d index:0 type:dynamic flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='test2(dynamic): dynamic'
|
||||
BLOCK type=dynamic origin=SAFE_CALL
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_safe_receiver type:dynamic flags:val
|
||||
GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
|
||||
WHEN type=dynamic origin=null
|
||||
BRANCH
|
||||
if: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'tmp0_safe_receiver: dynamic' type=dynamic origin=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value=null
|
||||
then: CONST Null type=kotlin.Nothing? value=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: DYN_MEMBER memberName='member' type=dynamic
|
||||
GET_VAR 'tmp0_safe_receiver: dynamic' type=dynamic origin=null
|
||||
@@ -41,6 +41,11 @@ public class IrJsTextTestCaseGenerated extends AbstractIrJsTextTestCase {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/ir/irJsText/dynamic"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("dynamicMemberAccess.kt")
|
||||
public void testDynamicMemberAccess() throws Exception {
|
||||
runTest("compiler/testData/ir/irJsText/dynamic/dynamicMemberAccess.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("invokeOperator.kt")
|
||||
public void testInvokeOperator() throws Exception {
|
||||
runTest("compiler/testData/ir/irJsText/dynamic/invokeOperator.kt");
|
||||
|
||||
Reference in New Issue
Block a user