From ddb1ea204757f92eda1a8589932167f1ea016975 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 5 Feb 2019 17:09:52 +0300 Subject: [PATCH] psi2ir: dynamic member access ('d.x', 'd?.x') --- .../kotlin/psi2ir/generators/CallGenerator.kt | 56 ++++++++++++------- .../irJsText/dynamic/dynamicMemberAccess.kt | 3 + .../irJsText/dynamic/dynamicMemberAccess.txt | 24 ++++++++ .../kotlin/ir/IrJsTextTestCaseGenerated.java | 5 ++ 4 files changed, 69 insertions(+), 19 deletions(-) create mode 100644 compiler/testData/ir/irJsText/dynamic/dynamicMemberAccess.kt create mode 100644 compiler/testData/ir/irJsText/dynamic/dynamicMemberAccess.txt diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt index 3fb4e54da67..8588300bf9d 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt @@ -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() } + } + } + } } } diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicMemberAccess.kt b/compiler/testData/ir/irJsText/dynamic/dynamicMemberAccess.kt new file mode 100644 index 00000000000..b8ea0ab61d7 --- /dev/null +++ b/compiler/testData/ir/irJsText/dynamic/dynamicMemberAccess.kt @@ -0,0 +1,3 @@ +fun test1(d: dynamic) = d.member + +fun test2(d: dynamic) = d?.member \ No newline at end of file diff --git a/compiler/testData/ir/irJsText/dynamic/dynamicMemberAccess.txt b/compiler/testData/ir/irJsText/dynamic/dynamicMemberAccess.txt new file mode 100644 index 00000000000..6a799ec822a --- /dev/null +++ b/compiler/testData/ir/irJsText/dynamic/dynamicMemberAccess.txt @@ -0,0 +1,24 @@ +FILE fqName: 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 diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrJsTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrJsTextTestCaseGenerated.java index c3dfa42724c..afa9b5b13f3 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrJsTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrJsTextTestCaseGenerated.java @@ -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");