diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/SamType.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/SamType.java index 40fcf602324..63db01fda63 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/SamType.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/SamType.java @@ -32,17 +32,31 @@ import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt; public class SamType { @Nullable public static SamType createByValueParameter(@NotNull ValueParameterDescriptor valueParameter) { + KotlinType singleArgumentType; + KotlinType originalSingleArgumentType; + KotlinType varargElementType = valueParameter.getVarargElementType(); + if (varargElementType != null) { + singleArgumentType = varargElementType; + originalSingleArgumentType = valueParameter.getOriginal().getVarargElementType(); + assert originalSingleArgumentType != null : + "Value parameter and original value parameter have inconsistent varargs: " + + valueParameter + "; " + valueParameter.getOriginal(); + } else { + singleArgumentType = valueParameter.getType(); + originalSingleArgumentType = valueParameter.getOriginal().getType(); + } + KotlinType originalTypeToUse = // This can be true in case when the value parameter is in the method of a generic type with out-projection. // We approximate Inv to Nothing, while Inv itself can be a SAM interface safe to call here // (see testData genericSamProjectedOut.kt for details) - KotlinBuiltIns.isNothing(valueParameter.getType()) + KotlinBuiltIns.isNothing(singleArgumentType) // In such a case we can't have a proper supertype since wildcards are not allowed there, // so we use Nothing arguments instead that leads to a raw type used for a SAM wrapper. // See org.jetbrains.kotlin.codegen.state.KotlinTypeMapper#writeGenericType to understand how // raw types and Nothing arguments relate. - ? TypeUtilsKt.replaceArgumentsWithNothing(valueParameter.getOriginal().getType()) - : valueParameter.getType(); + ? TypeUtilsKt.replaceArgumentsWithNothing(originalSingleArgumentType) + : singleArgumentType; return create(TypeMapperUtilsKt.removeExternalProjections(originalTypeToUse)); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java index 23735161f07..b11ddf1694e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java @@ -42,10 +42,7 @@ import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; -import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument; -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; -import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument; -import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall; +import org.jetbrains.kotlin.resolve.calls.model.*; import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl; import org.jetbrains.kotlin.resolve.calls.tower.NewVariableAsFunctionResolvedCallImpl; import org.jetbrains.kotlin.resolve.constants.ConstantValue; @@ -799,12 +796,16 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { CallableDescriptor descriptor = call.getResultingDescriptor(); if (!(descriptor instanceof FunctionDescriptor)) return; - recordSamValueForNewInference(call); + recordSamValuesForNewInference(call); recordSamConstructorIfNeeded(expression, call); + recordSamValuesForOldInference(call, descriptor); + } + private void recordSamValuesForOldInference(ResolvedCall call, CallableDescriptor descriptor) { FunctionDescriptor original = SamCodegenUtil.getOriginalIfSamAdapter((FunctionDescriptor) descriptor); if (original == null) return; + // TODO we can just record SAM_VALUE on relevant value arguments as we do in recordSamValuesForNewInference List valueParametersWithSAMConversion = new SmartList<>(); for (ValueParameterDescriptor valueParameter : original.getValueParameters()) { ValueParameterDescriptor adaptedParameter = descriptor.getValueParameters().get(valueParameter.getIndex()); @@ -814,30 +815,43 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { writeSamValueForValueParameters(valueParametersWithSAMConversion, call.getValueArgumentsByIndex()); } - private void recordSamValueForNewInference(@NotNull ResolvedCall call) { - NewResolvedCallImpl newResolvedCall = null; - if (call instanceof NewVariableAsFunctionResolvedCallImpl) { - newResolvedCall = ((NewVariableAsFunctionResolvedCallImpl) call).getFunctionCall(); - } - else if(call instanceof NewResolvedCallImpl) { - newResolvedCall = (NewResolvedCallImpl) call; - } + private void recordSamValuesForNewInference(@NotNull ResolvedCall call) { + NewResolvedCallImpl newResolvedCall = getNewResolvedCallForCallWithPossibleSamConversions(call); if (newResolvedCall == null) return; - List valueParametersWithSAMConversion = new SmartList<>(); Map arguments = newResolvedCall.getValueArguments(); for (ValueParameterDescriptor valueParameter : arguments.keySet()) { + SamType samType = SamType.createByValueParameter(valueParameter); + if (samType == null) continue; + ResolvedValueArgument argument = arguments.get(valueParameter); - - if (!(argument instanceof ExpressionValueArgument)) continue; - ValueArgument valueArgument = ((ExpressionValueArgument) argument).getValueArgument(); - - if (valueArgument == null || newResolvedCall.getExpectedTypeForSamConvertedArgument(valueArgument) == null) continue; - - valueParametersWithSAMConversion.add(valueParameter); + if (argument instanceof ExpressionValueArgument) { + ValueArgument valueArgument = ((ExpressionValueArgument) argument).getValueArgument(); + if (valueArgument != null && newResolvedCall.getExpectedTypeForSamConvertedArgument(valueArgument) != null) { + recordSamTypeOnArgumentExpression(samType, valueArgument); + } + } else if (argument instanceof VarargValueArgument) { + VarargValueArgument varargValueArgument = (VarargValueArgument) argument; + for (ValueArgument valueArgument : varargValueArgument.getArguments()) { + if (valueArgument != null && newResolvedCall.getExpectedTypeForSamConvertedArgument(valueArgument) != null) { + recordSamTypeOnArgumentExpression(samType, valueArgument); + } + } + } } - writeSamValueForValueParameters(valueParametersWithSAMConversion, newResolvedCall.getValueArgumentsByIndex()); + } + @Nullable + private static NewResolvedCallImpl getNewResolvedCallForCallWithPossibleSamConversions(@NotNull ResolvedCall call) { + if (call instanceof NewVariableAsFunctionResolvedCallImpl) { + return ((NewVariableAsFunctionResolvedCallImpl) call).getFunctionCall(); + } + else if (call instanceof NewResolvedCallImpl) { + return (NewResolvedCallImpl) call; + } + else { + return null; + } } private void writeSamValueForValueParameters( @@ -854,13 +868,17 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { assert resolvedValueArgument instanceof ExpressionValueArgument : resolvedValueArgument; ValueArgument valueArgument = ((ExpressionValueArgument) resolvedValueArgument).getValueArgument(); assert valueArgument != null; - KtExpression argumentExpression = valueArgument.getArgumentExpression(); - assert argumentExpression != null : valueArgument.asElement().getText(); - - bindingTrace.record(CodegenBinding.SAM_VALUE, argumentExpression, samType); + recordSamTypeOnArgumentExpression(samType, valueArgument); } } + private void recordSamTypeOnArgumentExpression(SamType samType, ValueArgument valueArgument) { + KtExpression argumentExpression = valueArgument.getArgumentExpression(); + assert argumentExpression != null : valueArgument.asElement().getText(); + + bindingTrace.record(CodegenBinding.SAM_VALUE, argumentExpression, samType); + } + @Override public void visitSuperTypeCallEntry(@NotNull KtSuperTypeCallEntry call) { // Closures in super type constructor calls for anonymous objects are created in outer context @@ -942,7 +960,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { if (!(operationDescriptor instanceof FunctionDescriptor)) return; ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext); - if (resolvedCall != null) recordSamValueForNewInference(resolvedCall); + if (resolvedCall != null) recordSamValuesForNewInference(resolvedCall); FunctionDescriptor original = SamCodegenUtil.getOriginalIfSamAdapter((FunctionDescriptor) operationDescriptor); if (original == null) return; @@ -967,7 +985,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { if (!(operationDescriptor instanceof FunctionDescriptor)) return; ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext); - if (resolvedCall != null) recordSamValueForNewInference(resolvedCall); + if (resolvedCall != null) recordSamValuesForNewInference(resolvedCall); boolean isSetter = operationDescriptor.getName().asString().equals("set"); FunctionDescriptor original = SamCodegenUtil.getOriginalIfSamAdapter((FunctionDescriptor) operationDescriptor); diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 8f1d5e74dd9..4d05b6d2b57 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -11205,6 +11205,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt"); } + @TestMetadata("funConversionInVararg.kt") + public void testFunConversionInVararg() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt"); + } + @TestMetadata("funInterfaceInheritance.kt") public void testFunInterfaceInheritance() throws Exception { runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt"); @@ -28143,6 +28148,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/sam/kt24825.kt"); } + @TestMetadata("kt31908.kt") + public void testKt31908() throws Exception { + runTest("compiler/testData/codegen/box/sam/kt31908.kt"); + } + @TestMetadata("nonInlinedSamWrapper.kt") public void testNonInlinedSamWrapper() throws Exception { runTest("compiler/testData/codegen/box/sam/nonInlinedSamWrapper.kt"); diff --git a/compiler/testData/codegen/box/funInterface/funConversionInVararg.kt b/compiler/testData/codegen/box/funInterface/funConversionInVararg.kt new file mode 100644 index 00000000000..c27161ecda4 --- /dev/null +++ b/compiler/testData/codegen/box/funInterface/funConversionInVararg.kt @@ -0,0 +1,17 @@ +// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +fun interface MyRunnable { + fun run() +} + +fun box(): String { + var result = "failed" + val r = MyRunnable { result += "K" } + foo({ result = "O" }, r) + return result +} + +fun foo(vararg rs: MyRunnable) { + for (r in rs) { + r.run() + } +} diff --git a/compiler/testData/codegen/box/sam/kt31908.kt b/compiler/testData/codegen/box/sam/kt31908.kt new file mode 100644 index 00000000000..3d7df05a9b4 --- /dev/null +++ b/compiler/testData/codegen/box/sam/kt31908.kt @@ -0,0 +1,17 @@ +// TARGET_BACKEND: JVM +// FILE: kt31908.kt +fun box(): String { + var result = "failed" + val r = java.lang.Runnable { result += "K" } + J().foo({ result = "O" }, r) + return result +} + +// FILE: J.java +public class J { + public void foo(Runnable... rs) { + for (Runnable r : rs) { + r.run(); + } + } +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 1dd669efe64..977c20b6542 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -12420,6 +12420,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt"); } + @TestMetadata("funConversionInVararg.kt") + public void testFunConversionInVararg() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt"); + } + @TestMetadata("funInterfaceInheritance.kt") public void testFunInterfaceInheritance() throws Exception { runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt"); @@ -29729,6 +29734,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/sam/kt24825.kt"); } + @TestMetadata("kt31908.kt") + public void testKt31908() throws Exception { + runTest("compiler/testData/codegen/box/sam/kt31908.kt"); + } + @TestMetadata("nonInlinedSamWrapper.kt") public void testNonInlinedSamWrapper() throws Exception { runTest("compiler/testData/codegen/box/sam/nonInlinedSamWrapper.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index d803ef856a3..3d786a7d4fb 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -12425,6 +12425,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt"); } + @TestMetadata("funConversionInVararg.kt") + public void testFunConversionInVararg() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt"); + } + @TestMetadata("funInterfaceWithReceiver.kt") public void testFunInterfaceWithReceiver() throws Exception { runTest("compiler/testData/codegen/box/funInterface/funInterfaceWithReceiver.kt"); @@ -27363,6 +27368,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/sam/kt24825.kt"); } + @TestMetadata("kt31908.kt") + public void testKt31908() throws Exception { + runTest("compiler/testData/codegen/box/sam/kt31908.kt"); + } + @TestMetadata("nonInlinedSamWrapper.kt") public void testNonInlinedSamWrapper() throws Exception { runTest("compiler/testData/codegen/box/sam/nonInlinedSamWrapper.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 24ef15fd00f..e60b535217b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -11205,6 +11205,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt"); } + @TestMetadata("funConversionInVararg.kt") + public void testFunConversionInVararg() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt"); + } + @TestMetadata("funInterfaceInheritance.kt") public void testFunInterfaceInheritance() throws Exception { runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt"); @@ -28143,6 +28148,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/sam/kt24825.kt"); } + @TestMetadata("kt31908.kt") + public void testKt31908() throws Exception { + runTest("compiler/testData/codegen/box/sam/kt31908.kt"); + } + @TestMetadata("nonInlinedSamWrapper.kt") public void testNonInlinedSamWrapper() throws Exception { runTest("compiler/testData/codegen/box/sam/nonInlinedSamWrapper.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 86b18ac8de4..969f2e1db44 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -9605,6 +9605,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt"); } + @TestMetadata("funConversionInVararg.kt") + public void testFunConversionInVararg() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt"); + } + @TestMetadata("funInterfaceInheritance.kt") public void testFunInterfaceInheritance() throws Exception { runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 1337d969d4e..377e1001d25 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -9615,6 +9615,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt"); } + @TestMetadata("funConversionInVararg.kt") + public void testFunConversionInVararg() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt"); + } + @TestMetadata("funInterfaceInheritance.kt") public void testFunInterfaceInheritance() throws Exception { runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 38b2e619aa6..fcc63b7e209 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -9615,6 +9615,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt"); } + @TestMetadata("funConversionInVararg.kt") + public void testFunConversionInVararg() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/funConversionInVararg.kt"); + } + @TestMetadata("funInterfaceInheritance.kt") public void testFunInterfaceInheritance() throws Exception { runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt");