diff --git a/compiler/testData/codegen/box/funInterface/basicFunInterfaceConversion.kt b/compiler/testData/codegen/box/funInterface/basicFunInterfaceConversion.kt index 243978ff3fe..6e454d357aa 100644 --- a/compiler/testData/codegen/box/funInterface/basicFunInterfaceConversion.kt +++ b/compiler/testData/codegen/box/funInterface/basicFunInterfaceConversion.kt @@ -1,6 +1,5 @@ // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions // IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND: JS // SKIP_DCE_DRIVEN fun interface Foo { diff --git a/compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt b/compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt new file mode 100644 index 00000000000..67282d3c519 --- /dev/null +++ b/compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt @@ -0,0 +1,33 @@ +// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions + +// IGNORE_BACKEND: JVM, JVM_IR, JS_IR +// IGNORE_BACKEND_FIR: JVM_IR +// SKIP_DCE_DRIVEN + +fun interface Base { + fun doStuff(): String +} + +fun interface I : Base + +fun interface Proxy : I { + + override fun doStuff(): String = doStuffInt().toString() + + fun doStuffInt(): Int +} + +fun runBase(b: Base) = b.doStuff() + +fun runI(i: I) = i.doStuff() + +fun runProxy(p: Proxy) = p.doStuff() + +fun box(): String { + + if (runI { "i" } != "i") return "fail1" + + if (runProxy { 10 } != "10") return "fail2" + + return runBase { "OK" } +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/funInterface/multimodule.kt b/compiler/testData/codegen/box/funInterface/multimodule.kt new file mode 100644 index 00000000000..90231c78ba5 --- /dev/null +++ b/compiler/testData/codegen/box/funInterface/multimodule.kt @@ -0,0 +1,32 @@ +// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions + +// IGNORE_BACKEND_FIR: JVM_IR +// SKIP_DCE_DRIVEN + +// MODULE: m1 +// FILE: m1.kt + +fun interface I { + fun f(): String +} + +fun rn(i: I) = i.f() + +inline fun rnInline(i: I) = i.f() + +// MODULE: m2(m1) +// FILE: m2.kt + +fun rn2(f: () -> String) = rn(f) + +inline fun rn2Inline(noinline f: () -> String) = rnInline(f) + +// MODULE: main(m2) +// FILE: main.kt + +fun box(): String { + + if (rn2Inline { "inline" } != "inline") return "fail" + + return rn2 { "OK" } +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/funInterface/nullableSam.kt b/compiler/testData/codegen/box/funInterface/nullableSam.kt index eb535398491..5c1e89d63a6 100644 --- a/compiler/testData/codegen/box/funInterface/nullableSam.kt +++ b/compiler/testData/codegen/box/funInterface/nullableSam.kt @@ -1,6 +1,5 @@ // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions // IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND: JS // WITH_RUNTIME // SKIP_DCE_DRIVEN diff --git a/compiler/testData/codegen/box/funInterface/partialSam.kt b/compiler/testData/codegen/box/funInterface/partialSam.kt index 8289e832a18..891493ca9f6 100644 --- a/compiler/testData/codegen/box/funInterface/partialSam.kt +++ b/compiler/testData/codegen/box/funInterface/partialSam.kt @@ -1,6 +1,5 @@ // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions // IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND: JS // WITH_RUNTIME // SKIP_DCE_DRIVEN diff --git a/compiler/testData/codegen/box/funInterface/primitiveConversions.kt b/compiler/testData/codegen/box/funInterface/primitiveConversions.kt new file mode 100644 index 00000000000..5386659a716 --- /dev/null +++ b/compiler/testData/codegen/box/funInterface/primitiveConversions.kt @@ -0,0 +1,20 @@ +// !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions + +// IGNORE_BACKEND_FIR: JVM_IR +// SKIP_DCE_DRIVEN + +// This test should check argument coercion between the SAM and the lambda. +// For now it checks that Char is boxed in JS + +fun interface CharToAny { + fun invoke(c: Char): Any +} + +fun foo(c: CharToAny): Any = c.invoke('O') + +fun box(): String { + + if (foo { it } !is Char) return "fail" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.kt b/compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.kt index f7609a450d0..10f627d4a2e 100644 --- a/compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.kt +++ b/compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.kt @@ -1,6 +1,5 @@ // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions // IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND: JS // WITH_RUNTIME // SKIP_DCE_DRIVEN diff --git a/compiler/testData/codegen/box/funInterface/suspendFunInterfaceConversionCodegen.kt b/compiler/testData/codegen/box/funInterface/suspendFunInterfaceConversionCodegen.kt index 7aff4f225ac..09681100305 100644 --- a/compiler/testData/codegen/box/funInterface/suspendFunInterfaceConversionCodegen.kt +++ b/compiler/testData/codegen/box/funInterface/suspendFunInterfaceConversionCodegen.kt @@ -1,11 +1,11 @@ // !LANGUAGE: +NewInference +FunctionalInterfaceConversion +SamConversionPerArgument +SamConversionForKotlinFunctions // IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND: JS, JS_IR +// IGNORE_BACKEND: JS_IR // WITH_COROUTINES // WITH_RUNTIME import helpers.* -import kotlin.coroutines.startCoroutine +import kotlin.coroutines.* fun interface SuspendRunnable { suspend fun invoke() @@ -17,11 +17,25 @@ fun run(r: SuspendRunnable) { var result = "initial" +var resumingCallback: () -> Unit = {} + suspend fun bar() { + // Generate proper state machine + suspendCoroutine { cont -> + resumingCallback = { + cont.resume(Unit) + } + } + result = "OK" } fun box(): String { run(::bar) + + if (result != "initial") return "fail" + + resumingCallback() + return result } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 7cd5bed518e..7c0c63f73dc 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -11723,11 +11723,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt"); } + @TestMetadata("funInterfaceInheritance.kt") + public void testFunInterfaceInheritance() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt"); + } + @TestMetadata("inlinedSamWrapper.kt") public void testInlinedSamWrapper() throws Exception { runTest("compiler/testData/codegen/box/funInterface/inlinedSamWrapper.kt"); } + @TestMetadata("multimodule.kt") + public void testMultimodule() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/multimodule.kt"); + } + @TestMetadata("nullableSam.kt") public void testNullableSam() throws Exception { runTest("compiler/testData/codegen/box/funInterface/nullableSam.kt"); @@ -11738,6 +11748,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/funInterface/partialSam.kt"); } + @TestMetadata("primitiveConversions.kt") + public void testPrimitiveConversions() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/primitiveConversions.kt"); + } + @TestMetadata("receiverEvaluatedOnce.kt") public void testReceiverEvaluatedOnce() throws Exception { runTest("compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 1b7628a3630..dc4b1b946cc 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -11700,6 +11700,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class FunInterface extends AbstractLightAnalysisModeTest { + @TestMetadata("funInterfaceInheritance.kt") + public void ignoreFunInterfaceInheritance() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt"); + } + private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); } @@ -11728,6 +11733,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/funInterface/inlinedSamWrapper.kt"); } + @TestMetadata("multimodule.kt") + public void testMultimodule() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/multimodule.kt"); + } + @TestMetadata("nullableSam.kt") public void testNullableSam() throws Exception { runTest("compiler/testData/codegen/box/funInterface/nullableSam.kt"); @@ -11738,6 +11748,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/funInterface/partialSam.kt"); } + @TestMetadata("primitiveConversions.kt") + public void testPrimitiveConversions() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/primitiveConversions.kt"); + } + @TestMetadata("receiverEvaluatedOnce.kt") public void testReceiverEvaluatedOnce() throws Exception { runTest("compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index ac053b5169e..f1553a96167 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -10593,11 +10593,21 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt"); } + @TestMetadata("funInterfaceInheritance.kt") + public void testFunInterfaceInheritance() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt"); + } + @TestMetadata("inlinedSamWrapper.kt") public void testInlinedSamWrapper() throws Exception { runTest("compiler/testData/codegen/box/funInterface/inlinedSamWrapper.kt"); } + @TestMetadata("multimodule.kt") + public void testMultimodule() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/multimodule.kt"); + } + @TestMetadata("nullableSam.kt") public void testNullableSam() throws Exception { runTest("compiler/testData/codegen/box/funInterface/nullableSam.kt"); @@ -10608,6 +10618,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/funInterface/partialSam.kt"); } + @TestMetadata("primitiveConversions.kt") + public void testPrimitiveConversions() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/primitiveConversions.kt"); + } + @TestMetadata("receiverEvaluatedOnce.kt") public void testReceiverEvaluatedOnce() throws Exception { runTest("compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 9bce6d3e12f..b3e54740692 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -10593,11 +10593,21 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/funInterface/castFromAny.kt"); } + @TestMetadata("funInterfaceInheritance.kt") + public void testFunInterfaceInheritance() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt"); + } + @TestMetadata("inlinedSamWrapper.kt") public void testInlinedSamWrapper() throws Exception { runTest("compiler/testData/codegen/box/funInterface/inlinedSamWrapper.kt"); } + @TestMetadata("multimodule.kt") + public void testMultimodule() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/multimodule.kt"); + } + @TestMetadata("nullableSam.kt") public void testNullableSam() throws Exception { runTest("compiler/testData/codegen/box/funInterface/nullableSam.kt"); @@ -10608,6 +10618,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/funInterface/partialSam.kt"); } + @TestMetadata("primitiveConversions.kt") + public void testPrimitiveConversions() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/primitiveConversions.kt"); + } + @TestMetadata("receiverEvaluatedOnce.kt") public void testReceiverEvaluatedOnce() throws Exception { runTest("compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.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 ff12559868c..86ac196190a 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 @@ -9073,6 +9073,16 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/funInterface/basicFunInterfaceConversion.kt"); } + @TestMetadata("funInterfaceInheritance.kt") + public void testFunInterfaceInheritance() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt"); + } + + @TestMetadata("multimodule.kt") + public void testMultimodule() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/multimodule.kt"); + } + @TestMetadata("nullableSam.kt") public void testNullableSam() throws Exception { runTest("compiler/testData/codegen/box/funInterface/nullableSam.kt"); @@ -9083,6 +9093,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/funInterface/partialSam.kt"); } + @TestMetadata("primitiveConversions.kt") + public void testPrimitiveConversions() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/primitiveConversions.kt"); + } + @TestMetadata("receiverEvaluatedOnce.kt") public void testReceiverEvaluatedOnce() throws Exception { runTest("compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.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 92967c96df3..88512640383 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 @@ -9073,6 +9073,16 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/funInterface/basicFunInterfaceConversion.kt"); } + @TestMetadata("funInterfaceInheritance.kt") + public void testFunInterfaceInheritance() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/funInterfaceInheritance.kt"); + } + + @TestMetadata("multimodule.kt") + public void testMultimodule() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/multimodule.kt"); + } + @TestMetadata("nullableSam.kt") public void testNullableSam() throws Exception { runTest("compiler/testData/codegen/box/funInterface/nullableSam.kt"); @@ -9083,6 +9093,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/funInterface/partialSam.kt"); } + @TestMetadata("primitiveConversions.kt") + public void testPrimitiveConversions() throws Exception { + runTest("compiler/testData/codegen/box/funInterface/primitiveConversions.kt"); + } + @TestMetadata("receiverEvaluatedOnce.kt") public void testReceiverEvaluatedOnce() throws Exception { runTest("compiler/testData/codegen/box/funInterface/receiverEvaluatedOnce.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java index dd460cf3dd5..036dffbb291 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java @@ -131,6 +131,8 @@ public final class Namer { public static final String IMPORTS_FOR_INLINE_PROPERTY = "$$importsForInline$$"; + public static final String SAM_FIELD_NAME = "function$"; + @NotNull public static String getFunctionTag(@NotNull CallableDescriptor functionDescriptor, @NotNull JsConfig config) { String intrinsicTag = ArrayFIF.INSTANCE.getTag(functionDescriptor, config); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt index 9605017cfa6..579d32e3f15 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt @@ -119,6 +119,8 @@ class ClassTranslator private constructor( enumInitFunction.body.statements += JsAstUtils.asSyntheticStatement(initInvocation.source(companionDescriptor.source.getPsi())) } + maybeConvertInterfaceToSamAdapter(context, constructorFunction) + translatePrimaryConstructor(constructorFunction, context, delegationTranslator) addMetadataObject() addMetadataType() @@ -562,6 +564,42 @@ class ClassTranslator private constructor( } } + private fun maybeConvertInterfaceToSamAdapter(context: TranslationContext, constructorFunction: JsFunction) { + if (!descriptor.isFun) return + + val paramName = context.scope().declareFreshName("f") + constructorFunction.parameters += JsParameter(paramName) + constructorFunction.body.statements += JsBinaryOperation( + JsBinaryOperator.ASG, + pureFqn(Namer.SAM_FIELD_NAME, JsThisRef()), + JsNameRef(paramName) + ).makeStmt() + + val samDescriptor = descriptor.unsubstitutedMemberScope + .getContributedDescriptors(DescriptorKindFilter.FUNCTIONS) + .filterIsInstance() + .single { it.modality === Modality.ABSTRACT } + + val function = context.getFunctionObject(samDescriptor) + val innerContext = context.newDeclaration(samDescriptor).translateAndAliasParameters(samDescriptor, function.parameters) + + if (samDescriptor.isSuspend) { + function.fillCoroutineMetadata(innerContext, samDescriptor, hasController = false) + } + + val parameters = listOfNotNull(samDescriptor.extensionReceiverParameter) + + samDescriptor.valueParameters + + listOfNotNull(innerContext.continuationParameterDescriptor) + + val arguments = parameters.map { + TranslationUtils.coerce(innerContext, innerContext.getAliasForDescriptor(it)!!, context.currentModule.builtIns.anyType) + } + + function.body = JsBlock(JsReturn(JsInvocation(pureFqn(Namer.SAM_FIELD_NAME, JsThisRef()), arguments))) + + context.addDeclarationStatement(context.addFunctionToPrototype(descriptor, samDescriptor, function)) + } + private fun T.withDefaultLocation(): T = apply { source = classDeclaration } companion object { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt index 26430eee842..1578791ec4f 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.kt @@ -66,7 +66,9 @@ fun TranslationContext.translateAndAliasParameters( for (valueParameter in descriptor.valueParameters) { val name = getNameForDescriptor(valueParameter) val tmpName = JsScope.declareTemporaryName(name.ident).also { it.descriptor = valueParameter } - aliases[valueParameter] = JsAstUtils.pureFqn(tmpName, null) + val parameterRef = JsAstUtils.pureFqn(tmpName, null) + parameterRef.type = valueParameter.type + aliases[valueParameter] = parameterRef targetList += JsParameter(tmpName).apply { hasDefaultValue = valueParameter.hasDefaultValue() } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java index 20a3c886e08..9572327ee18 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java @@ -545,6 +545,21 @@ public final class TranslationUtils { } } + // SAM conversion + if ((FunctionTypesKt.isFunctionTypeOrSubtype(from) || FunctionTypesKt.isSuspendFunctionTypeOrSubtype(from))) { + ClassifierDescriptor d = to.getConstructor().getDeclarationDescriptor(); + if (d instanceof ClassDescriptor && ((ClassDescriptor)d).isFun()) { + JsName constructorName = context.getInlineableInnerNameForDescriptor(d.getOriginal()); + if (to.isMarkedNullable()) { + JsConditional c = TranslationUtils.notNullConditional(value, new JsNullLiteral(), context); + c.setThenExpression(new JsNew(new JsNameRef(constructorName), Collections.singletonList(c.getThenExpression()))); + value = c; + } else { + value = new JsNew(new JsNameRef(constructorName), Collections.singletonList(value)); + } + } + } + MetadataProperties.setType(value, to); return value; }