psi2ir: simple dynamic member calls

This commit is contained in:
Dmitry Petrov
2019-02-05 17:51:07 +03:00
parent ddb1ea2047
commit 3c8f52b436
13 changed files with 210 additions and 101 deletions
@@ -280,7 +280,7 @@ fun Generator.getSuperQualifier(resolvedCall: ResolvedCall<*>): ClassDescriptor?
return getOrFail(BindingContext.REFERENCE_TARGET, superCallExpression.instanceReference) as ClassDescriptor
}
fun StatementGenerator.pregenerateCall(resolvedCall: ResolvedCall<*>): CallBuilder {
fun StatementGenerator.pregenerateCall(resolvedCall: ResolvedCall<*>, isVariableAsFunctionCall: Boolean = false): CallBuilder {
if (resolvedCall.isExtensionInvokeCall()) {
return pregenerateExtensionInvokeCall(resolvedCall)
}
@@ -21,10 +21,14 @@ import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.types.IrDynamicType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments
import org.jetbrains.kotlin.psi2ir.intermediate.*
@@ -36,6 +40,7 @@ import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.util.*
class CallGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator) {
@@ -183,12 +188,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
} 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")
}
val dispatchReceiver = getDynamicExpressionReceiver(dispatchReceiverValue, extensionReceiverValue, descriptor)
IrDynamicMemberExpressionImpl(
startOffset, endOffset,
@@ -216,6 +216,33 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
}
}
private fun getDynamicExpressionReceiver(
dispatchReceiverValue: IntermediateValue?,
extensionReceiverValue: IntermediateValue?,
referencedDescriptor: DeclarationDescriptor
): IrExpression {
val dispatchReceiver = dispatchReceiverValue?.load()
?: throw AssertionError("Dynamic member reference $referencedDescriptor should have a dispatch receiver")
if (dispatchReceiver.type !is IrDynamicType) {
throw AssertionError(
"Dynamic member reference $referencedDescriptor should have a receiver of dynamic type: ${dispatchReceiver.render()}"
)
}
if (extensionReceiverValue != null) {
throw AssertionError("Dynamic member reference $referencedDescriptor should have no extension receiver")
}
return dispatchReceiver
}
private fun ResolvedCall<*>.isImplicitInvokeOnDynamic(): Boolean {
if (resultingDescriptor.name != OperatorNameConventions.INVOKE) return false
val callExression = call.callElement as? KtCallExpression ?: return true
val calleeExpression = callExression.calleeExpression as? KtSimpleNameExpression ?: return true
return calleeExpression.getReferencedName() != OperatorNameConventions.INVOKE.asString()
}
private fun generateFunctionCall(
functionDescriptor: FunctionDescriptor,
startOffset: Int,
@@ -225,21 +252,48 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator
): IrExpression =
call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
val returnType = functionDescriptor.returnType!!
val functionSymbol = context.symbolTable.referenceFunction(functionDescriptor.original)
val superQualifierSymbol = call.superQualifier?.let { context.symbolTable.referenceClass(it) }
val irCall = IrCallImpl(
startOffset, endOffset,
returnType.toIrType(),
functionSymbol,
functionDescriptor,
origin,
superQualifierSymbol
).apply {
putTypeArguments(call.typeArguments) { it.toIrType() }
this.dispatchReceiver = dispatchReceiverValue?.load()
this.extensionReceiver = extensionReceiverValue?.load()
val irType = returnType.toIrType()
if (functionDescriptor.isDynamic()) {
IrDynamicOperatorExpressionImpl(
startOffset, endOffset,
irType,
IrDynamicOperator.INVOKE
).apply {
val dispatchReceiver = getDynamicExpressionReceiver(dispatchReceiverValue, extensionReceiverValue, functionDescriptor)
receiver =
if (call.original.isImplicitInvokeOnDynamic())
dispatchReceiver
else
IrDynamicMemberExpressionImpl(
startOffset, endOffset, // TODO obtain more exact start/end offsets for explicit receiver expression
dispatchReceiver.type,
functionDescriptor.name.asString(),
dispatchReceiver
)
arguments.addAll(call.getValueArgumentsInParameterOrder().mapIndexed { index: Int, arg: IrExpression? ->
arg ?: throw AssertionError("No argument in dynamic call $functionDescriptor at position $index")
})
}
} else {
val functionSymbol = context.symbolTable.referenceFunction(functionDescriptor.original)
val superQualifierSymbol = call.superQualifier?.let { context.symbolTable.referenceClass(it) }
val irCall = IrCallImpl(
startOffset, endOffset,
irType,
functionSymbol,
functionDescriptor,
origin,
superQualifierSymbol
).apply {
putTypeArguments(call.typeArguments) { it.toIrType() }
this.dispatchReceiver = dispatchReceiverValue?.load()
this.extensionReceiver = extensionReceiverValue?.load()
}
addParametersToCall(startOffset, endOffset, call, irCall, returnType)
}
addParametersToCall(startOffset, endOffset, call, irCall, returnType)
}
private fun addParametersToCall(
@@ -329,7 +329,7 @@ class StatementGenerator(
val resolvedCall = getResolvedCall(expression) ?: return ErrorExpressionGenerator(this).generateErrorCall(expression)
if (resolvedCall is VariableAsFunctionResolvedCall) {
val functionCall = pregenerateCall(resolvedCall.functionCall)
val functionCall = pregenerateCall(resolvedCall.functionCall, isVariableAsFunctionCall = true)
return CallGenerator(this).generateCall(expression, functionCall, IrStatementOrigin.INVOKE)
}
@@ -10,12 +10,23 @@ interface IrDynamicExpression : IrExpression
interface IrDynamicOperatorExpression : IrDynamicExpression {
val operator: IrDynamicOperator
val valueArgumentsCount: Int
fun getValueArgument(index: Int): IrExpression?
fun putValueArgument(index: Int, valueArgument: IrExpression?)
fun removeValueArgument(index: Int)
var receiver: IrExpression
val arguments: MutableList<IrExpression>
}
var IrDynamicOperatorExpression.left: IrExpression
get() = receiver
set(value) {
receiver = value
}
var IrDynamicOperatorExpression.right: IrExpression
get() = arguments[0]
set(value) {
arguments[0] = value
}
interface IrDynamicMemberExpression : IrDynamicExpression {
val memberName: String
var receiver: IrExpression
@@ -16,45 +16,27 @@ class IrDynamicOperatorExpressionImpl(
startOffset: Int,
endOffset: Int,
type: IrType,
override val operator: IrDynamicOperator,
override val valueArgumentsCount: Int
override val operator: IrDynamicOperator
) :
IrExpressionBase(startOffset, endOffset, type),
IrDynamicOperatorExpression {
private val valueArguments = arrayOfNulls<IrExpression>(valueArgumentsCount)
override fun getValueArgument(index: Int): IrExpression? {
if (index >= valueArgumentsCount) {
throw AssertionError("$this: No such value argument slot: $index")
}
return valueArguments[index]
}
override fun putValueArgument(index: Int, valueArgument: IrExpression?) {
if (index >= valueArgumentsCount) {
throw AssertionError("$this: No such value argument slot: $index")
}
valueArguments[index] = valueArgument
}
override fun removeValueArgument(index: Int) {
putValueArgument(index, null)
}
override lateinit var receiver: IrExpression
override val arguments: MutableList<IrExpression> = ArrayList()
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitDynamicOperatorExpression(this, data)
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
for (valueArgument in valueArguments) {
valueArgument?.accept(visitor, data)
for (valueArgument in arguments) {
valueArgument.accept(visitor, data)
}
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
for (i in 0 until valueArgumentsCount) {
valueArguments[i] = valueArguments[i]?.transform(transformer, data)
for (i in arguments.indices) {
arguments[i] = arguments[i].transform(transformer, data)
}
}
}
@@ -652,12 +652,10 @@ open class DeepCopyIrTree : IrElementTransformerVoid() {
IrDynamicOperatorExpressionImpl(
expression.startOffset, expression.endOffset,
expression.type,
expression.operator,
expression.valueArgumentsCount
expression.operator
).apply {
for (i in 0 until expression.valueArgumentsCount) {
putValueArgument(i, expression.getValueArgument(i)?.transform())
}
receiver = expression.receiver.transform()
expression.arguments.mapTo(arguments) { it.transform() }
}
override fun visitDynamicMemberExpression(expression: IrDynamicMemberExpression): IrDynamicMemberExpression =
@@ -716,12 +716,10 @@ open class DeepCopyIrTreeWithSymbols(
IrDynamicOperatorExpressionImpl(
expression.startOffset, expression.endOffset,
expression.type.remapType(),
expression.operator,
expression.valueArgumentsCount
expression.operator
).apply {
for (i in 0 until expression.valueArgumentsCount) {
putValueArgument(i, expression.getValueArgument(i)?.transform())
}
receiver = expression.receiver.transform()
expression.arguments.mapTo(arguments) { it.transform() }
}
override fun visitDynamicMemberExpression(expression: IrDynamicMemberExpression): IrDynamicMemberExpression =
@@ -258,6 +258,15 @@ class DumpIrTreeVisitor(out: Appendable) : IrElementVisitor<Unit, String> {
}
}
override fun visitDynamicOperatorExpression(expression: IrDynamicOperatorExpression, data: String) {
expression.dumpLabeledElementWith(data) {
expression.receiver.accept(this, "receiver")
for ((i, arg) in expression.arguments.withIndex()) {
arg.accept(this, i.toString())
}
}
}
private inline fun IrElement.dumpLabeledElementWith(label: String, body: () -> Unit) {
printer.println(accept(elementRenderer, null).withLabel(label))
indented(body)