From c5f14a29a4774037d54c435a593061aab7f5d252 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 15 Jan 2020 11:49:50 +0300 Subject: [PATCH] PSI2IR: Generate adapted callable references Callable reference is "adapted" if it requires some adaptation to an expected function type - e.g., when a reference to ``` fun foo(vararg xs: Int): Int ``` is used where `(Int, Int, Int) -> Int` is expected. For such callable references we generate the following IR (in pseudo-Kotlin): ``` { fun foo'(p0: Int, p1: Int, p2: Int): Int { return [| foo(p0, p1, p2) |] } ::foo' } ``` where `[| foo(p0, p1, p2) |]` is calling function `foo` with arguments `p0`, `p1`, and `p2`, as they were mapped by callable reference resolution. --- .../kotlin/fir/Fir2IrTextTestGenerated.java | 10 + .../resolve/calls/tower/NewCallArguments.kt | 12 + .../calls/tower/ResolvedAtomCompleter.kt | 11 +- .../kotlin/backend/jvm/ir/IrUtils.kt | 7 +- .../ReflectionReferencesGenerator.kt | 272 +++++++++++++++++- .../jetbrains/kotlin/ir/util/DumpIrTree.kt | 10 +- .../org/jetbrains/kotlin/psi/ValueArgument.kt | 4 + .../components/CallableReferenceResolution.kt | 31 +- ...leReferenceWithArgumentsConversion.fir.txt | 69 +++++ ...allableReferenceWithArgumentsConversion.kt | 22 ++ ...llableReferenceWithArgumentsConversion.txt | 100 +++++++ ...leReferenceWithVarargViewedAsArray.fir.txt | 74 +++++ ...allableReferenceWithVarargViewedAsArray.kt | 22 ++ ...llableReferenceWithVarargViewedAsArray.txt | 94 ++++++ .../kotlin/ir/IrTextTestCaseGenerated.java | 10 + 15 files changed, 729 insertions(+), 19 deletions(-) create mode 100644 compiler/testData/ir/irText/expressions/callableReferenceWithArgumentsConversion.fir.txt create mode 100644 compiler/testData/ir/irText/expressions/callableReferenceWithArgumentsConversion.kt create mode 100644 compiler/testData/ir/irText/expressions/callableReferenceWithArgumentsConversion.txt create mode 100644 compiler/testData/ir/irText/expressions/callableReferenceWithVarargViewedAsArray.fir.txt create mode 100644 compiler/testData/ir/irText/expressions/callableReferenceWithVarargViewedAsArray.kt create mode 100644 compiler/testData/ir/irText/expressions/callableReferenceWithVarargViewedAsArray.txt diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java index 280503b34d7..69c70d8d0e6 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java @@ -802,6 +802,16 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest { runTest("compiler/testData/ir/irText/expressions/callableReferenceTypeArguments.kt"); } + @TestMetadata("callableReferenceWithArgumentsConversion.kt") + public void testCallableReferenceWithArgumentsConversion() throws Exception { + runTest("compiler/testData/ir/irText/expressions/callableReferenceWithArgumentsConversion.kt"); + } + + @TestMetadata("callableReferenceWithVarargViewedAsArray.kt") + public void testCallableReferenceWithVarargViewedAsArray() throws Exception { + runTest("compiler/testData/ir/irText/expressions/callableReferenceWithVarargViewedAsArray.kt"); + } + @TestMetadata("calls.kt") public void testCalls() throws Exception { runTest("compiler/testData/ir/irText/expressions/calls.kt"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt index 2758f4c48ff..d07d240e131 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/NewCallArguments.kt @@ -193,6 +193,18 @@ class FakePositionalValueArgumentForCallableReferenceImpl( override fun isExternal(): Boolean = false } +class FakeImplicitSpreadValueArgumentForCallableReferenceImpl( + private val callElement: KtElement, + override val expression: ValueArgument +) : FakeImplicitSpreadValueArgumentForCallableReference { + override fun getArgumentExpression(): KtExpression? = null + override fun getArgumentName(): ValueArgumentName? = null + override fun isNamed(): Boolean = false + override fun asElement(): KtElement = callElement + override fun getSpreadElement(): LeafPsiElement? = null // TODO callElement? + override fun isExternal(): Boolean = false +} + class EmptyLabeledReturn( val returnExpression: KtReturnExpression, builtIns: KotlinBuiltIns diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt index 106472e1bc4..821e8ce5d8d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ResolvedAtomCompleter.kt @@ -7,7 +7,10 @@ package org.jetbrains.kotlin.resolve.calls.tower import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.createFunctionType -import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl import org.jetbrains.kotlin.psi.KtElement @@ -377,7 +380,11 @@ class ResolvedAtomCompleter( is ResolvedCallArgument.SimpleArgument -> { val valueArgument = makeFakeValueArgument(resolvedCallArgument.callArgument, callElement) if (valueParameter.isVararg) - VarargValueArgument(listOf(valueArgument)) + VarargValueArgument( + listOf( + FakeImplicitSpreadValueArgumentForCallableReferenceImpl(callElement, valueArgument) + ) + ) else ExpressionValueArgument(valueArgument) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt index 3c0ac5b9874..f77d181fc05 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt @@ -134,8 +134,11 @@ val IrType.isBoxedArray: Boolean fun IrType.getArrayElementType(irBuiltIns: IrBuiltIns): IrType = if (isBoxedArray) ((this as IrSimpleType).arguments.single() as IrTypeProjection).type - else - irBuiltIns.primitiveArrayElementTypes.getValue(this.classOrNull!!) + else { + val classifier = this.classOrNull!! + irBuiltIns.primitiveArrayElementTypes[classifier] + ?: throw AssertionError("Primitive array expected: $classifier") + } val IrStatementOrigin?.isLambda: Boolean get() = this == IrStatementOrigin.LAMBDA || this == IrStatementOrigin.ANONYMOUS_FUNCTION diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt index bfe22883342..c159f110198 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ReflectionReferencesGenerator.kt @@ -16,19 +16,30 @@ package org.jetbrains.kotlin.psi2ir.generators +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.declarations.MetadataSource +import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl +import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol import org.jetbrains.kotlin.ir.util.referenceClassifier import org.jetbrains.kotlin.ir.util.referenceFunction -import org.jetbrains.kotlin.psi.KtCallableReferenceExpression -import org.jetbrains.kotlin.psi.KtClassLiteralExpression -import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.ir.util.withScope +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments +import org.jetbrains.kotlin.psi2ir.intermediate.CallBuilder import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.expressions.DoubleColonLHS @@ -61,6 +72,15 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St val callBuilder = unwrapCallableDescriptorAndTypeArguments(resolvedCall, context.extensions.samConversion) + if (resolvedCall.valueArguments.isNotEmpty()) { + val adaptedCallableReference = generateAdaptedCallableReference(ktCallableReference, callBuilder) + if (adaptedCallableReference.hasResultAdaptation || + !isTrivialArgumentAdaptation(adaptedCallableReference.irAdapteeCall) + ) { + return adaptedCallableReference.irReferenceExpression + } + } + return statementGenerator.generateCallReceiver( ktCallableReference, resolvedDescriptor, @@ -79,6 +99,252 @@ class ReflectionReferencesGenerator(statementGenerator: StatementGenerator) : St } } + private fun isTrivialArgumentAdaptation(irAdapteeCall: IrFunctionAccessExpression): Boolean { + for (i in 0 until irAdapteeCall.valueArgumentsCount) { + val irValueArgument = irAdapteeCall.getValueArgument(i) ?: return false + if (irValueArgument is IrVararg) { + val irVarargElements = irValueArgument.elements + if (irVarargElements.size != 1 || irVarargElements[0] !is IrSpreadElement) return false + } + } + return true + } + + private class AdaptedCallableReference( + val irReferenceExpression: IrExpression, + val irAdapteeCall: IrFunctionAccessExpression, + val hasResultAdaptation: Boolean + ) + + private fun generateAdaptedCallableReference( + ktCallableReference: KtCallableReferenceExpression, + callBuilder: CallBuilder + ): AdaptedCallableReference { + val adapteeDescriptor = callBuilder.descriptor + if (adapteeDescriptor !is FunctionDescriptor) { + throw AssertionError("Function descriptor expected in adapted callable reference: $adapteeDescriptor") + } + + val startOffset = ktCallableReference.startOffsetSkippingComments + val endOffset = ktCallableReference.endOffset + + val adapteeSymbol = context.symbolTable.referenceFunction(adapteeDescriptor.original) + + val ktFunctionalType = getTypeInferredByFrontendOrFail(ktCallableReference) + val irFunctionalType = ktFunctionalType.toIrType() + + val ktFunctionalTypeArguments = ktFunctionalType.arguments + val ktExpectedReturnType = ktFunctionalTypeArguments.last().type + val ktExpectedParameterTypes = ktFunctionalTypeArguments.take(ktFunctionalTypeArguments.size - 1).map { it.type } + + val irAdapterFun = createAdapterFun(startOffset, endOffset, adapteeDescriptor, ktExpectedParameterTypes, ktExpectedReturnType) + val (irCall, irAdapteeCallInner) = + createAdapteeCall(startOffset, endOffset, ktCallableReference, adapteeSymbol, callBuilder, irAdapterFun) + + irAdapterFun.body = IrBlockBodyImpl(startOffset, endOffset).apply { + if (KotlinBuiltIns.isUnit(ktExpectedReturnType)) + statements.add(irCall) + else + statements.add(IrReturnImpl(startOffset, endOffset, context.irBuiltIns.nothingType, irAdapterFun.symbol, irCall)) + } + + val irBlock = IrBlockImpl(startOffset, endOffset, irFunctionalType).apply { + statements.add(irAdapterFun) + statements.add( + IrFunctionReferenceImpl( + startOffset, endOffset, + irFunctionalType, + irAdapterFun.symbol, + 0, + irAdapterFun.valueParameters.size + ) + ) + } + + return AdaptedCallableReference( + irBlock, irAdapteeCallInner, + KotlinBuiltIns.isUnit(ktExpectedReturnType) && !KotlinBuiltIns.isUnit(adapteeDescriptor.returnType!!) + ) + } + + private fun createAdapteeCall( + startOffset: Int, + endOffset: Int, + ktCallableReference: KtCallableReferenceExpression, + adapteeSymbol: IrFunctionSymbol, + callBuilder: CallBuilder, + irAdapterFun: IrSimpleFunction + ): Pair { + val resolvedCall = callBuilder.original + val resolvedDescriptor = resolvedCall.resultingDescriptor + + var irAdapteeCall: IrFunctionAccessExpression? = null + val irCall = statementGenerator.generateCallReceiver( + ktCallableReference, + resolvedDescriptor, + resolvedCall.dispatchReceiver, resolvedCall.extensionReceiver, + isSafe = false + ).call { dispatchReceiverValue, extensionReceiverValue -> + val irType = resolvedDescriptor.returnType!!.toIrType() + + val irAdapteeCallInner = + if (resolvedDescriptor is ConstructorDescriptor) + IrConstructorCallImpl.fromSymbolDescriptor( + startOffset, endOffset, irType, + adapteeSymbol as IrConstructorSymbol + ) + else + IrCallImpl( + startOffset, endOffset, irType, + adapteeSymbol, + origin = null, superQualifierSymbol = null + ) + + context.callToSubstitutedDescriptorMap[irAdapteeCallInner] = resolvedDescriptor + + irAdapteeCallInner.dispatchReceiver = dispatchReceiverValue?.load() + irAdapteeCallInner.extensionReceiver = extensionReceiverValue?.load() + + irAdapteeCallInner.putTypeArguments(callBuilder.typeArguments) { it.toIrType() } + + putAdaptedValueArguments(startOffset, endOffset, irAdapteeCallInner, irAdapterFun, resolvedCall) + + irAdapteeCall = irAdapteeCallInner + + irAdapteeCallInner + } + + return Pair(irCall, irAdapteeCall!!) + } + + private fun putAdaptedValueArguments( + startOffset: Int, + endOffset: Int, + irAdapteeCall: IrFunctionAccessExpression, + irAdapterFun: IrSimpleFunction, + resolvedCall: ResolvedCall<*> + ) { + val adaptedArguments = resolvedCall.valueArguments + if (adaptedArguments.isEmpty()) { + throw AssertionError("Callable reference with adapted arguments expected: ${resolvedCall.call.callElement.text}") + } + + for ((valueParameter, valueArgument) in adaptedArguments) { + irAdapteeCall.putValueArgument( + valueParameter.index, + adaptResolvedValueArgument(startOffset, endOffset, valueArgument, irAdapterFun, valueParameter) + ) + } + } + + private fun adaptResolvedValueArgument( + startOffset: Int, + endOffset: Int, + resolvedValueArgument: ResolvedValueArgument, + irAdapterFun: IrSimpleFunction, + valueParameter: ValueParameterDescriptor + ): IrExpression? = + when (resolvedValueArgument) { + is DefaultValueArgument -> + null + is VarargValueArgument -> + IrVarargImpl( + startOffset, endOffset, + valueParameter.type.toIrType(), valueParameter.varargElementType!!.toIrType(), + resolvedValueArgument.arguments.map { + adaptValueArgument(startOffset, endOffset, it, irAdapterFun) + } + ) + is ExpressionValueArgument -> { + val valueArgument = resolvedValueArgument.valueArgument!! + + adaptValueArgument(startOffset, endOffset, valueArgument, irAdapterFun) as IrExpression + } + else -> + throw AssertionError("Unexpected ResolvedValueArgument: $resolvedValueArgument") + } + + private fun adaptValueArgument( + startOffset: Int, + endOffset: Int, + valueArgument: ValueArgument, + irAdapterFun: IrSimpleFunction + ): IrVarargElement = + when (valueArgument) { + is FakeImplicitSpreadValueArgumentForCallableReference -> + IrSpreadElementImpl( + startOffset, endOffset, + adaptValueArgument(startOffset, endOffset, valueArgument.expression, irAdapterFun) as IrExpression + ) + + is FakePositionalValueArgumentForCallableReference -> { + val irAdapterParameter = irAdapterFun.valueParameters[valueArgument.index] + IrGetValueImpl(startOffset, endOffset, irAdapterParameter.type, irAdapterParameter.symbol) + } + + else -> + throw AssertionError("Unexpected ValueArgument: $valueArgument") + } + + private fun createAdapterFun( + startOffset: Int, + endOffset: Int, + adapteeDescriptor: FunctionDescriptor, + ktExpectedParameterTypes: List, + ktExpectedReturnType: KotlinType + ): IrSimpleFunction { + val adapterFunctionDescriptor = WrappedSimpleFunctionDescriptor() + val adapterOrigin = IrDeclarationOrigin.DEFINED // TODO special declaration origin for callable reference adapter? + + return context.symbolTable.declareSimpleFunction( + startOffset, endOffset, adapterOrigin, adapterFunctionDescriptor + ) { irAdapterSymbol -> + IrFunctionImpl( + startOffset, endOffset, adapterOrigin, + irAdapterSymbol, + adapteeDescriptor.name, + Visibilities.LOCAL, + Modality.FINAL, + ktExpectedReturnType.toIrType(), + isInline = adapteeDescriptor.isInline, // TODO ? + isExternal = false, + isTailrec = false, + isSuspend = adapteeDescriptor.isSuspend, // TODO ? + isOperator = adapteeDescriptor.isOperator, // TODO ? + isExpect = false, + isFakeOverride = false + ).also { irAdapterFun -> + adapterFunctionDescriptor.bind(irAdapterFun) + + context.symbolTable.withScope(adapterFunctionDescriptor) { + irAdapterFun.metadata = MetadataSource.Function(adapteeDescriptor) + + irAdapterFun.dispatchReceiverParameter = null + irAdapterFun.extensionReceiverParameter = null + + ktExpectedParameterTypes.mapIndexedTo(irAdapterFun.valueParameters) { index, ktExpectedParameterType -> + val adapterValueParameterDescriptor = WrappedValueParameterDescriptor() + context.symbolTable.declareValueParameter( + startOffset, endOffset, adapterOrigin, adapterValueParameterDescriptor, + ktExpectedParameterType.toIrType() + ) { irAdapterParameterSymbol -> + IrValueParameterImpl( + startOffset, endOffset, adapterOrigin, + irAdapterParameterSymbol, + Name.identifier("p$index"), + index, + ktExpectedParameterType.toIrType(), + varargElementType = null, isCrossinline = false, isNoinline = false + ).also { irAdapterValueParameter -> + adapterValueParameterDescriptor.bind(irAdapterValueParameter) + } + } + } + } + } + } + } + fun generateCallableReference( ktElement: KtElement, type: KotlinType, diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt index 41023af55fb..3e16916b2db 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DumpIrTree.kt @@ -377,20 +377,18 @@ class DumpTreeFromSourceLineVisitor( internal fun IrMemberAccessExpression.getValueParameterNamesForDebug(): List { val expectedCount = valueArgumentsCount - return if (this is IrDeclarationReference && symbol.isBound) { + if (symbol.isBound) { val owner = symbol.owner if (owner is IrFunction) { - (0 until expectedCount).map { + return (0 until expectedCount).map { if (it < owner.valueParameters.size) owner.valueParameters[it].name.asString() else "${it + 1}" } - } else { - getPlaceholderParameterNames(expectedCount) } - } else - getPlaceholderParameterNames(expectedCount) + } + return getPlaceholderParameterNames(expectedCount) } internal fun getPlaceholderParameterNames(expectedCount: Int) = diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/ValueArgument.kt b/compiler/psi/src/org/jetbrains/kotlin/psi/ValueArgument.kt index 555b092a6f9..17b8b862a49 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/psi/ValueArgument.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/psi/ValueArgument.kt @@ -40,6 +40,10 @@ interface FakePositionalValueArgumentForCallableReference : ValueArgument { val index: Int } +interface FakeImplicitSpreadValueArgumentForCallableReference : ValueArgument { + val expression: ValueArgument +} + interface LambdaArgument : ValueArgument { fun getLambdaExpression(): KtLambdaExpression? } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt index 3d6f1581e17..e05022a0ead 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/CallableReferenceResolution.kt @@ -266,7 +266,9 @@ class CallableReferencesCandidateFactory( */ var defaults = 0 var varargMappingState = VarargMappingState.UNMAPPED - val mappedArguments = arrayOfNulls(fakeArguments.size) + val mappedArguments = linkedMapOf() + val mappedVarargElements = linkedMapOf>() + val mappedArgumentTypes = arrayOfNulls(fakeArguments.size) for ((valueParameter, resolvedArgument) in argumentMapping.parameterToCallArgumentMap) { for (fakeArgument in resolvedArgument.arguments) { @@ -283,25 +285,42 @@ class CallableReferencesCandidateFactory( ) varargMappingState = newVarargMappingState mappedArgument = varargType + + when (newVarargMappingState) { + VarargMappingState.MAPPED_WITH_ARRAY -> { + if (valueParameter in mappedArguments.keys) { + throw AssertionError("Vararg parameter already mapped: $valueParameter, fakeArgument: $fakeArgument") + } + mappedArguments[valueParameter] = ResolvedCallArgument.SimpleArgument(fakeArgument) + } + + VarargMappingState.MAPPED_WITH_PLAIN_ARGS -> { + mappedVarargElements.getOrPut(valueParameter) { ArrayList() }.add(fakeArgument) + } + } } else { mappedArgument = substitutedParameter.type + mappedArguments[valueParameter] = resolvedArgument } - mappedArguments[index] = mappedArgument + mappedArgumentTypes[index] = mappedArgument } if (resolvedArgument == ResolvedCallArgument.DefaultArgument) defaults++ } - if (mappedArguments.any { it == null }) return null + if (mappedArgumentTypes.any { it == null }) return null + + for ((valueParameter, varargElements) in mappedVarargElements) { + mappedArguments[valueParameter] = ResolvedCallArgument.VarargArgument(varargElements) + } // lower(Unit!) = Unit val returnExpectedType = inputOutputTypes.outputType val coercion = if (returnExpectedType.isUnit()) CoercionStrategy.COERCION_TO_UNIT else CoercionStrategy.NO_COERCION - return CallableReferenceAdaptation( - @Suppress("UNCHECKED_CAST") (mappedArguments as Array), - coercion, defaults, argumentMapping.parameterToCallArgumentMap + @Suppress("UNCHECKED_CAST") (mappedArgumentTypes as Array), + coercion, defaults, mappedArguments ) } diff --git a/compiler/testData/ir/irText/expressions/callableReferenceWithArgumentsConversion.fir.txt b/compiler/testData/ir/irText/expressions/callableReferenceWithArgumentsConversion.fir.txt new file mode 100644 index 00000000000..d78e2c2d129 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/callableReferenceWithArgumentsConversion.fir.txt @@ -0,0 +1,69 @@ +FILE fqName: fileName:/callableReferenceWithArgumentsConversion.kt + FUN name:use visibility:public modality:FINAL <> (fn:kotlin.Function1) returnType:kotlin.String + VALUE_PARAMETER name:fn index:0 type:kotlin.Function1 + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun use (fn: kotlin.Function1): kotlin.String declared in ' + CALL 'public abstract fun invoke (p1: kotlin.Int): kotlin.String [operator] declared in kotlin.Function1' type=kotlin.String origin=null + $this: GET_VAR 'fn: kotlin.Function1 declared in .use' type=kotlin.Function1 origin=null + p1: CONST Int type=kotlin.Int value=1 + FUN name:coerceToUnit visibility:public modality:FINAL <> (fn:kotlin.Function1) returnType:kotlin.Unit + VALUE_PARAMETER name:fn index:0 type:kotlin.Function1 + BLOCK_BODY + FUN name:fnWithDefault visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.String + VALUE_PARAMETER name:a index:0 type:kotlin.Int + VALUE_PARAMETER name:b index:1 type:kotlin.Int + EXPRESSION_BODY + CONST Int type=kotlin.Int value=42 + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun fnWithDefault (a: kotlin.Int, b: kotlin.Int): kotlin.String declared in ' + CONST String type=kotlin.String value="abc" + FUN name:fnWithVarargs visibility:public modality:FINAL <> (xs:kotlin.IntArray) returnType:kotlin.String + VALUE_PARAMETER name:xs index:0 type:kotlin.IntArray + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun fnWithVarargs (xs: kotlin.IntArray): kotlin.String declared in ' + CONST String type=kotlin.String value="abc" + CLASS OBJECT name:Host modality:FINAL visibility:public superTypes:[kotlin.Any] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Host + CONSTRUCTOR visibility:private <> () returnType:.Host [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS OBJECT name:Host modality:FINAL visibility:public superTypes:[kotlin.Any]' + FUN name:importedObjectMemberWithVarargs visibility:public modality:FINAL <> ($this:.Host, xs:kotlin.IntArray) returnType:kotlin.String + $this: VALUE_PARAMETER name: type:.Host + VALUE_PARAMETER name:xs index:0 type:kotlin.IntArray + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun importedObjectMemberWithVarargs (xs: kotlin.IntArray): kotlin.String declared in .Host' + CONST String type=kotlin.String value="abc" + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN name:testDefault visibility:public modality:FINAL <> () returnType:IrErrorType + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun testDefault (): IrErrorType declared in ' + ERROR_CALL 'Unresolved reference: #' type=IrErrorType + FUNCTION_REFERENCE 'public final fun fnWithDefault (a: kotlin.Int, b: kotlin.Int): kotlin.String declared in ' type=kotlin.reflect.KFunction2 origin=null + FUN name:testVararg visibility:public modality:FINAL <> () returnType:IrErrorType + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun testVararg (): IrErrorType declared in ' + ERROR_CALL 'Unresolved reference: #' type=IrErrorType + FUNCTION_REFERENCE 'public final fun fnWithVarargs (xs: kotlin.IntArray): kotlin.String declared in ' type=kotlin.reflect.KFunction1 origin=null + FUN name:testCoercionToUnit visibility:public modality:FINAL <> () returnType:IrErrorType + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun testCoercionToUnit (): IrErrorType declared in ' + ERROR_CALL 'Unresolved reference: #' type=IrErrorType + FUNCTION_REFERENCE 'public final fun fnWithDefault (a: kotlin.Int, b: kotlin.Int): kotlin.String declared in ' type=kotlin.reflect.KFunction2 origin=null + FUN name:testImportedObjectMember visibility:public modality:FINAL <> () returnType:IrErrorType + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun testImportedObjectMember (): IrErrorType declared in ' + ERROR_CALL 'Unresolved reference: #' type=IrErrorType + FUNCTION_REFERENCE 'public final fun importedObjectMemberWithVarargs (xs: kotlin.IntArray): kotlin.String declared in .Host' type=kotlin.reflect.KFunction1 origin=null diff --git a/compiler/testData/ir/irText/expressions/callableReferenceWithArgumentsConversion.kt b/compiler/testData/ir/irText/expressions/callableReferenceWithArgumentsConversion.kt new file mode 100644 index 00000000000..853faa576ce --- /dev/null +++ b/compiler/testData/ir/irText/expressions/callableReferenceWithArgumentsConversion.kt @@ -0,0 +1,22 @@ +// !LANGUAGE: +NewInference, +FunctionReferenceWithDefaultValueAsOtherType +import Host.importedObjectMemberWithVarargs + +fun use(fn: (Int) -> String) = fn(1) + +fun coerceToUnit(fn: (Int) -> Unit) {} + +fun fnWithDefault(a: Int, b: Int = 42) = "abc" + +fun fnWithVarargs(vararg xs: Int) = "abc" + +object Host { + fun importedObjectMemberWithVarargs(vararg xs: Int) = "abc" +} + +fun testDefault() = use(::fnWithDefault) + +fun testVararg() = use(::fnWithVarargs) + +fun testCoercionToUnit() = coerceToUnit(::fnWithDefault) + +fun testImportedObjectMember() = use(::importedObjectMemberWithVarargs) \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/callableReferenceWithArgumentsConversion.txt b/compiler/testData/ir/irText/expressions/callableReferenceWithArgumentsConversion.txt new file mode 100644 index 00000000000..63b85b59fbe --- /dev/null +++ b/compiler/testData/ir/irText/expressions/callableReferenceWithArgumentsConversion.txt @@ -0,0 +1,100 @@ +FILE fqName: fileName:/callableReferenceWithArgumentsConversion.kt + FUN name:use visibility:public modality:FINAL <> (fn:kotlin.Function1) returnType:kotlin.String + VALUE_PARAMETER name:fn index:0 type:kotlin.Function1 + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun use (fn: kotlin.Function1): kotlin.String declared in ' + CALL 'public abstract fun invoke (p1: P1 of kotlin.Function1): R of kotlin.Function1 [operator] declared in kotlin.Function1' type=kotlin.String origin=INVOKE + $this: GET_VAR 'fn: kotlin.Function1 declared in .use' type=kotlin.Function1 origin=VARIABLE_AS_FUNCTION + p1: CONST Int type=kotlin.Int value=1 + FUN name:coerceToUnit visibility:public modality:FINAL <> (fn:kotlin.Function1) returnType:kotlin.Unit + VALUE_PARAMETER name:fn index:0 type:kotlin.Function1 + BLOCK_BODY + FUN name:fnWithDefault visibility:public modality:FINAL <> (a:kotlin.Int, b:kotlin.Int) returnType:kotlin.String + VALUE_PARAMETER name:a index:0 type:kotlin.Int + VALUE_PARAMETER name:b index:1 type:kotlin.Int + EXPRESSION_BODY + CONST Int type=kotlin.Int value=42 + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun fnWithDefault (a: kotlin.Int, b: kotlin.Int): kotlin.String declared in ' + CONST String type=kotlin.String value="abc" + FUN name:fnWithVarargs visibility:public modality:FINAL <> (xs:kotlin.IntArray) returnType:kotlin.String + VALUE_PARAMETER name:xs index:0 type:kotlin.IntArray varargElementType:kotlin.Int [vararg] + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun fnWithVarargs (vararg xs: kotlin.Int): kotlin.String declared in ' + CONST String type=kotlin.String value="abc" + CLASS OBJECT name:Host modality:FINAL visibility:public superTypes:[kotlin.Any] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Host + CONSTRUCTOR visibility:private <> () returnType:.Host [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS OBJECT name:Host modality:FINAL visibility:public superTypes:[kotlin.Any]' + FUN name:importedObjectMemberWithVarargs visibility:public modality:FINAL <> ($this:.Host, xs:kotlin.IntArray) returnType:kotlin.String + $this: VALUE_PARAMETER name: type:.Host + VALUE_PARAMETER name:xs index:0 type:kotlin.IntArray varargElementType:kotlin.Int [vararg] + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun importedObjectMemberWithVarargs (vararg xs: kotlin.Int): kotlin.String declared in .Host' + CONST String type=kotlin.String value="abc" + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + VALUE_PARAMETER name:other index:0 type:kotlin.Any? + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + $this: VALUE_PARAMETER name: type:kotlin.Any + FUN name:testDefault visibility:public modality:FINAL <> () returnType:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun testDefault (): kotlin.String declared in ' + CALL 'public final fun use (fn: kotlin.Function1): kotlin.String declared in ' type=kotlin.String origin=null + fn: BLOCK type=kotlin.reflect.KFunction1 origin=null + FUN name:fnWithDefault visibility:local modality:FINAL <> (p0:kotlin.Int) returnType:kotlin.String + VALUE_PARAMETER name:p0 index:0 type:kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun fnWithDefault (p0: kotlin.Int): kotlin.String declared in .testDefault' + CALL 'public final fun fnWithDefault (a: kotlin.Int, b: kotlin.Int): kotlin.String declared in ' type=kotlin.String origin=null + a: GET_VAR 'p0: kotlin.Int declared in .testDefault.fnWithDefault' type=kotlin.Int origin=null + FUNCTION_REFERENCE 'local final fun fnWithDefault (p0: kotlin.Int): kotlin.String declared in .testDefault' type=kotlin.reflect.KFunction1 origin=null + FUN name:testVararg visibility:public modality:FINAL <> () returnType:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun testVararg (): kotlin.String declared in ' + CALL 'public final fun use (fn: kotlin.Function1): kotlin.String declared in ' type=kotlin.String origin=null + fn: BLOCK type=kotlin.reflect.KFunction1 origin=null + FUN name:fnWithVarargs visibility:local modality:FINAL <> (p0:kotlin.Int) returnType:kotlin.String + VALUE_PARAMETER name:p0 index:0 type:kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun fnWithVarargs (p0: kotlin.Int): kotlin.String declared in .testVararg' + CALL 'public final fun fnWithVarargs (vararg xs: kotlin.Int): kotlin.String declared in ' type=kotlin.String origin=null + xs: VARARG type=kotlin.IntArray varargElementType=kotlin.Int + GET_VAR 'p0: kotlin.Int declared in .testVararg.fnWithVarargs' type=kotlin.Int origin=null + FUNCTION_REFERENCE 'local final fun fnWithVarargs (p0: kotlin.Int): kotlin.String declared in .testVararg' type=kotlin.reflect.KFunction1 origin=null + FUN name:testCoercionToUnit visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun testCoercionToUnit (): kotlin.Unit declared in ' + CALL 'public final fun coerceToUnit (fn: kotlin.Function1): kotlin.Unit declared in ' type=kotlin.Unit origin=null + fn: BLOCK type=kotlin.reflect.KFunction1 origin=null + FUN name:fnWithDefault visibility:local modality:FINAL <> (p0:kotlin.Int) returnType:kotlin.Unit + VALUE_PARAMETER name:p0 index:0 type:kotlin.Int + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun fnWithDefault (a: kotlin.Int, b: kotlin.Int): kotlin.String declared in ' type=kotlin.String origin=null + a: GET_VAR 'p0: kotlin.Int declared in .testCoercionToUnit.fnWithDefault' type=kotlin.Int origin=null + FUNCTION_REFERENCE 'local final fun fnWithDefault (p0: kotlin.Int): kotlin.Unit declared in .testCoercionToUnit' type=kotlin.reflect.KFunction1 origin=null + FUN name:testImportedObjectMember visibility:public modality:FINAL <> () returnType:kotlin.String + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun testImportedObjectMember (): kotlin.String declared in ' + CALL 'public final fun use (fn: kotlin.Function1): kotlin.String declared in ' type=kotlin.String origin=null + fn: BLOCK type=kotlin.reflect.KFunction1 origin=null + FUN name:importedObjectMemberWithVarargs visibility:local modality:FINAL <> (p0:kotlin.Int) returnType:kotlin.String + VALUE_PARAMETER name:p0 index:0 type:kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun importedObjectMemberWithVarargs (p0: kotlin.Int): kotlin.String declared in .testImportedObjectMember' + CALL 'public final fun importedObjectMemberWithVarargs (vararg xs: kotlin.Int): kotlin.String declared in .Host' type=kotlin.String origin=null + $this: GET_OBJECT 'CLASS OBJECT name:Host modality:FINAL visibility:public superTypes:[kotlin.Any]' type=.Host + xs: VARARG type=kotlin.IntArray varargElementType=kotlin.Int + GET_VAR 'p0: kotlin.Int declared in .testImportedObjectMember.importedObjectMemberWithVarargs' type=kotlin.Int origin=null + FUNCTION_REFERENCE 'local final fun importedObjectMemberWithVarargs (p0: kotlin.Int): kotlin.String declared in .testImportedObjectMember' type=kotlin.reflect.KFunction1 origin=null diff --git a/compiler/testData/ir/irText/expressions/callableReferenceWithVarargViewedAsArray.fir.txt b/compiler/testData/ir/irText/expressions/callableReferenceWithVarargViewedAsArray.fir.txt new file mode 100644 index 00000000000..36abd7accb4 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/callableReferenceWithVarargViewedAsArray.fir.txt @@ -0,0 +1,74 @@ +FILE fqName: fileName:/callableReferenceWithVarargViewedAsArray.kt + FUN name:sum visibility:public modality:FINAL <> (args:kotlin.IntArray) returnType:kotlin.Int + VALUE_PARAMETER name:args index:0 type:kotlin.IntArray + BLOCK_BODY + VAR name:result type:kotlin.Int [var] + CONST Int type=kotlin.Int value=0 + VAR IR_TEMPORARY_VARIABLE name:tmp_0 type:kotlin.IntArray [val] + GET_VAR 'args: kotlin.IntArray declared in .sum' type=kotlin.IntArray origin=null + VAR IR_TEMPORARY_VARIABLE name:tmp_1 type:kotlin.collections.IntIterator [val] + CALL 'public final fun iterator (): kotlin.collections.IntIterator [operator] declared in kotlin.IntArray' type=kotlin.collections.IntIterator origin=null + $this: GET_VAR 'val tmp_0: kotlin.IntArray [val] declared in .sum' type=kotlin.IntArray origin=null + WHILE label=null origin=FOR_LOOP_INNER_WHILE + condition: CALL 'public abstract fun hasNext (): kotlin.Boolean [operator] declared in kotlin.collections.Iterator' type=kotlin.Boolean origin=null + $this: GET_VAR 'val tmp_1: kotlin.collections.IntIterator [val] declared in .sum' type=kotlin.collections.IntIterator origin=null + body: BLOCK type=kotlin.Unit origin=null + VAR name:arg type:kotlin.Int [val] + CALL 'public final fun next (): kotlin.Int [operator] declared in kotlin.collections.IntIterator' type=kotlin.Int origin=null + $this: GET_VAR 'val tmp_1: kotlin.collections.IntIterator [val] declared in .sum' type=kotlin.collections.IntIterator origin=null + SET_VAR 'var result: kotlin.Int [var] declared in .sum' type=kotlin.Int origin=null + CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null + $this: GET_VAR 'var result: kotlin.Int [var] declared in .sum' type=kotlin.Int origin=null + other: GET_VAR 'val arg: kotlin.Int [val] declared in .sum' type=kotlin.Int origin=null + RETURN type=kotlin.Nothing from='public final fun sum (args: kotlin.IntArray): kotlin.Int declared in ' + GET_VAR 'var result: kotlin.Int [var] declared in .sum' type=kotlin.Int origin=null + FUN name:nsum visibility:public modality:FINAL <> (args:kotlin.Array) returnType:kotlin.Int + VALUE_PARAMETER name:args index:0 type:kotlin.Array + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun nsum (args: kotlin.Array): kotlin.Int declared in ' + CALL 'public final fun sum (args: kotlin.IntArray): kotlin.Int declared in ' type=kotlin.Int origin=null + args: CONSTRUCTOR_CALL 'public constructor (size: kotlin.Int, init: kotlin.Function1) declared in kotlin.IntArray' type=kotlin.IntArray origin=null + size: CALL 'public final fun (): kotlin.Int declared in kotlin.Array' type=kotlin.Int origin=null + $this: GET_VAR 'args: kotlin.Array declared in .nsum' type=kotlin.Array origin=null + init: FUN_EXPR type=kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Int + VALUE_PARAMETER name:it index:0 type:kotlin.Int + BLOCK_BODY + CALL 'public abstract fun toInt (): kotlin.Int declared in kotlin.Number' type=kotlin.Int origin=null + $this: CALL 'public final fun get (index: kotlin.Int): kotlin.Number [operator] declared in kotlin.Array' type=kotlin.Number origin=null + $this: GET_VAR 'args: kotlin.Array declared in .nsum' type=kotlin.Array origin=null + index: GET_VAR 'it: kotlin.Int declared in .nsum.' type=kotlin.Int origin=null + FUN name:zap visibility:public modality:FINAL <> (b:kotlin.Array, k:kotlin.Int) returnType:kotlin.Unit + VALUE_PARAMETER name:b index:0 type:kotlin.Array + VALUE_PARAMETER name:k index:1 type:kotlin.Int + EXPRESSION_BODY + CONST Int type=kotlin.Int value=42 + BLOCK_BODY + FUN name:usePlainArgs visibility:public modality:FINAL <> (fn:kotlin.Function2) returnType:kotlin.Unit + VALUE_PARAMETER name:fn index:0 type:kotlin.Function2 + BLOCK_BODY + FUN name:usePrimitiveArray visibility:public modality:FINAL <> (fn:kotlin.Function1) returnType:kotlin.Unit + VALUE_PARAMETER name:fn index:0 type:kotlin.Function1 + BLOCK_BODY + FUN name:useArray visibility:public modality:FINAL <> (fn:kotlin.Function1, kotlin.Int>) returnType:kotlin.Unit + VALUE_PARAMETER name:fn index:0 type:kotlin.Function1, kotlin.Int> + BLOCK_BODY + FUN name:useStringArray visibility:public modality:FINAL <> (fn:kotlin.Function1, kotlin.Unit>) returnType:kotlin.Unit + VALUE_PARAMETER name:fn index:0 type:kotlin.Function1, kotlin.Unit> + BLOCK_BODY + FUN name:testPlainArgs visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + ERROR_CALL 'Unresolved reference: #' type=IrErrorType + FUNCTION_REFERENCE 'public final fun sum (args: kotlin.IntArray): kotlin.Int declared in ' type=kotlin.reflect.KFunction1 origin=null + FUN name:testPrimitiveArrayAsVararg visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + CALL 'public final fun usePrimitiveArray (fn: kotlin.Function1): kotlin.Unit declared in ' type=kotlin.Unit origin=null + fn: FUNCTION_REFERENCE 'public final fun sum (args: kotlin.IntArray): kotlin.Int declared in ' type=kotlin.reflect.KFunction1 origin=null + FUN name:testArrayAsVararg visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + ERROR_CALL 'Unresolved reference: #' type=IrErrorType + FUNCTION_REFERENCE 'public final fun nsum (args: kotlin.Array): kotlin.Int declared in ' type=kotlin.reflect.KFunction1, kotlin.Int> origin=null + FUN name:testArrayAndDefaults visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + ERROR_CALL 'Unresolved reference: #' type=IrErrorType + FUNCTION_REFERENCE 'public final fun zap (b: kotlin.Array, k: kotlin.Int): kotlin.Unit declared in ' type=kotlin.reflect.KFunction2, kotlin.Int, kotlin.Unit> origin=null diff --git a/compiler/testData/ir/irText/expressions/callableReferenceWithVarargViewedAsArray.kt b/compiler/testData/ir/irText/expressions/callableReferenceWithVarargViewedAsArray.kt new file mode 100644 index 00000000000..5ee75aec534 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/callableReferenceWithVarargViewedAsArray.kt @@ -0,0 +1,22 @@ +// !LANGUAGE: +NewInference, +FunctionReferenceWithDefaultValueAsOtherType + +fun sum(vararg args: Int): Int { + var result = 0 + for (arg in args) + result += arg + return result +} + +fun nsum(vararg args: Number) = sum(*IntArray(args.size) { args[it].toInt() }) + +fun zap(vararg b: String, k: Int = 42) {} + +fun usePlainArgs(fn: (Int, Int) -> Int) {} +fun usePrimitiveArray(fn: (IntArray) -> Int) {} +fun useArray(fn: (Array) -> Int) {} +fun useStringArray(fn: (Array) -> Unit) {} + +fun testPlainArgs() { usePlainArgs(::sum) } +fun testPrimitiveArrayAsVararg() { usePrimitiveArray(::sum) } +fun testArrayAsVararg() { useArray(::nsum) } +fun testArrayAndDefaults() { useStringArray(::zap) } diff --git a/compiler/testData/ir/irText/expressions/callableReferenceWithVarargViewedAsArray.txt b/compiler/testData/ir/irText/expressions/callableReferenceWithVarargViewedAsArray.txt new file mode 100644 index 00000000000..2912fcb183c --- /dev/null +++ b/compiler/testData/ir/irText/expressions/callableReferenceWithVarargViewedAsArray.txt @@ -0,0 +1,94 @@ +FILE fqName: fileName:/callableReferenceWithVarargViewedAsArray.kt + FUN name:sum visibility:public modality:FINAL <> (args:kotlin.IntArray) returnType:kotlin.Int + VALUE_PARAMETER name:args index:0 type:kotlin.IntArray varargElementType:kotlin.Int [vararg] + BLOCK_BODY + VAR name:result type:kotlin.Int [var] + CONST Int type=kotlin.Int value=0 + BLOCK type=kotlin.Unit origin=FOR_LOOP + VAR FOR_LOOP_ITERATOR name:tmp_0 type:kotlin.collections.IntIterator [val] + CALL 'public final fun iterator (): kotlin.collections.IntIterator [operator] declared in kotlin.IntArray' type=kotlin.collections.IntIterator origin=FOR_LOOP_ITERATOR + $this: GET_VAR 'args: kotlin.IntArray [vararg] declared in .sum' type=kotlin.IntArray origin=null + WHILE label=null origin=FOR_LOOP_INNER_WHILE + condition: CALL 'public abstract fun hasNext (): kotlin.Boolean [fake_override,operator] declared in kotlin.collections.IntIterator' type=kotlin.Boolean origin=FOR_LOOP_HAS_NEXT + $this: GET_VAR 'val tmp_0: kotlin.collections.IntIterator [val] declared in .sum' type=kotlin.collections.IntIterator origin=null + body: BLOCK type=kotlin.Unit origin=FOR_LOOP_INNER_WHILE + VAR FOR_LOOP_VARIABLE name:arg type:kotlin.Int [val] + CALL 'public final fun next (): kotlin.Int [operator] declared in kotlin.collections.IntIterator' type=kotlin.Int origin=FOR_LOOP_NEXT + $this: GET_VAR 'val tmp_0: kotlin.collections.IntIterator [val] declared in .sum' type=kotlin.collections.IntIterator origin=null + SET_VAR 'var result: kotlin.Int [var] declared in .sum' type=kotlin.Unit origin=PLUSEQ + CALL 'public final fun plus (other: kotlin.Int): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=PLUSEQ + $this: GET_VAR 'var result: kotlin.Int [var] declared in .sum' type=kotlin.Int origin=PLUSEQ + other: GET_VAR 'val arg: kotlin.Int [val] declared in .sum' type=kotlin.Int origin=null + RETURN type=kotlin.Nothing from='public final fun sum (vararg args: kotlin.Int): kotlin.Int declared in ' + GET_VAR 'var result: kotlin.Int [var] declared in .sum' type=kotlin.Int origin=null + FUN name:nsum visibility:public modality:FINAL <> (args:kotlin.Array) returnType:kotlin.Int + VALUE_PARAMETER name:args index:0 type:kotlin.Array varargElementType:kotlin.Number [vararg] + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun nsum (vararg args: kotlin.Number): kotlin.Int declared in ' + CALL 'public final fun sum (vararg args: kotlin.Int): kotlin.Int declared in ' type=kotlin.Int origin=null + args: VARARG type=kotlin.IntArray varargElementType=kotlin.Int + SPREAD_ELEMENT + CONSTRUCTOR_CALL 'public constructor (size: kotlin.Int, init: kotlin.Function1) declared in kotlin.IntArray' type=kotlin.IntArray origin=null + size: CALL 'public final fun (): kotlin.Int declared in kotlin.Array' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR 'args: kotlin.Array [vararg] declared in .nsum' type=kotlin.Array origin=null + init: FUN_EXPR type=kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Int + VALUE_PARAMETER name:it index:0 type:kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (it: kotlin.Int): kotlin.Int declared in .nsum' + CALL 'public abstract fun toInt (): kotlin.Int declared in kotlin.Number' type=kotlin.Int origin=null + $this: CALL 'public final fun get (index: kotlin.Int): T of kotlin.Array [operator] declared in kotlin.Array' type=kotlin.Number origin=GET_ARRAY_ELEMENT + $this: GET_VAR 'args: kotlin.Array [vararg] declared in .nsum' type=kotlin.Array origin=null + index: GET_VAR 'it: kotlin.Int declared in .nsum.' type=kotlin.Int origin=null + FUN name:zap visibility:public modality:FINAL <> (b:kotlin.Array, k:kotlin.Int) returnType:kotlin.Unit + VALUE_PARAMETER name:b index:0 type:kotlin.Array varargElementType:kotlin.String [vararg] + VALUE_PARAMETER name:k index:1 type:kotlin.Int + EXPRESSION_BODY + CONST Int type=kotlin.Int value=42 + BLOCK_BODY + FUN name:usePlainArgs visibility:public modality:FINAL <> (fn:kotlin.Function2) returnType:kotlin.Unit + VALUE_PARAMETER name:fn index:0 type:kotlin.Function2 + BLOCK_BODY + FUN name:usePrimitiveArray visibility:public modality:FINAL <> (fn:kotlin.Function1) returnType:kotlin.Unit + VALUE_PARAMETER name:fn index:0 type:kotlin.Function1 + BLOCK_BODY + FUN name:useArray visibility:public modality:FINAL <> (fn:kotlin.Function1, kotlin.Int>) returnType:kotlin.Unit + VALUE_PARAMETER name:fn index:0 type:kotlin.Function1, kotlin.Int> + BLOCK_BODY + FUN name:useStringArray visibility:public modality:FINAL <> (fn:kotlin.Function1, kotlin.Unit>) returnType:kotlin.Unit + VALUE_PARAMETER name:fn index:0 type:kotlin.Function1, kotlin.Unit> + BLOCK_BODY + FUN name:testPlainArgs visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + CALL 'public final fun usePlainArgs (fn: kotlin.Function2): kotlin.Unit declared in ' type=kotlin.Unit origin=null + fn: BLOCK type=kotlin.reflect.KFunction2 origin=null + FUN name:sum visibility:local modality:FINAL <> (p0:kotlin.Int, p1:kotlin.Int) returnType:kotlin.Int + VALUE_PARAMETER name:p0 index:0 type:kotlin.Int + VALUE_PARAMETER name:p1 index:1 type:kotlin.Int + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun sum (p0: kotlin.Int, p1: kotlin.Int): kotlin.Int declared in .testPlainArgs' + CALL 'public final fun sum (vararg args: kotlin.Int): kotlin.Int declared in ' type=kotlin.Int origin=null + args: VARARG type=kotlin.IntArray varargElementType=kotlin.Int + GET_VAR 'p0: kotlin.Int declared in .testPlainArgs.sum' type=kotlin.Int origin=null + GET_VAR 'p1: kotlin.Int declared in .testPlainArgs.sum' type=kotlin.Int origin=null + FUNCTION_REFERENCE 'local final fun sum (p0: kotlin.Int, p1: kotlin.Int): kotlin.Int declared in .testPlainArgs' type=kotlin.reflect.KFunction2 origin=null + FUN name:testPrimitiveArrayAsVararg visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + CALL 'public final fun usePrimitiveArray (fn: kotlin.Function1): kotlin.Unit declared in ' type=kotlin.Unit origin=null + fn: FUNCTION_REFERENCE 'public final fun sum (vararg args: kotlin.Int): kotlin.Int declared in ' type=kotlin.reflect.KFunction1 origin=null + FUN name:testArrayAsVararg visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + CALL 'public final fun useArray (fn: kotlin.Function1, kotlin.Int>): kotlin.Unit declared in ' type=kotlin.Unit origin=null + fn: FUNCTION_REFERENCE 'public final fun nsum (vararg args: kotlin.Number): kotlin.Int declared in ' type=kotlin.reflect.KFunction1, kotlin.Int> origin=null + FUN name:testArrayAndDefaults visibility:public modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + CALL 'public final fun useStringArray (fn: kotlin.Function1, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null + fn: BLOCK type=kotlin.reflect.KFunction1, kotlin.Unit> origin=null + FUN name:zap visibility:local modality:FINAL <> (p0:kotlin.Array) returnType:kotlin.Unit + VALUE_PARAMETER name:p0 index:0 type:kotlin.Array + BLOCK_BODY + CALL 'public final fun zap (vararg b: kotlin.String, k: kotlin.Int): kotlin.Unit declared in ' type=kotlin.Unit origin=null + b: VARARG type=kotlin.Array varargElementType=kotlin.String + SPREAD_ELEMENT + GET_VAR 'p0: kotlin.Array declared in .testArrayAndDefaults.zap' type=kotlin.Array origin=null + FUNCTION_REFERENCE 'local final fun zap (p0: kotlin.Array): kotlin.Unit declared in .testArrayAndDefaults' type=kotlin.reflect.KFunction1, kotlin.Unit> origin=null diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index df7dad6883e..92bbfec52c7 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -801,6 +801,16 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { runTest("compiler/testData/ir/irText/expressions/callableReferenceTypeArguments.kt"); } + @TestMetadata("callableReferenceWithArgumentsConversion.kt") + public void testCallableReferenceWithArgumentsConversion() throws Exception { + runTest("compiler/testData/ir/irText/expressions/callableReferenceWithArgumentsConversion.kt"); + } + + @TestMetadata("callableReferenceWithVarargViewedAsArray.kt") + public void testCallableReferenceWithVarargViewedAsArray() throws Exception { + runTest("compiler/testData/ir/irText/expressions/callableReferenceWithVarargViewedAsArray.kt"); + } + @TestMetadata("calls.kt") public void testCalls() throws Exception { runTest("compiler/testData/ir/irText/expressions/calls.kt");