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.psi2ir.unwrappedGetMethod
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
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.calls.util.FakeCallableDescriptorForObject
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
|
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
|
||||||
@@ -165,36 +166,53 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
|
|||||||
): IrExpression {
|
): IrExpression {
|
||||||
val getMethodDescriptor = descriptor.unwrappedGetMethod
|
val getMethodDescriptor = descriptor.unwrappedGetMethod
|
||||||
val superQualifierSymbol = call.superQualifier?.let { context.symbolTable.referenceClass(it) }
|
val superQualifierSymbol = call.superQualifier?.let { context.symbolTable.referenceClass(it) }
|
||||||
|
val irType = descriptor.type.toIrType()
|
||||||
|
|
||||||
return if (getMethodDescriptor != null) {
|
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 {
|
|
||||||
call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||||
val fieldSymbol = context.symbolTable.referenceField(descriptor.original)
|
val fieldSymbol = context.symbolTable.referenceField(descriptor.original)
|
||||||
IrGetFieldImpl(
|
IrGetFieldImpl(
|
||||||
startOffset, endOffset,
|
startOffset, endOffset,
|
||||||
fieldSymbol,
|
fieldSymbol,
|
||||||
descriptor.type.toIrType(),
|
irType,
|
||||||
dispatchReceiverValue?.load(),
|
dispatchReceiverValue?.load(),
|
||||||
IrStatementOrigin.GET_PROPERTY,
|
IrStatementOrigin.GET_PROPERTY,
|
||||||
superQualifierSymbol
|
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);
|
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")
|
@TestMetadata("invokeOperator.kt")
|
||||||
public void testInvokeOperator() throws Exception {
|
public void testInvokeOperator() throws Exception {
|
||||||
runTest("compiler/testData/ir/irJsText/dynamic/invokeOperator.kt");
|
runTest("compiler/testData/ir/irJsText/dynamic/invokeOperator.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user