From 1b0648a926f7ffbc3b673164d95d6ce47a2cc31f Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Mon, 16 Jan 2017 15:15:57 +0300 Subject: [PATCH] JS: refactor generation of property callable references --- .../kotlin/resolve/calls/util/callUtil.kt | 10 + .../callableReference/bound/simpleProperty.kt | 3 - .../property/listOfStringsMapLength.kt | 3 - .../kotlin/js/naming/NameSuggestion.kt | 17 +- .../js/inline/context/FunctionContext.kt | 4 +- js/js.libraries/src/core/builtins.kt | 2 +- .../src/js/callableReferenceUtils.js | 46 ++-- .../semantics/JsCodegenBoxTestGenerated.java | 24 +-- .../kotlin/js/translate/context/Namer.java | 45 +--- .../translate/context/TranslationContext.java | 5 + .../reference/CallableReferenceTranslator.kt | 200 ++++++++---------- 11 files changed, 138 insertions(+), 221 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt index 2432fd5d459..e0f8534f36b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.callUtil import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.incremental.KotlinLookupLocation import org.jetbrains.kotlin.lexer.KtTokens @@ -200,6 +201,15 @@ fun KtExpression.getFunctionResolvedCallWithAssert(context: BindingContext): Res return resolvedCall as ResolvedCall } +fun KtExpression.getPropertyResolvedCallWithAssert(context: BindingContext): ResolvedCall { + val resolvedCall = getResolvedCallWithAssert(context) + assert(resolvedCall.resultingDescriptor is PropertyDescriptor) { + "ResolvedCall for this expression must be ResolvedCall: ${this.getTextWithLocation()}" + } + @Suppress("UNCHECKED_CAST") + return resolvedCall as ResolvedCall +} + fun KtExpression.getType(context: BindingContext): KotlinType? { val type = context.getType(this) if (type != null) return type diff --git a/compiler/testData/codegen/box/callableReference/bound/simpleProperty.kt b/compiler/testData/codegen/box/callableReference/bound/simpleProperty.kt index 533c75f6bf7..c271b1c6418 100644 --- a/compiler/testData/codegen/box/callableReference/bound/simpleProperty.kt +++ b/compiler/testData/codegen/box/callableReference/bound/simpleProperty.kt @@ -1,6 +1,3 @@ -// Enable when callable references to builtin members are supported. -// IGNORE_BACKEND: JS - fun box(): String { val f = "kotlin"::length val result = f.get() diff --git a/compiler/testData/codegen/box/callableReference/property/listOfStringsMapLength.kt b/compiler/testData/codegen/box/callableReference/property/listOfStringsMapLength.kt index 2ef9208075f..1a035732ad3 100644 --- a/compiler/testData/codegen/box/callableReference/property/listOfStringsMapLength.kt +++ b/compiler/testData/codegen/box/callableReference/property/listOfStringsMapLength.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/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt index 08bc25db4f4..316aab839f6 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.js.naming +import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName @@ -171,10 +172,9 @@ class NameSuggestion { do { parts += getSuggestedName(current) - var last = current + val last = current current = current.containingDeclaration!! if (last is ConstructorDescriptor && !last.isPrimary) { - last = current parts[parts.lastIndex] = getSuggestedName(current) + "_init" current = current.containingDeclaration!! } @@ -232,6 +232,19 @@ class NameSuggestion { "kotlin.CharSequence.get" -> return NameAndStability("charAt", true) "kotlin.Any.equals" -> return NameAndStability("equals", true) } + val container = overriddenDescriptor.containingDeclaration + if (container is ClassDescriptor && ReflectionTypes.isNumberedKPropertyOrKMutablePropertyType(container.defaultType)) { + val name = overriddenDescriptor.name.asString() + when (name) { + "get", + "set" -> return NameAndStability(name, true) + } + } + } + else if (overriddenDescriptor is PropertyDescriptor) { + when (overriddenDescriptor.fqNameUnsafe.asString()) { + "kotlin.reflect.KCallable.name" -> return NameAndStability("callableName", true) + } } return mangleRegularNameIfNecessary(baseName, overriddenDescriptor) diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/FunctionContext.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/FunctionContext.kt index f3e9830c2db..fb6e9b45211 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/FunctionContext.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/context/FunctionContext.kt @@ -91,7 +91,9 @@ abstract class FunctionContext( val qualifier = callQualifier.transitiveStaticRef return when (qualifier) { is JsInvocation -> { - lookUpStaticFunction(getSimpleName(qualifier)!!)?.let { if (isFunctionCreator(it)) it else null } + getSimpleName(qualifier)?.let { simpleName -> + lookUpStaticFunction(simpleName)?.let { if (isFunctionCreator(it)) it else null } + } } is JsNameRef -> lookUpStaticFunction(qualifier.name) is JsFunction -> qualifier diff --git a/js/js.libraries/src/core/builtins.kt b/js/js.libraries/src/core/builtins.kt index 3b80da96653..3ce95f5a593 100644 --- a/js/js.libraries/src/core/builtins.kt +++ b/js/js.libraries/src/core/builtins.kt @@ -33,7 +33,7 @@ internal fun arrayIterator(array: dynamic): MutableIterator { } @JsName("PropertyMetadata") -internal class PropertyMetadata(val name: String) +internal class PropertyMetadata(@JsName("callableName") val name: String) @JsName("noWhenBranchMatched") internal fun noWhenBranchMatched(): Nothing = throw NoWhenBranchMatchedException() \ No newline at end of file diff --git a/js/js.libraries/src/js/callableReferenceUtils.js b/js/js.libraries/src/js/callableReferenceUtils.js index 3e7fa007089..f87b913c358 100644 --- a/js/js.libraries/src/js/callableReferenceUtils.js +++ b/js/js.libraries/src/js/callableReferenceUtils.js @@ -53,44 +53,22 @@ Kotlin.getCallableRefForConstructor = function (klass) { }; }; -Kotlin.getCallableRefForTopLevelProperty = function(getter, setter, name) { - var getFun = Function("getter", "return function " + name + "() { return getter(); }")(getter, setter); - return getPropertyRefClass(getFun, "get", setter, "set_za3rmp$", propertyRefClassMetadataCache.zeroArg); +Kotlin.getCallableRefZeroArg = function(name, getter, setter) { + getter.get = getter; + getter.set = setter; + getter.callableName = name; + return getPropertyRefClass(getter, setter, propertyRefClassMetadataCache.zeroArg); }; -Kotlin.getCallableRefForMemberProperty = function(name, isVar) { - var getFun = Function("return function " + name + "(receiver) { return receiver['" + name + "']; }")(); - var setFun = isVar ? function(receiver, value) { receiver[name] = value; } : null; - return getPropertyRefClass(getFun, "get_za3rmp$", setFun, "set_wn2jw4$", propertyRefClassMetadataCache.oneArg); +Kotlin.getCallableRefOneArg = function(name, getter, setter) { + getter.get = getter; + getter.set = setter; + getter.callableName = name; + return getPropertyRefClass(getter, setter, propertyRefClassMetadataCache.oneArg); }; -Kotlin.getBoundCallableRefForMemberProperty = function(receiver, name, isVar) { - var getFun = Function("receiver", "return function " + name + "() { return receiver['" + name + "']; }")(receiver); - var setFun = isVar ? function(value) { receiver[name] = value; } : null; - return getPropertyRefClass(getFun, "get", setFun, "set_za3rmp$", propertyRefClassMetadataCache.oneArg); -}; - -Kotlin.getCallableRefForExtensionProperty = function(name, getFun, setFun) { - var getFunWrapper = Function("getFun", "return function " + name + "(receiver, extensionReceiver) { return getFun(receiver, extensionReceiver) }")(getFun); - return getPropertyRefClass(getFunWrapper, "get_za3rmp$", setFun, "set_wn2jw4$", propertyRefClassMetadataCache.oneArg); -}; - -Kotlin.getBoundCallableRefForExtensionProperty = function(receiver, name, getFun, setFun) { - var getFunWrapper = Function("receiver", "getFun", "return function " + name + "(extensionReceiver) { return getFun(receiver, extensionReceiver) }")(receiver, getFun); - if (setFun) { - setFun = setFun.bind(null, receiver); - } - return getPropertyRefClass(getFunWrapper, "get", setFun, "set_za3rmp$", propertyRefClassMetadataCache.oneArg); -}; - -function getPropertyRefClass(getFun, getName, setFun, setName, cache) { - var obj = getFun; - var isMutable = typeof setFun === "function"; - obj.$metadata$ = getPropertyRefMetadata(isMutable ? cache.mutable : cache.immutable); - obj[getName] = getFun; - if (isMutable) { - obj[setName] = setFun; - } +function getPropertyRefClass(obj, setter, cache) { + obj.$metadata$ = getPropertyRefMetadata(typeof setter === "function" ? cache.mutable : cache.immutable); obj.constructor = obj; return obj; } 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 891f30a2181..254caad43b4 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 @@ -1937,13 +1937,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("simpleProperty.kt") public void testSimpleProperty() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/bound/simpleProperty.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("compiler/testData/codegen/box/callableReference/bound/equals") @@ -2606,13 +2600,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("listOfStringsMapLength.kt") public void testListOfStringsMapLength() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/property/listOfStringsMapLength.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("localClassVar.kt") @@ -2636,13 +2624,7 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { @TestMetadata("privateSetterOutsideClass.kt") public void testPrivateSetterOutsideClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/callableReference/property/privateSetterOutsideClass.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("simpleExtension.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 11a5195e90c..483179fca4e 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 @@ -82,11 +82,6 @@ public final class Namer { 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 CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY = "getCallableRefForTopLevelProperty"; - private static final String CALLABLE_REF_FOR_MEMBER_PROPERTY = "getCallableRefForMemberProperty"; - private static final String BOUND_CALLABLE_REF_FOR_MEMBER_PROPERTY = "getBoundCallableRefForMemberProperty"; - private static final String CALLABLE_REF_FOR_EXTENSION_PROPERTY = "getCallableRefForExtensionProperty"; - private static final String BOUND_CALLABLE_REF_FOR_EXTENSION_PROPERTY = "getBoundCallableRefForExtensionProperty"; private static final String DELEGATE = "$delegate"; @@ -213,15 +208,9 @@ public final class Namer { @NotNull private final JsName callableRefForConstructorName; @NotNull - private final JsName callableRefForTopLevelProperty; + public static final String PROPERTY_CALLABLE_REF_ZERO_ARG = "getCallableRefZeroArg"; @NotNull - private final JsName callableRefForMemberProperty; - @NotNull - private final JsName boundCallableRefForMemberProperty; - @NotNull - private final JsName callableRefForExtensionProperty; - @NotNull - private final JsName boundCallableRefForExtensionProperty; + public static final String PROPERTY_CALLABLE_REF_ONE_ARG = "getCallableRefOneArg"; @NotNull private final JsExpression callGetProperty; @NotNull @@ -241,11 +230,6 @@ public final class Namer { 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); - callableRefForTopLevelProperty = kotlinScope.declareName(CALLABLE_REF_FOR_TOP_LEVEL_PROPERTY); - callableRefForMemberProperty = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_PROPERTY); - boundCallableRefForMemberProperty = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_MEMBER_PROPERTY); - callableRefForExtensionProperty = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_PROPERTY); - boundCallableRefForExtensionProperty = kotlinScope.declareName(BOUND_CALLABLE_REF_FOR_EXTENSION_PROPERTY); isTypeName = kotlinScope.declareName("isType"); } @@ -286,31 +270,6 @@ public final class Namer { return kotlin(callableRefForConstructorName); } - @NotNull - public JsExpression callableRefForTopLevelPropertyReference() { - return kotlin(callableRefForTopLevelProperty); - } - - @NotNull - public JsExpression callableRefForMemberPropertyReference() { - return kotlin(callableRefForMemberProperty); - } - - @NotNull - public JsExpression boundCallableRefForMemberPropertyReference() { - return kotlin(boundCallableRefForMemberProperty); - } - - @NotNull - public JsExpression callableRefForExtensionPropertyReference() { - return kotlin(callableRefForExtensionProperty); - } - - @NotNull - public JsExpression boundCallableRefForExtensionPropertyReference() { - return kotlin(boundCallableRefForExtensionProperty); - } - @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/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java index 2780d9beac9..5a542da9ef6 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java @@ -227,6 +227,11 @@ public class TranslationContext { } } + @Nullable + public ClassDescriptor getClassDescriptor() { + return classDescriptor; + } + @NotNull public BindingContext bindingContext() { return staticContext.getBindingContext(); 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 35ece57cddb..24acb928b0f 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 @@ -20,15 +20,20 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* 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.* +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.KtCallableReferenceExpression 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.getPropertyResolvedCallWithAssert +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.types.expressions.DoubleColonLHS -import java.util.* object CallableReferenceTranslator { @@ -93,17 +98,87 @@ object CallableReferenceTranslator { expression: KtCallableReferenceExpression, receiver: JsExpression? ): JsExpression { - return when { - // TODO Support for callable reference to builtin properties - KotlinBuiltIns.isBuiltIn(descriptor) -> - reportNotSupported(context, expression) - isExtension(descriptor) -> - translateForExtensionProperty(descriptor, context, receiver) - isMember(descriptor) -> - translateForMemberProperty(descriptor, context, receiver) - else -> - translateForTopLevelProperty(descriptor, context) + val call = expression.callableReference.getPropertyResolvedCallWithAssert(context.bindingContext()) + + val getter = translateForPropertyAccessor(call, descriptor, context, receiver, false) { context, call, _, receiverParam -> + CallTranslator.translateGet(context, call, receiverParam) } + + val setter = if (isSetterVisible(descriptor, context)) { + translateForPropertyAccessor(call, descriptor, context, receiver, true, CallTranslator::translateSet) + } + else { + null + } + + return wrapPropertyCallableRef(context, receiver, descriptor, descriptor.name.identifier, getter, setter) + } + + private fun isSetterVisible(descriptor: PropertyDescriptor, context: TranslationContext): Boolean { + val setter = descriptor.setter ?: return false + if (setter.visibility != Visibilities.PRIVATE) return true + val classDescriptor = context.classDescriptor ?: return false + return classDescriptor == descriptor.containingDeclaration + } + + private fun translateForPropertyAccessor( + call: ResolvedCall, + descriptor: PropertyDescriptor, + context: TranslationContext, + receiver: JsExpression?, + isSetter: Boolean, + translator: (TranslationContext, ResolvedCall, JsExpression, JsExpression?) -> JsExpression + ): JsExpression { + val accessorFunction = JsFunction(context.scope(), JsBlock(), "") + val accessorContext = context.innerBlock(accessorFunction.body) + val receiverParam = if (descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null) { + val name = accessorFunction.scope.declareTemporaryName(Namer.getReceiverParameterName()) + accessorFunction.parameters += JsParameter(name) + name.makeRef() + } + else { + null + } + + val valueParam = if (isSetter) { + val name = accessorFunction.scope.declareTemporaryName("value") + accessorFunction.parameters += JsParameter(name) + name.makeRef() + } + else { + JsLiteral.NULL + } + + val accessorResult = translator(accessorContext, call, valueParam, receiverParam) + accessorFunction.body.statements += if (isSetter) accessorResult.makeStmt() else JsReturn(accessorResult) + return if (receiver != null) { + JsInvocation(JsNameRef("bind", accessorFunction), JsLiteral.NULL, receiver) + } + else { + accessorFunction + } + } + + private fun wrapPropertyCallableRef( + context: TranslationContext, + receiver: JsExpression?, + descriptor: PropertyDescriptor, + name: String, + getter: JsExpression, + setter: JsExpression? + ): JsExpression { + var argCount = if (descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null) 1 else 0 + if (receiver != null) { + argCount-- + } + val nameLiteral = context.program().getStringLiteral(name) + val invokeName = if (argCount == 0) Namer.PROPERTY_CALLABLE_REF_ZERO_ARG else Namer.PROPERTY_CALLABLE_REF_ONE_ARG + val invokeFun = JsNameRef(invokeName, Namer.kotlinObject()) + val invocation = JsInvocation(invokeFun, nameLiteral, getter) + if (setter != null) { + invocation.arguments += setter + } + return invocation } private fun isConstructor(descriptor: CallableDescriptor) = descriptor is ConstructorDescriptor @@ -112,107 +187,6 @@ object CallableReferenceTranslator { private fun isMember(descriptor: CallableDescriptor) = JsDescriptorUtils.getContainingDeclaration(descriptor) is ClassDescriptor - private fun isVar(descriptor: PropertyDescriptor) = if (descriptor.isVar) JsLiteral.TRUE else JsLiteral.FALSE - - private fun translateForTopLevelProperty(descriptor: PropertyDescriptor, context: TranslationContext): JsExpression { - val packageDescriptor = JsDescriptorUtils.getContainingDeclaration(descriptor) - assert(packageDescriptor is PackageFragmentDescriptor) { "Expected PackageFragmentDescriptor: $packageDescriptor" } - - val jsPropertyName = context.getNameForDescriptor(descriptor) - val jsPropertyNameAsString = context.program().getStringLiteral(jsPropertyName.toString()) - - val getter = createTopLevelGetterFunction(descriptor, context) - val setter = if (descriptor.isVar) createTopLevelSetterFunction(descriptor, context) else JsLiteral.NULL - - return JsInvocation(context.namer().callableRefForTopLevelPropertyReference(), getter, setter, jsPropertyNameAsString) - } - - private fun createTopLevelGetterFunction(descriptor: PropertyDescriptor, context: TranslationContext): JsExpression { - val getter = descriptor.getter!! - if (!JsDescriptorUtils.isSimpleFinalProperty(descriptor) && context.isFromCurrentModule(descriptor)) { - return context.getInnerReference(getter) - } - - val expression = if (TranslationUtils.shouldAccessViaFunctions(descriptor)) { - JsInvocation(ReferenceTranslator.translateAsValueReference(getter, context)) - } - else { - ReferenceTranslator.translateAsValueReference(descriptor, context) - } - - val function = context.createRootScopedFunction(getter) - function.body.statements += JsReturn(expression) - - return function - } - - private fun createTopLevelSetterFunction(descriptor: PropertyDescriptor, context: TranslationContext): JsExpression { - val setter = descriptor.setter!! - if (!JsDescriptorUtils.isSimpleFinalProperty(descriptor) && context.isFromCurrentModule(descriptor)) { - return context.getInnerReference(setter) - } - - val function = context.createRootScopedFunction(setter) - val valueParam = function.scope.declareTemporaryName("value") - function.parameters += JsParameter(valueParam) - - val expression = if (TranslationUtils.shouldAccessViaFunctions(descriptor)) { - JsInvocation(ReferenceTranslator.translateAsValueReference(setter, context), valueParam.makeRef()) - } - else { - JsAstUtils.assignment(ReferenceTranslator.translateAsValueReference(descriptor, context), valueParam.makeRef()) - } - - function.body.statements += expression.makeStmt() - - return function - } - - private fun translateForMemberProperty( - descriptor: PropertyDescriptor, - context: TranslationContext, - receiver: JsExpression? - ): JsExpression { - val jsPropertyName = context.getNameForDescriptor(descriptor) - val jsPropertyNameAsString = context.program().getStringLiteral(jsPropertyName.toString()) - if (receiver == null) { - return JsInvocation(context.namer().callableRefForMemberPropertyReference(), jsPropertyNameAsString, isVar(descriptor)) - } - else { - return JsInvocation(context.namer().boundCallableRefForMemberPropertyReference(), receiver, jsPropertyNameAsString, - isVar(descriptor)) - } - } - - private fun translateForExtensionProperty( - descriptor: PropertyDescriptor, - context: TranslationContext, - receiver: JsExpression? - ): JsExpression { - val jsGetterNameRef = ReferenceTranslator.translateAsValueReference(descriptor.getter!!, context) - val propertyName = descriptor.name - val jsPropertyNameAsString = context.program().getStringLiteral(propertyName.asString()) - val argumentList = ArrayList(4) - if (receiver != null) { - argumentList.add(receiver) - } - argumentList.add(jsPropertyNameAsString) - argumentList.add(jsGetterNameRef) - if (descriptor.isVar) { - val jsSetterNameRef = ReferenceTranslator.translateAsValueReference(descriptor.setter!!, context) - argumentList.add(jsSetterNameRef) - } - return if (AnnotationsUtils.isNativeObject(descriptor)) { - translateForMemberProperty(descriptor, context, receiver) - } - else if (receiver == null) { - JsInvocation(context.namer().callableRefForExtensionPropertyReference(), argumentList) - } - else { - JsInvocation(context.namer().boundCallableRefForExtensionPropertyReference(), argumentList) - } - } - private fun translateForConstructor(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression { val jsFunctionRef = ReferenceTranslator.translateAsValueReference(descriptor, context) return JsInvocation(context.namer().callableRefForConstructorReference(), jsFunctionRef)