psi2ir: simple dynamic member calls
This commit is contained in:
+1
-1
@@ -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(
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+7
-25
@@ -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)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
fun test1(d: dynamic) = d.member(1, 2, 3)
|
||||
|
||||
fun test2(d: dynamic) = d?.member(1, 2, 3)
|
||||
|
||||
// Named arguments in dynamic calls are ignored by JS back-end.
|
||||
// If this becomes a compilation error, simply remove this particular test case.
|
||||
fun test3(d: dynamic) = d.member(a = 1, b = 2, c = 3)
|
||||
@@ -0,0 +1,42 @@
|
||||
FILE fqName:<root> fileName:/dynamicCall.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_OP operator=INVOKE type=dynamic
|
||||
receiver: DYN_MEMBER memberName='member' type=dynamic
|
||||
GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
|
||||
0: CONST Int type=kotlin.Int value=1
|
||||
1: CONST Int type=kotlin.Int value=2
|
||||
2: CONST Int type=kotlin.Int value=3
|
||||
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_OP operator=INVOKE type=dynamic
|
||||
receiver: DYN_MEMBER memberName='member' type=dynamic
|
||||
GET_VAR 'tmp0_safe_receiver: dynamic' type=dynamic origin=null
|
||||
0: CONST Int type=kotlin.Int value=1
|
||||
1: CONST Int type=kotlin.Int value=2
|
||||
2: CONST Int type=kotlin.Int value=3
|
||||
FUN name:test3 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='test3(dynamic): dynamic'
|
||||
DYN_OP operator=INVOKE type=dynamic
|
||||
receiver: DYN_MEMBER memberName='member' type=dynamic
|
||||
GET_VAR 'value-parameter d: dynamic' type=dynamic origin=null
|
||||
0: CONST Int type=kotlin.Int value=1
|
||||
1: CONST Int type=kotlin.Int value=2
|
||||
2: CONST Int type=kotlin.Int value=3
|
||||
+6
-6
@@ -1,9 +1,9 @@
|
||||
fun invoke() {}
|
||||
|
||||
fun test1(a: dynamic) = a(1)
|
||||
fun test1a(a: dynamic) = a.invoke(1)
|
||||
fun test2(a: dynamic, b: dynamic) = a(b)
|
||||
fun test2a(a: dynamic, b: dynamic) = a.invoke(b)
|
||||
fun test2b(a: dynamic, b: dynamic) = a(b)(b)
|
||||
fun test2c(a: dynamic, b: dynamic) = a(b).invoke(b)
|
||||
fun test3(a: dynamic) = invoke()
|
||||
fun test2(a: dynamic) = a.invoke(1)
|
||||
fun test3(a: dynamic, b: dynamic) = a(b)
|
||||
fun test4(a: dynamic, b: dynamic) = a.invoke(b)
|
||||
fun test5(a: dynamic, b: dynamic) = a(b)(b)
|
||||
fun test6(a: dynamic, b: dynamic) = a(b).invoke(b)
|
||||
fun test7(a: dynamic) = invoke()
|
||||
+37
-34
@@ -5,54 +5,57 @@ FILE fqName:<root> fileName:/invokeOperator.kt
|
||||
VALUE_PARAMETER name:a index:0 type:dynamic flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='test1(dynamic): dynamic'
|
||||
CALL 'invoke(dynamic): dynamic' type=dynamic origin=INVOKE
|
||||
$this: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION
|
||||
p0: CONST Int type=kotlin.Int value=1
|
||||
FUN name:test1a visibility:public modality:FINAL <> (a:dynamic) returnType:dynamic flags:
|
||||
DYN_OP operator=INVOKE type=dynamic
|
||||
receiver: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION
|
||||
0: CONST Int type=kotlin.Int value=1
|
||||
FUN name:test2 visibility:public modality:FINAL <> (a:dynamic) returnType:dynamic flags:
|
||||
VALUE_PARAMETER name:a index:0 type:dynamic flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='test1a(dynamic): dynamic'
|
||||
CALL 'invoke(dynamic): dynamic' type=dynamic origin=null
|
||||
$this: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=null
|
||||
p0: CONST Int type=kotlin.Int value=1
|
||||
FUN name:test2 visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags:
|
||||
RETURN type=kotlin.Nothing from='test2(dynamic): dynamic'
|
||||
DYN_OP operator=INVOKE type=dynamic
|
||||
receiver: DYN_MEMBER memberName='invoke' type=dynamic
|
||||
GET_VAR 'value-parameter a: dynamic' type=dynamic origin=null
|
||||
0: CONST Int type=kotlin.Int value=1
|
||||
FUN name:test3 visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags:
|
||||
VALUE_PARAMETER name:a index:0 type:dynamic flags:
|
||||
VALUE_PARAMETER name:b index:1 type:dynamic flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='test2(dynamic, dynamic): dynamic'
|
||||
CALL 'invoke(dynamic): dynamic' type=dynamic origin=INVOKE
|
||||
$this: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION
|
||||
p0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null
|
||||
FUN name:test2a visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags:
|
||||
RETURN type=kotlin.Nothing from='test3(dynamic, dynamic): dynamic'
|
||||
DYN_OP operator=INVOKE type=dynamic
|
||||
receiver: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION
|
||||
0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null
|
||||
FUN name:test4 visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags:
|
||||
VALUE_PARAMETER name:a index:0 type:dynamic flags:
|
||||
VALUE_PARAMETER name:b index:1 type:dynamic flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='test2a(dynamic, dynamic): dynamic'
|
||||
CALL 'invoke(dynamic): dynamic' type=dynamic origin=null
|
||||
$this: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=null
|
||||
p0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null
|
||||
FUN name:test2b visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags:
|
||||
RETURN type=kotlin.Nothing from='test4(dynamic, dynamic): dynamic'
|
||||
DYN_OP operator=INVOKE type=dynamic
|
||||
receiver: DYN_MEMBER memberName='invoke' type=dynamic
|
||||
GET_VAR 'value-parameter a: dynamic' type=dynamic origin=null
|
||||
0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null
|
||||
FUN name:test5 visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags:
|
||||
VALUE_PARAMETER name:a index:0 type:dynamic flags:
|
||||
VALUE_PARAMETER name:b index:1 type:dynamic flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='test2b(dynamic, dynamic): dynamic'
|
||||
CALL 'invoke(dynamic): dynamic' type=dynamic origin=INVOKE
|
||||
$this: CALL 'invoke(dynamic): dynamic' type=dynamic origin=INVOKE
|
||||
$this: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION
|
||||
p0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null
|
||||
p0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null
|
||||
FUN name:test2c visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags:
|
||||
RETURN type=kotlin.Nothing from='test5(dynamic, dynamic): dynamic'
|
||||
DYN_OP operator=INVOKE type=dynamic
|
||||
receiver: DYN_OP operator=INVOKE type=dynamic
|
||||
receiver: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION
|
||||
0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null
|
||||
0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null
|
||||
FUN name:test6 visibility:public modality:FINAL <> (a:dynamic, b:dynamic) returnType:dynamic flags:
|
||||
VALUE_PARAMETER name:a index:0 type:dynamic flags:
|
||||
VALUE_PARAMETER name:b index:1 type:dynamic flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='test2c(dynamic, dynamic): dynamic'
|
||||
CALL 'invoke(dynamic): dynamic' type=dynamic origin=null
|
||||
$this: CALL 'invoke(dynamic): dynamic' type=dynamic origin=INVOKE
|
||||
$this: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION
|
||||
p0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null
|
||||
p0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null
|
||||
FUN name:test3 visibility:public modality:FINAL <> (a:dynamic) returnType:kotlin.Unit flags:
|
||||
RETURN type=kotlin.Nothing from='test6(dynamic, dynamic): dynamic'
|
||||
DYN_OP operator=INVOKE type=dynamic
|
||||
receiver: DYN_MEMBER memberName='invoke' type=dynamic
|
||||
DYN_OP operator=INVOKE type=dynamic
|
||||
receiver: GET_VAR 'value-parameter a: dynamic' type=dynamic origin=VARIABLE_AS_FUNCTION
|
||||
0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null
|
||||
0: GET_VAR 'value-parameter b: dynamic' type=dynamic origin=null
|
||||
FUN name:test7 visibility:public modality:FINAL <> (a:dynamic) returnType:kotlin.Unit flags:
|
||||
VALUE_PARAMETER name:a index:0 type:dynamic flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='test3(dynamic): Unit'
|
||||
RETURN type=kotlin.Nothing from='test7(dynamic): Unit'
|
||||
CALL 'invoke(): Unit' type=kotlin.Unit 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("dynamicCall.kt")
|
||||
public void testDynamicCall() throws Exception {
|
||||
runTest("compiler/testData/ir/irJsText/dynamic/dynamicCall.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("dynamicMemberAccess.kt")
|
||||
public void testDynamicMemberAccess() throws Exception {
|
||||
runTest("compiler/testData/ir/irJsText/dynamic/dynamicMemberAccess.kt");
|
||||
|
||||
Reference in New Issue
Block a user