diff --git a/compiler/testData/codegen/box/callableReference/bound/kCallableNameIntrinsic.kt b/compiler/testData/codegen/box/callableReference/bound/kCallableNameIntrinsic.kt index 3dcd0359a85..f03245fd2f5 100644 --- a/compiler/testData/codegen/box/callableReference/bound/kCallableNameIntrinsic.kt +++ b/compiler/testData/codegen/box/callableReference/bound/kCallableNameIntrinsic.kt @@ -1,5 +1,3 @@ -// Enable when callable references to builtin members is supported -// IGNORE_BACKEND: JS fun box(): String { var state = 0 val name = (state++)::toString.name diff --git a/compiler/testData/codegen/box/callableReference/bound/kt12738.kt b/compiler/testData/codegen/box/callableReference/bound/kt12738.kt index 668798431de..4d0e0c85c47 100644 --- a/compiler/testData/codegen/box/callableReference/bound/kt12738.kt +++ b/compiler/testData/codegen/box/callableReference/bound/kt12738.kt @@ -1,5 +1,3 @@ -// Enable when callable references to builtin members is supported -// IGNORE_BACKEND: JS fun get(t: T): () -> String { return t::toString } diff --git a/compiler/testData/codegen/box/callableReference/bound/kt15446.kt b/compiler/testData/codegen/box/callableReference/bound/kt15446.kt index 967150ab7cb..8270b90eb95 100644 --- a/compiler/testData/codegen/box/callableReference/bound/kt15446.kt +++ b/compiler/testData/codegen/box/callableReference/bound/kt15446.kt @@ -1,5 +1,4 @@ //WITH_RUNTIME -// IGNORE_BACKEND: JS fun box(): String { val a = intArrayOf(1, 2) val b = arrayOf("OK") diff --git a/compiler/testData/codegen/box/callableReference/bound/simpleFunction.kt b/compiler/testData/codegen/box/callableReference/bound/simpleFunction.kt index 327c73d5914..15fae151f5f 100644 --- a/compiler/testData/codegen/box/callableReference/bound/simpleFunction.kt +++ b/compiler/testData/codegen/box/callableReference/bound/simpleFunction.kt @@ -1,5 +1,3 @@ -// Enable when callable references to builtin members is supported -// IGNORE_BACKEND: JS fun box(): String { val f = "KOTLIN"::get return "${f(1)}${f(0)}" diff --git a/compiler/testData/codegen/box/callableReference/function/booleanNotIntrinsic.kt b/compiler/testData/codegen/box/callableReference/function/booleanNotIntrinsic.kt index ece7520df91..213c8d88996 100644 --- a/compiler/testData/codegen/box/callableReference/function/booleanNotIntrinsic.kt +++ b/compiler/testData/codegen/box/callableReference/function/booleanNotIntrinsic.kt @@ -1,6 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS - fun box(): String { if ((Boolean::not)(true) != false) return "Fail 1" if ((Boolean::not)(false) != true) return "Fail 2" diff --git a/compiler/testData/codegen/box/callableReference/function/enumValueOfMethod.kt b/compiler/testData/codegen/box/callableReference/function/enumValueOfMethod.kt index 8a7187958d6..21a53adfff3 100644 --- a/compiler/testData/codegen/box/callableReference/function/enumValueOfMethod.kt +++ b/compiler/testData/codegen/box/callableReference/function/enumValueOfMethod.kt @@ -1,6 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS - enum class E { ENTRY } diff --git a/compiler/testData/codegen/box/callableReference/function/equalsIntrinsic.kt b/compiler/testData/codegen/box/callableReference/function/equalsIntrinsic.kt index 0f007abd864..c83a188802d 100644 --- a/compiler/testData/codegen/box/callableReference/function/equalsIntrinsic.kt +++ b/compiler/testData/codegen/box/callableReference/function/equalsIntrinsic.kt @@ -1,6 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS - class A fun box() = if ((A::equals)(A(), A())) "Fail" else "OK" diff --git a/compiler/testData/codegen/box/callableReference/function/local/localFunctionName.kt b/compiler/testData/codegen/box/callableReference/function/local/localFunctionName.kt index f4ad0ac77f9..361ba4c3ce3 100644 --- a/compiler/testData/codegen/box/callableReference/function/local/localFunctionName.kt +++ b/compiler/testData/codegen/box/callableReference/function/local/localFunctionName.kt @@ -1,6 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS - fun box(): String { fun OK() {} diff --git a/compiler/testData/codegen/box/callableReference/function/newArray.kt b/compiler/testData/codegen/box/callableReference/function/newArray.kt index 533e8395616..b27d4e68ac9 100644 --- a/compiler/testData/codegen/box/callableReference/function/newArray.kt +++ b/compiler/testData/codegen/box/callableReference/function/newArray.kt @@ -1,6 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS - private fun upcast(value: T): T = value fun box(): String { diff --git a/compiler/testData/codegen/box/callableReference/property/privateSetterOutsideClass.kt b/compiler/testData/codegen/box/callableReference/property/privateSetterOutsideClass.kt index de11060a95d..3c8b5f8de62 100644 --- a/compiler/testData/codegen/box/callableReference/property/privateSetterOutsideClass.kt +++ b/compiler/testData/codegen/box/callableReference/property/privateSetterOutsideClass.kt @@ -1,6 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS - // See KT-12337 Reference to property with invisible setter should not be a KMutableProperty import kotlin.reflect.KProperty1 diff --git a/compiler/testData/codegen/box/intrinsics/kt10131.kt b/compiler/testData/codegen/box/intrinsics/kt10131.kt index 93723cd3ebe..b388bc4fb62 100644 --- a/compiler/testData/codegen/box/intrinsics/kt10131.kt +++ b/compiler/testData/codegen/box/intrinsics/kt10131.kt @@ -1,6 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS - // WITH_RUNTIME fun box(): String = diff --git a/compiler/testData/codegen/box/intrinsics/kt10131a.kt b/compiler/testData/codegen/box/intrinsics/kt10131a.kt index d6dab66f544..db05fd54b18 100644 --- a/compiler/testData/codegen/box/intrinsics/kt10131a.kt +++ b/compiler/testData/codegen/box/intrinsics/kt10131a.kt @@ -1,6 +1,3 @@ -// TODO: muted automatically, investigate should it be ran for JS or not -// IGNORE_BACKEND: JS - // WITH_RUNTIME fun box(): String = diff --git a/compiler/testData/codegen/boxInline/callableReference/bound/intrinsic.kt b/compiler/testData/codegen/boxInline/callableReference/bound/intrinsic.kt index 4ef94a1c8a3..ab6fb03092d 100644 --- a/compiler/testData/codegen/boxInline/callableReference/bound/intrinsic.kt +++ b/compiler/testData/codegen/boxInline/callableReference/bound/intrinsic.kt @@ -1,5 +1,3 @@ -// Enable when callable references to builtin members is supported -// IGNORE_BACKEND: JS // FILE: 1.kt package test diff --git a/js/js.libraries/src/js/callableReferenceUtils.js b/js/js.libraries/src/js/callableReferenceUtils.js index f87b913c358..2f989620a85 100644 --- a/js/js.libraries/src/js/callableReferenceUtils.js +++ b/js/js.libraries/src/js/callableReferenceUtils.js @@ -14,43 +14,9 @@ * limitations under the License. */ -// TODO Store callable references for members in class -Kotlin.getCallableRefForMemberFunction = function (memberName) { - return function () { - var args = [].slice.call(arguments); - var instance = args.shift(); - return instance[memberName].apply(instance, args); - }; -}; - -Kotlin.getBoundCallableRefForMemberFunction = function (receiver, memberName) { - return function () { - return receiver[memberName].apply(receiver, arguments); - }; -}; - -// TODO Store callable references for extension functions in class -// extFun expected receiver as the first argument -Kotlin.getCallableRefForExtensionFunction = function (extFun) { - return function () { - return extFun.apply(null, arguments); - }; -}; - -Kotlin.getBoundCallableRefForExtensionFunction = function (receiver, extFun) { - return function () { - var args = [].slice.call(arguments); - args.unshift(receiver); - return extFun.apply(null, args); - }; -}; - -Kotlin.getCallableRefForConstructor = function (klass) { - return function () { - var obj = Object.create(klass.prototype); - klass.apply(obj, arguments); - return obj; - }; +Kotlin.getCallableRef = function(name, f) { + f.callableName = name; + return f; }; Kotlin.getCallableRefZeroArg = function(name, getter, setter) { diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/CallableReferenceInlineTestsGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/CallableReferenceInlineTestsGenerated.java index 78960a873e0..2fbfc325226 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/CallableReferenceInlineTestsGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/CallableReferenceInlineTestsGenerated.java @@ -143,13 +143,7 @@ public class CallableReferenceInlineTestsGenerated extends AbstractCallableRefer @TestMetadata("intrinsic.kt") public void testIntrinsic() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/callableReference/bound/intrinsic.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("map.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 254caad43b4..b772edfcf53 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 @@ -1865,37 +1865,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("kCallableNameIntrinsic.kt") public void testKCallableNameIntrinsic() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/kCallableNameIntrinsic.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("kt12738.kt") public void testKt12738() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/kt12738.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("kt15446.kt") public void testKt15446() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/kt15446.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("multiCase.kt") @@ -1925,13 +1907,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("simpleFunction.kt") public void testSimpleFunction() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/simpleFunction.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("simpleProperty.kt") @@ -2036,13 +2012,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("booleanNotIntrinsic.kt") public void testBooleanNotIntrinsic() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/function/booleanNotIntrinsic.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("classMemberFromClass.kt") @@ -2096,25 +2066,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("enumValueOfMethod.kt") public void testEnumValueOfMethod() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/function/enumValueOfMethod.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("equalsIntrinsic.kt") public void testEqualsIntrinsic() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/function/equalsIntrinsic.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("extensionFromClass.kt") @@ -2270,13 +2228,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("newArray.kt") public void testNewArray() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/function/newArray.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("overloadedFun.kt") @@ -2446,13 +2398,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("localFunctionName.kt") public void testLocalFunctionName() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/function/local/localFunctionName.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("localLocal.kt") @@ -9975,25 +9921,13 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("kt10131.kt") public void testKt10131() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/intrinsics/kt10131.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("kt10131a.kt") public void testKt10131a() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/intrinsics/kt10131a.kt"); - try { - doTest(fileName); - } - catch (Throwable ignore) { - return; - } - throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + doTest(fileName); } @TestMetadata("kt12125.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 483179fca4e..77cd8afa24e 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 @@ -75,14 +75,6 @@ public final class Namer { public static final String OUTER_FIELD_NAME = "$outer"; - private static final String CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME = "getCallableRefForMemberFunction"; - private static final String BOUND_CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME = "getBoundCallableRefForMemberFunction"; - private static final String CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME = "getCallableRefForExtensionFunction"; - private static final String BOUND_CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME = "getBoundCallableRefForExtensionFunction"; - private static final String CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME = "getCallableRefForLocalExtensionFunction"; - private static final String BOUND_CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME = "getBoundCallableRefForLocalExtensionFunction"; - private static final String CALLABLE_REF_FOR_CONSTRUCTOR_NAME = "getCallableRefForConstructor"; - private static final String DELEGATE = "$delegate"; private static final String ROOT_PACKAGE = "_"; @@ -198,15 +190,7 @@ public final class Namer { @NotNull private final JsObjectScope kotlinScope; @NotNull - private final JsName callableRefForMemberFunctionName; - @NotNull - private final JsName boundCallableRefForMemberFunctionName; - @NotNull - private final JsName callableRefForExtensionFunctionName; - @NotNull - private final JsName boundCallableRefForExtensionFunctionName; - @NotNull - private final JsName callableRefForConstructorName; + public static final String FUNCTION_CALLABLE_REF = "getCallableRef"; @NotNull public static final String PROPERTY_CALLABLE_REF_ZERO_ARG = "getCallableRefZeroArg"; @NotNull @@ -225,12 +209,6 @@ public final class Namer { callGetProperty = kotlin("callGetter"); callSetProperty = kotlin("callSetter"); - callableRefForMemberFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME); - boundCallableRefForMemberFunctionName = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME); - callableRefForExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME); - boundCallableRefForExtensionFunctionName = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME); - callableRefForConstructorName = kotlinScope.declareName(CALLABLE_REF_FOR_CONSTRUCTOR_NAME); - isTypeName = kotlinScope.declareName("isType"); } @@ -245,31 +223,6 @@ public final class Namer { return suggested.getNames().get(0); } - @NotNull - public JsExpression callableRefForMemberFunctionReference() { - return kotlin(callableRefForMemberFunctionName); - } - - @NotNull - public JsExpression boundCallableRefForMemberFunctionReference() { - return kotlin(boundCallableRefForMemberFunctionName); - } - - @NotNull - public JsExpression callableRefForExtensionFunctionReference() { - return kotlin(callableRefForExtensionFunctionName); - } - - @NotNull - public JsExpression boundCallableRefForExtensionFunctionReference() { - return kotlin(boundCallableRefForExtensionFunctionName); - } - - @NotNull - public JsExpression callableRefForConstructorReference() { - return kotlin(callableRefForConstructorName); - } - @NotNull public static JsExpression throwNPEFunctionRef() { return new JsNameRef(THROW_NPE_FUN_NAME, kotlinObject()); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallableReferenceTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallableReferenceTranslator.kt index 24acb928b0f..328e444479a 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallableReferenceTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallableReferenceTranslator.kt @@ -16,23 +16,30 @@ package org.jetbrains.kotlin.js.translate.reference -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.* +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.js.backend.ast.* -import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.general.Translation -import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.js.translate.utils.BindingUtils -import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils +import org.jetbrains.kotlin.psi.KtCallExpression import org.jetbrains.kotlin.psi.KtCallableReferenceExpression +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.PropertyImportedFromObject +import org.jetbrains.kotlin.resolve.calls.callUtil.getFunctionResolvedCallWithAssert import org.jetbrains.kotlin.resolve.calls.callUtil.getPropertyResolvedCallWithAssert +import org.jetbrains.kotlin.resolve.calls.model.DelegatingResolvedCall +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.util.CallMaker import org.jetbrains.kotlin.types.expressions.DoubleColonLHS object CallableReferenceTranslator { @@ -66,30 +73,56 @@ object CallableReferenceTranslator { } } - private fun reportNotSupported(context: TranslationContext, expression: KtCallableReferenceExpression): JsExpression { - context.bindingTrace().report(ErrorsJs.REFERENCE_TO_BUILTIN_MEMBERS_NOT_SUPPORTED.on(expression, expression)) - return JsLiteral.NULL - } - private fun translateForFunction( descriptor: FunctionDescriptor, context: TranslationContext, expression: KtCallableReferenceExpression, receiver: JsExpression? ): JsExpression { - return when { - // TODO Support for callable reference to builtin functions and members - KotlinBuiltIns.isBuiltIn(descriptor) -> - reportNotSupported(context, expression) - isConstructor(descriptor) -> - translateForConstructor(descriptor, context) - isExtension(descriptor) -> - translateForExtensionFunction(descriptor, context, receiver) - isMember(descriptor) -> - translateForMemberFunction(descriptor, context, receiver) - else -> - ReferenceTranslator.translateAsValueReference(descriptor, context) + val realResolvedCall = expression.callableReference.getFunctionResolvedCallWithAssert(context.bindingContext()) + val fakeExpression = constructFakeFunctionCall(expression.project, descriptor) + + val fakeCall = CallMaker.makeCall(fakeExpression, null, null, fakeExpression, fakeExpression.valueArguments) + val fakeResolvedCall = object : DelegatingResolvedCall(realResolvedCall) { + val valueArgumentList = fakeCall.valueArguments.map(::ExpressionValueArgument) + val valueArgumentMap = valueArgumentList.withIndex().associate { (index, arg) -> descriptor.valueParameters[index] to arg } + + override fun getCall() = fakeCall + + override fun getValueArgumentsByIndex(): List = valueArgumentList + + override fun getValueArguments(): Map = valueArgumentMap } + + val function = JsFunction(context.scope(), JsBlock(), "") + val receiverParam = if (descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null) { + val paramName = function.scope.declareTemporaryName(Namer.getReceiverParameterName()) + function.parameters += JsParameter(paramName) + paramName.makeRef() + } + else { + null + } + + val aliases = mutableMapOf() + for ((index, valueArg) in fakeCall.valueArguments.withIndex()) { + val paramName = function.scope.declareTemporaryName(descriptor.valueParameters[index].name.asString()) + function.parameters += JsParameter(paramName) + aliases[valueArg.getArgumentExpression()!!] = paramName.makeRef() + } + val functionContext = context.innerBlock(function.body).innerContextWithAliasesForExpressions(aliases) + val invocation = CallTranslator.translate(functionContext, fakeResolvedCall, receiverParam) + function.body.statements += JsReturn(invocation) + + val rawCallableRef = bindIfNecessary(function, receiver) + return wrapFunctionCallableRef(context, expression.callableReference.getReferencedName(), rawCallableRef) + } + + private fun constructFakeFunctionCall(project: Project, referencedFunction: FunctionDescriptor): KtCallExpression { + val fakeFunctionCall = StringBuilder("callableReferenceFakeCall(") + fakeFunctionCall.append(referencedFunction.valueParameters.map { "p${it.index}" }.joinToString(", ")) + fakeFunctionCall.append(")") + return KtPsiFactory(project).createExpression(fakeFunctionCall.toString()) as KtCallExpression } private fun translateForProperty( @@ -111,7 +144,7 @@ object CallableReferenceTranslator { null } - return wrapPropertyCallableRef(context, receiver, descriptor, descriptor.name.identifier, getter, setter) + return wrapPropertyCallableRef(context, receiver, descriptor, expression.callableReference.getReferencedName(), getter, setter) } private fun isSetterVisible(descriptor: PropertyDescriptor, context: TranslationContext): Boolean { @@ -151,11 +184,15 @@ object CallableReferenceTranslator { val accessorResult = translator(accessorContext, call, valueParam, receiverParam) accessorFunction.body.statements += if (isSetter) accessorResult.makeStmt() else JsReturn(accessorResult) + return bindIfNecessary(accessorFunction, receiver) + } + + private fun bindIfNecessary(function: JsFunction, receiver: JsExpression?): JsExpression { return if (receiver != null) { - JsInvocation(JsNameRef("bind", accessorFunction), JsLiteral.NULL, receiver) + JsInvocation(JsNameRef("bind", function), JsLiteral.NULL, receiver) } else { - accessorFunction + function } } @@ -181,47 +218,15 @@ object CallableReferenceTranslator { return invocation } - private fun isConstructor(descriptor: CallableDescriptor) = descriptor is ConstructorDescriptor - - private fun isExtension(descriptor: CallableDescriptor) = DescriptorUtils.isExtension(descriptor) - - private fun isMember(descriptor: CallableDescriptor) = JsDescriptorUtils.getContainingDeclaration(descriptor) is ClassDescriptor - - private fun translateForConstructor(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression { - val jsFunctionRef = ReferenceTranslator.translateAsValueReference(descriptor, context) - return JsInvocation(context.namer().callableRefForConstructorReference(), jsFunctionRef) - } - - private fun translateForExtensionFunction(descriptor: FunctionDescriptor, - context: TranslationContext, - receiver: JsExpression? - ): JsExpression { - val jsFunctionRef = ReferenceTranslator.translateAsValueReference(descriptor, context) - if (AnnotationsUtils.isNativeObject(descriptor)) { - return translateForMemberFunction(descriptor, context, receiver) - } - else { - if (receiver == null) { - return JsInvocation(context.namer().callableRefForExtensionFunctionReference(), jsFunctionRef) - } - else { - return JsInvocation(context.namer().boundCallableRefForExtensionFunctionReference(), receiver, jsFunctionRef) - } - } - } - - private fun translateForMemberFunction( - descriptor: CallableDescriptor, + private fun wrapFunctionCallableRef( context: TranslationContext, - receiver: JsExpression? + name: String, + function: JsExpression ): JsExpression { - val funName = context.getNameForDescriptor(descriptor) - val funNameAsString = context.program().getStringLiteral(funName.toString()) - if (receiver == null) { - return JsInvocation(context.namer().callableRefForMemberFunctionReference(), funNameAsString) - } - else { - return JsInvocation(context.namer().boundCallableRefForMemberFunctionReference(), receiver, funNameAsString) - } + val nameLiteral = context.program().getStringLiteral(name) + val invokeName = Namer.FUNCTION_CALLABLE_REF + val invokeFun = JsNameRef(invokeName, Namer.kotlinObject()) + val invocation = JsInvocation(invokeFun, nameLiteral, function) + return invocation } }