psi2ir: dynamic member access ('d.x', 'd?.x')

This commit is contained in:
Dmitry Petrov
2019-02-05 17:09:52 +03:00
parent 6e7ccfbfff
commit ddb1ea2047
4 changed files with 69 additions and 19 deletions
@@ -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");