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 f2d1b03897d..af47c3f93a7 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/fir/Fir2IrTextTestGenerated.java @@ -1595,6 +1595,11 @@ public class Fir2IrTextTestGenerated extends AbstractFir2IrTextTest { runTest("compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargs.kt"); } + @TestMetadata("samConversionInVarargsMixed.kt") + public void testSamConversionInVarargsMixed() throws Exception { + runTest("compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargsMixed.kt"); + } + @TestMetadata("samConversionOnCallableReference.kt") public void testSamConversionOnCallableReference() throws Exception { runTest("compiler/testData/ir/irText/expressions/funInterface/samConversionOnCallableReference.kt"); diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt index 46441cef330..5a88e8f3cd3 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ArgumentsGenerationUtils.kt @@ -23,7 +23,10 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.incremental.components.NoLookupLocation -import org.jetbrains.kotlin.ir.builders.* +import org.jetbrains.kotlin.ir.builders.irBlock +import org.jetbrains.kotlin.ir.builders.irBlockBody +import org.jetbrains.kotlin.ir.builders.irGet +import org.jetbrains.kotlin.ir.builders.irTemporary import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl @@ -619,10 +622,11 @@ fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(call: Ca for (i in underlyingValueParameters.indices) { val underlyingValueParameter = underlyingValueParameters[i] + val expectedSamConversionTypesForVararg = ArrayList() if (expectSamConvertedArgumentToBeAvailableInResolvedCall && resolvedCall is NewResolvedCallImpl<*>) { - // TODO support SAM conversion of varargs - val argument = resolvedCall.valueArguments[originalValueParameters[i]]?.arguments?.singleOrNull() ?: continue - resolvedCall.getExpectedTypeForSamConvertedArgument(argument) ?: continue + val arguments = resolvedCall.valueArguments[originalValueParameters[i]]?.arguments ?: continue + arguments.mapTo(expectedSamConversionTypesForVararg) { resolvedCall.getExpectedTypeForSamConvertedArgument(it) } + if (expectedSamConversionTypesForVararg.all { it == null }) continue } else { // When the method is `f(T)` with `T` = a SAM type, the substituted type is a SAM while the original is not; // when the method is `f(X)` with `T` = `out V` where `X` is a SAM type, the substituted type is `Nothing` @@ -678,11 +682,16 @@ fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(call: Ca substitutedVarargType.toIrType(), irSamType ).apply { - originalArgument.elements.mapTo(elements) { - if (it is IrExpression) - samConvertScalarExpression(it) - else + originalArgument.elements.mapIndexedTo(elements) { index, element -> + if (element is IrExpression) { + val samType = expectedSamConversionTypesForVararg[index] + if (samType != null) + samConvertScalarExpression(element) + else + element + } else { throw AssertionError("Unsupported: spread vararg element with SAM conversion") + } } } } diff --git a/compiler/testData/codegen/box/funInterface/funConversionInVararg.kt b/compiler/testData/codegen/box/funInterface/funConversionInVararg.kt index c27161ecda4..5741ce3e58b 100644 --- a/compiler/testData/codegen/box/funInterface/funConversionInVararg.kt +++ b/compiler/testData/codegen/box/funInterface/funConversionInVararg.kt @@ -1,4 +1,6 @@ // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +// IGNORE_BACKEND_FIR: JVM_IR + fun interface MyRunnable { fun run() } diff --git a/compiler/testData/codegen/box/sam/kt31908.kt b/compiler/testData/codegen/box/sam/kt31908.kt index 3d7df05a9b4..ae6700d1e89 100644 --- a/compiler/testData/codegen/box/sam/kt31908.kt +++ b/compiler/testData/codegen/box/sam/kt31908.kt @@ -1,4 +1,5 @@ // TARGET_BACKEND: JVM +// IGNORE_BACKEND_FIR: JVM_IR // FILE: kt31908.kt fun box(): String { var result = "failed" diff --git a/compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargs.txt b/compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargs.txt index 34a2eb0fff8..df7093b1723 100644 --- a/compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargs.txt +++ b/compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargs.txt @@ -35,21 +35,21 @@ FILE fqName: fileName:/samConversionInVarargs.kt BLOCK_BODY CALL 'public final fun useVararg (vararg foos: .IFoo): kotlin.Unit declared in ' type=kotlin.Unit origin=null foos: VARARG type=kotlin.Array.IFoo> varargElementType=.IFoo - TYPE_OP type=.IFoo origin=IMPLICIT_CAST typeOperand=.IFoo + TYPE_OP type=.IFoo origin=SAM_CONVERSION typeOperand=.IFoo FUN_EXPR type=kotlin.Function1<@[ParameterName(name = 'i')] kotlin.Int, kotlin.Unit> origin=LAMBDA FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Unit VALUE_PARAMETER name:it index:0 type:kotlin.Int BLOCK_BODY RETURN type=kotlin.Nothing from='local final fun (it: kotlin.Int): kotlin.Unit declared in .testSeveralLambdas' GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit - TYPE_OP type=.IFoo origin=IMPLICIT_CAST typeOperand=.IFoo + TYPE_OP type=.IFoo origin=SAM_CONVERSION typeOperand=.IFoo FUN_EXPR type=kotlin.Function1<@[ParameterName(name = 'i')] kotlin.Int, kotlin.Unit> origin=LAMBDA FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Unit VALUE_PARAMETER name:it index:0 type:kotlin.Int BLOCK_BODY RETURN type=kotlin.Nothing from='local final fun (it: kotlin.Int): kotlin.Unit declared in .testSeveralLambdas' GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit - TYPE_OP type=.IFoo origin=IMPLICIT_CAST typeOperand=.IFoo + TYPE_OP type=.IFoo origin=SAM_CONVERSION typeOperand=.IFoo FUN_EXPR type=kotlin.Function1<@[ParameterName(name = 'i')] kotlin.Int, kotlin.Unit> origin=LAMBDA FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (it:kotlin.Int) returnType:kotlin.Unit VALUE_PARAMETER name:it index:0 type:kotlin.Int diff --git a/compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargsMixed.fir.txt b/compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargsMixed.fir.txt new file mode 100644 index 00000000000..6e37891949c --- /dev/null +++ b/compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargsMixed.fir.txt @@ -0,0 +1,39 @@ +FILE fqName: fileName:/samConversionInVarargsMixed.kt + CLASS INTERFACE name:MyRunnable modality:ABSTRACT visibility:public superTypes:[kotlin.Any] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.MyRunnable + FUN name:run visibility:public modality:ABSTRACT <> ($this:.MyRunnable) returnType:kotlin.Unit + $this: VALUE_PARAMETER name: type:.MyRunnable + 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:test visibility:public modality:FINAL <> (a:kotlin.Any, r:.MyRunnable) returnType:kotlin.Unit + VALUE_PARAMETER name:a index:0 type:kotlin.Any + VALUE_PARAMETER name:r index:1 type:.MyRunnable + BLOCK_BODY + WHEN type=kotlin.Unit origin=IF + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=.MyRunnable + GET_VAR 'a: kotlin.Any declared in .test' type=kotlin.Any origin=null + then: CALL 'public final fun foo (vararg rs: .MyRunnable): kotlin.Unit declared in ' type=kotlin.Unit origin=null + rs: VARARG type=kotlin.Array.MyRunnable> varargElementType=.MyRunnable + FUN_EXPR type=kotlin.Function0 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (): kotlin.Unit declared in .test' + GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit + GET_VAR 'r: .MyRunnable declared in .test' type=.MyRunnable origin=null + TYPE_OP type=.MyRunnable origin=IMPLICIT_CAST typeOperand=.MyRunnable + GET_VAR 'a: kotlin.Any declared in .test' type=kotlin.Any origin=null + FUN name:foo visibility:public modality:FINAL <> (rs:kotlin.Array.MyRunnable>) returnType:kotlin.Unit + VALUE_PARAMETER name:rs index:0 type:kotlin.Array.MyRunnable> varargElementType:.MyRunnable [vararg] + BLOCK_BODY diff --git a/compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargsMixed.kt b/compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargsMixed.kt new file mode 100644 index 00000000000..bbaeb03038c --- /dev/null +++ b/compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargsMixed.kt @@ -0,0 +1,12 @@ +// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +fun interface MyRunnable { + fun run() +} + +fun test(a: Any, r: MyRunnable) { + if (a is MyRunnable) { + foo({}, r, a) + } +} + +fun foo(vararg rs: MyRunnable) {} diff --git a/compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargsMixed.txt b/compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargsMixed.txt new file mode 100644 index 00000000000..7fef096d089 --- /dev/null +++ b/compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargsMixed.txt @@ -0,0 +1,41 @@ +FILE fqName: fileName:/samConversionInVarargsMixed.kt + CLASS INTERFACE name:MyRunnable modality:ABSTRACT visibility:public [fun] superTypes:[kotlin.Any] + $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.MyRunnable + FUN name:run visibility:public modality:ABSTRACT <> ($this:.MyRunnable) returnType:kotlin.Unit + $this: VALUE_PARAMETER name: type:.MyRunnable + 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:test visibility:public modality:FINAL <> (a:kotlin.Any, r:.MyRunnable) returnType:kotlin.Unit + VALUE_PARAMETER name:a index:0 type:kotlin.Any + VALUE_PARAMETER name:r index:1 type:.MyRunnable + BLOCK_BODY + WHEN type=kotlin.Unit origin=IF + BRANCH + if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=.MyRunnable + GET_VAR 'a: kotlin.Any declared in .test' type=kotlin.Any origin=null + then: BLOCK type=kotlin.Unit origin=null + CALL 'public final fun foo (vararg rs: .MyRunnable): kotlin.Unit declared in ' type=kotlin.Unit origin=null + rs: VARARG type=kotlin.Array.MyRunnable> varargElementType=.MyRunnable + TYPE_OP type=.MyRunnable origin=SAM_CONVERSION typeOperand=.MyRunnable + FUN_EXPR type=kotlin.Function0 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> () returnType:kotlin.Unit + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (): kotlin.Unit declared in .test' + GET_OBJECT 'CLASS IR_EXTERNAL_DECLARATION_STUB OBJECT name:Unit modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit + GET_VAR 'r: .MyRunnable declared in .test' type=.MyRunnable origin=null + TYPE_OP type=.MyRunnable origin=IMPLICIT_CAST typeOperand=.MyRunnable + GET_VAR 'a: kotlin.Any declared in .test' type=kotlin.Any origin=null + FUN name:foo visibility:public modality:FINAL <> (rs:kotlin.Array.MyRunnable>) returnType:kotlin.Unit + VALUE_PARAMETER name:rs index:0 type:kotlin.Array.MyRunnable> varargElementType:.MyRunnable [vararg] + BLOCK_BODY diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index ee268f7f7e5..aa456a0f6fc 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -1594,6 +1594,11 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { runTest("compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargs.kt"); } + @TestMetadata("samConversionInVarargsMixed.kt") + public void testSamConversionInVarargsMixed() throws Exception { + runTest("compiler/testData/ir/irText/expressions/funInterface/samConversionInVarargsMixed.kt"); + } + @TestMetadata("samConversionOnCallableReference.kt") public void testSamConversionOnCallableReference() throws Exception { runTest("compiler/testData/ir/irText/expressions/funInterface/samConversionOnCallableReference.kt");