JS: introduce new flat JS declaration structure

This commit is contained in:
Alexey Andreev
2016-10-03 17:37:58 +03:00
parent f1ae9949fe
commit f9a392fdec
42 changed files with 1428 additions and 933 deletions
@@ -132,8 +132,7 @@ public abstract class JsScope {
return names.containsKey(name);
}
@Nullable
public boolean hasName(@NotNull String name) {
private boolean hasName(@NotNull String name) {
return hasOwnName(name) || (parent != null && parent.hasName(name));
}
@@ -20,7 +20,9 @@ import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addToStdlib.check
@@ -3269,6 +3269,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/extensionProperty"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("inClass.kt")
public void testInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/extensionProperty/inClass.kt");
doTest(fileName);
}
@TestMetadata("propertyWithGetterAndSetter.kt")
public void testPropertyWithGetterAndSetter() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/extensionProperty/propertyWithGetterAndSetter.kt");
@@ -3385,6 +3391,39 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inheritance/withInitializeMethod.kt");
doTest(fileName);
}
@TestMetadata("js/js.translator/testData/box/inheritance/interfaces")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Interfaces extends AbstractBoxJsTest {
@TestMetadata("abstractClassInheritingDefaultMethod.kt")
public void testAbstractClassInheritingDefaultMethod() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inheritance/interfaces/abstractClassInheritingDefaultMethod.kt");
doTest(fileName);
}
public void testAllFilesPresentInInterfaces() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/inheritance/interfaces"), Pattern.compile("^([^_](.+))\\.kt$"), true);
}
@TestMetadata("withDefaultMethod.kt")
public void testWithDefaultMethod() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inheritance/interfaces/withDefaultMethod.kt");
doTest(fileName);
}
@TestMetadata("withDefaultMethodFromSuperInterface.kt")
public void testWithDefaultMethodFromSuperInterface() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inheritance/interfaces/withDefaultMethodFromSuperInterface.kt");
doTest(fileName);
}
@TestMetadata("withDefaultProperty.kt")
public void testWithDefaultProperty() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/inheritance/interfaces/withDefaultProperty.kt");
doTest(fileName);
}
}
}
@TestMetadata("js/js.translator/testData/box/initialize")
@@ -21,10 +21,7 @@ import com.google.dart.compiler.backend.js.ast.JsName
import com.google.dart.compiler.backend.js.ast.metadata.HasMetadata
import com.google.dart.compiler.backend.js.ast.metadata.SideEffectKind
import com.google.dart.compiler.backend.js.ast.metadata.sideEffects
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
@@ -42,8 +39,6 @@ val CallInfo.callableDescriptor: CallableDescriptor
return if (result is TypeAliasConstructorDescriptor) result.underlyingConstructorDescriptor else result
}
fun CallInfo.isExtension(): Boolean = extensionReceiver != null
fun CallInfo.isNative(): Boolean = AnnotationsUtils.isNativeObject(callableDescriptor)
fun CallInfo.isSuperInvocation(): Boolean {
@@ -65,11 +60,16 @@ val VariableAccessInfo.variableName: JsName
fun VariableAccessInfo.isGetAccess(): Boolean = value == null
fun VariableAccessInfo.getAccessDescriptor(): DeclarationDescriptor {
val descriptor = variableDescriptor
if (descriptor is PropertyDescriptor && (descriptor.isExtension || TranslationUtils.shouldGenerateAccessors(descriptor))) {
val propertyAccessorDescriptor = if (isGetAccess()) descriptor.getter else descriptor.setter
return propertyAccessorDescriptor!!
fun VariableAccessInfo.getAccessDescriptor(): PropertyAccessorDescriptor {
val property = variableDescriptor as PropertyDescriptor
return if (isGetAccess()) property.getter!! else property.setter!!
}
fun VariableAccessInfo.getAccessDescriptorIfNeeded(): CallableDescriptor {
if (variableDescriptor is PropertyDescriptor &&
(variableDescriptor.isExtension || TranslationUtils.shouldAccessViaFunctions(variableDescriptor))
) {
return getAccessDescriptor()
}
else {
return variableDescriptor
@@ -70,9 +70,11 @@ object CallTranslator {
val isNative = AnnotationsUtils.isNativeObject(functionDescriptor)
val hasSpreadOperator = false
if (dispatchReceiver != null) {
return DefaultFunctionCallCase.buildDefaultCallWithDispatchReceiver(argumentsInfo, dispatchReceiver, functionName, isNative, hasSpreadOperator)
return DefaultFunctionCallCase.buildDefaultCallWithDispatchReceiver(argumentsInfo, dispatchReceiver, functionName, isNative,
hasSpreadOperator)
} else {
return DefaultFunctionCallCase.buildDefaultCallWithoutReceiver(context, argumentsInfo, functionDescriptor, isNative, hasSpreadOperator)
return DefaultFunctionCallCase.buildDefaultCallWithoutReceiver(context, argumentsInfo, functionDescriptor, isNative,
hasSpreadOperator)
}
}
}
@@ -19,15 +19,13 @@ package org.jetbrains.kotlin.js.translate.callTranslator
import com.google.dart.compiler.backend.js.ast.*
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.js.PredefinedAnnotation
import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.operation.OperatorTable
import org.jetbrains.kotlin.js.translate.reference.CallArgumentTranslator
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
@@ -83,7 +81,7 @@ object DefaultFunctionCallCase : FunctionCallCase() {
return JsInvocation(JsNameRef(context.getNameForDescriptor(callableDescriptor)), argumentsInfo.translateArguments)
}
val functionRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(it) }
val functionRef = ReferenceTranslator.translateAsFQReference(callableDescriptor, context)
return JsInvocation(functionRef, argumentsInfo.translateArguments)
}
@@ -103,7 +101,7 @@ object DefaultFunctionCallCase : FunctionCallCase() {
return JsInvocation(JsNameRef(functionName, extensionReceiver), argumentsInfo.translateArguments)
}
val functionRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(it) }
val functionRef = ReferenceTranslator.translateAsFQReference(callableDescriptor, context)
val referenceToCall =
if (callableDescriptor.visibility == Visibilities.LOCAL) {
@@ -214,9 +212,7 @@ object ConstructorCallCase : FunctionCallCase() {
private inline fun FunctionCallInfo.doTranslate(
getArguments: CallArgumentTranslator.ArgumentsInfo.() -> List<JsExpression>
): JsExpression {
val fqName = context.getQualifiedReference(callableDescriptor)
val functionRef = if (isNative()) fqName else context.aliasOrValue(callableDescriptor) { fqName }
val functionRef = ReferenceTranslator.translateAsFQReference(callableDescriptor, context)
val invocationArguments = mutableListOf<JsExpression>()
val constructorDescriptor = callableDescriptor as ClassConstructorDescriptor
@@ -245,7 +241,7 @@ object SuperCallCase : FunctionCallCase() {
override fun FunctionCallInfo.dispatchReceiver(): JsExpression {
// TODO: spread operator
val prototypeClass = pureFqn(Namer.getPrototypeName(), calleeOwner)
val prototypeClass = JsAstUtils.prototypeOf(calleeOwner)
val functionRef = Namer.getFunctionCallRef(JsNameRef(functionName, prototypeClass))
return JsInvocation(functionRef, argumentsInfo.argsWithReceiver(dispatchReceiver!!))
}
@@ -26,13 +26,14 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.Namer.getCapturedVarAccessor
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
import org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
import java.util.*
object NativeVariableAccessCase : VariableAccessCase() {
override fun VariableAccessInfo.extensionReceiver(): JsExpression {
return constructAccessExpression(JsNameRef(variableName, extensionReceiver!!))
@@ -40,8 +41,8 @@ object NativeVariableAccessCase : VariableAccessCase() {
override fun VariableAccessInfo.dispatchReceiver(): JsExpression {
val descriptor = resolvedCall.resultingDescriptor
return if (descriptor is PropertyDescriptor && TranslationUtils.shouldGenerateAccessors(descriptor)) {
val methodRef = context.getNameForDescriptor(getAccessDescriptor())
return if (descriptor is PropertyDescriptor && TranslationUtils.shouldAccessViaFunctions(descriptor)) {
val methodRef = context.getNameForDescriptor(getAccessDescriptorIfNeeded())
JsInvocation(pureFqn(methodRef, dispatchReceiver!!), *additionalArguments.toTypedArray())
}
else {
@@ -51,8 +52,8 @@ object NativeVariableAccessCase : VariableAccessCase() {
override fun VariableAccessInfo.noReceivers(): JsExpression {
val descriptor = resolvedCall.resultingDescriptor
return if (descriptor is PropertyDescriptor && TranslationUtils.shouldGenerateAccessors(descriptor)) {
val methodRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(getAccessDescriptor()) }
return if (descriptor is PropertyDescriptor && TranslationUtils.shouldAccessViaFunctions(descriptor)) {
val methodRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(getAccessDescriptorIfNeeded()) }
JsInvocation(methodRef, *additionalArguments.toTypedArray())
}
else {
@@ -63,32 +64,49 @@ object NativeVariableAccessCase : VariableAccessCase() {
object DefaultVariableAccessCase : VariableAccessCase() {
override fun VariableAccessInfo.noReceivers(): JsExpression {
val descriptor = resolvedCall.resultingDescriptor
if (descriptor is PropertyDescriptor && TranslationUtils.shouldGenerateAccessors(descriptor)) {
val methodRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(getAccessDescriptor()) }
val variableDescriptor = this.variableDescriptor
if (variableDescriptor is PropertyDescriptor &&
!JsDescriptorUtils.isSimpleFinalProperty(variableDescriptor) &&
context.isFromCurrentModule(variableDescriptor)
) {
val methodRef = context.getInnerReference(getAccessDescriptor())
return JsInvocation(methodRef, *additionalArguments.toTypedArray())
}
val functionRef = context.aliasOrValue(callableDescriptor) {
context.getQualifiedReference(variableDescriptor)
val descriptor = resolvedCall.resultingDescriptor
if (descriptor is PropertyDescriptor && TranslationUtils.shouldAccessViaFunctions(descriptor)) {
val methodRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(getAccessDescriptorIfNeeded()) }
return JsInvocation(methodRef, *additionalArguments.toTypedArray())
}
val ref =
if (isVarCapturedInClosure(context.bindingContext(), callableDescriptor)) {
getCapturedVarAccessor(functionRef)
} else {
functionRef
}
if (descriptor is FakeCallableDescriptorForObject) {
return JsInvocation(pureFqn(context.getNameForObjectInstance (descriptor.getReferencedObject()), null))
}
val functionRef = context.aliasOrValue(callableDescriptor) {
if (context.isFromCurrentModule(variableDescriptor)) {
context.getInnerReference(variableDescriptor)
}
else {
val qualifier = context.getInnerReference(variableDescriptor.containingDeclaration)
val name = context.getNameForDescriptor(variableDescriptor)
JsNameRef(name, qualifier)
}
}
val ref = if (isVarCapturedInClosure(context.bindingContext(), callableDescriptor)) {
getCapturedVarAccessor(functionRef)
}
else {
functionRef
}
val localVariableDescriptor = resolvedCall.resultingDescriptor as? LocalVariableDescriptor
val accessorDescriptor = if (isGetAccess()) localVariableDescriptor?.getter else localVariableDescriptor?.setter
if (accessorDescriptor != null) {
val funRef = JsNameRef(TranslationUtils.getAccessorFunctionName(accessorDescriptor), ref)
return if (isGetAccess()) {
JsInvocation(funRef)
} else {
JsInvocation(funRef, value!!)
}
return JsInvocation(funRef, *additionalArguments.toTypedArray())
}
return constructAccessExpression(ref)
@@ -96,8 +114,8 @@ object DefaultVariableAccessCase : VariableAccessCase() {
override fun VariableAccessInfo.dispatchReceiver(): JsExpression {
val descriptor = resolvedCall.resultingDescriptor
return if (descriptor is PropertyDescriptor && TranslationUtils.shouldGenerateAccessors(descriptor)) {
val callExpr = pureFqn(context.getNameForDescriptor(getAccessDescriptor()), dispatchReceiver!!)
return if (descriptor is PropertyDescriptor && TranslationUtils.shouldAccessViaFunctions(descriptor)) {
val callExpr = pureFqn(context.getNameForDescriptor(getAccessDescriptorIfNeeded()), dispatchReceiver!!)
JsInvocation(callExpr, *additionalArguments.toTypedArray())
}
else {
@@ -110,12 +128,12 @@ object DefaultVariableAccessCase : VariableAccessCase() {
}
override fun VariableAccessInfo.extensionReceiver(): JsExpression {
val functionRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(getAccessDescriptor()) }
val functionRef = context.aliasOrValue(callableDescriptor) { context.getQualifiedReference(getAccessDescriptorIfNeeded()) }
return JsInvocation(functionRef, extensionReceiver!!, *additionalArguments.toTypedArray())
}
override fun VariableAccessInfo.bothReceivers(): JsExpression {
val funRef = JsNameRef(context.getNameForDescriptor(getAccessDescriptor()), dispatchReceiver!!)
val funRef = JsNameRef(context.getNameForDescriptor(getAccessDescriptorIfNeeded()), dispatchReceiver!!)
return JsInvocation(funRef, extensionReceiver!!, *additionalArguments.toTypedArray())
}
}
@@ -150,16 +168,16 @@ object SuperPropertyAccessCase : VariableAccessCase() {
val variableName = context.program().getStringLiteral(this.variableName.ident)
val descriptor = resolvedCall.resultingDescriptor
return if (descriptor is PropertyDescriptor && TranslationUtils.shouldGenerateAccessors(descriptor)) {
val accessor = getAccessDescriptor()
val prototype = pureFqn(Namer.getPrototypeName(), context.getQualifiedReference(descriptor.containingDeclaration))
return if (descriptor is PropertyDescriptor && TranslationUtils.shouldAccessViaFunctions(descriptor)) {
val accessor = getAccessDescriptorIfNeeded()
val prototype = pureFqn(Namer.getPrototypeName(), context.getInnerReference(descriptor.containingDeclaration))
val funRef = Namer.getFunctionCallRef(pureFqn(context.getNameForDescriptor(accessor), prototype))
val arguments = listOf(dispatchReceiver!!) + additionalArguments
JsInvocation(funRef, *arguments.toTypedArray())
}
else {
val callExpr = if (isGetAccess()) context.namer().callGetProperty else context.namer().callSetProperty
val arguments = listOf(dispatchReceiver!!, calleeOwner, variableName) + additionalArguments
val arguments = listOf(dispatchReceiver!!, JsAstUtils.prototypeOf(calleeOwner), variableName) + additionalArguments
JsInvocation(callExpr, *arguments.toTypedArray())
}
}
@@ -1,39 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.translate.context
import com.google.dart.compiler.backend.js.ast.*
import com.google.dart.compiler.backend.js.ast.metadata.staticRef
class DefinitionPlace(
private val scope: JsObjectScope,
private val fqName: JsExpression,
val properties: MutableList<JsPropertyInitializer>
) {
fun define(suggestedName: String, expression : JsExpression) = define(scope.declareFreshName(suggestedName), expression)
fun define(name: JsName, expression: JsExpression): JsNameRef {
if (expression is JsFunction) {
/** JsInliner should be able
* to find function by name */
name.staticRef = expression
}
properties.add(JsPropertyInitializer(name.makeRef(), expression))
return JsNameRef(name, fqName)
}
}
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.js.naming.NameSuggestion;
import org.jetbrains.kotlin.js.naming.SuggestedName;
import org.jetbrains.kotlin.js.resolve.JsPlatform;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.FqNameUnsafe;
import org.jetbrains.kotlin.name.Name;
@@ -77,10 +78,6 @@ public final class Namer {
public static final String OUTER_FIELD_NAME = "$outer";
private static final String CLASS_OBJECT_NAME = "createClass";
private static final String ENUM_CLASS_OBJECT_NAME = "createEnumClass";
private static final String TRAIT_OBJECT_NAME = "createTrait";
private static final String OBJECT_OBJECT_NAME = "createObject";
private static final String CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME = "getCallableRefForMemberFunction";
private static final String CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME = "getCallableRefForExtensionFunction";
private static final String CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME = "getCallableRefForLocalExtensionFunction";
@@ -89,13 +86,8 @@ public final class Namer {
private static final String CALLABLE_REF_FOR_MEMBER_PROPERTY = "getCallableRefForMemberProperty";
private static final String CALLABLE_REF_FOR_EXTENSION_PROPERTY = "getCallableRefForExtensionProperty";
private static final String SETTER_PREFIX = "set_";
private static final String GETTER_PREFIX = "get_";
private static final String BACKING_FIELD_PREFIX = "$";
private static final String DELEGATE = "$delegate";
private static final String SUPER_METHOD_NAME = "baseInitializer";
private static final String ROOT_PACKAGE = "_";
private static final String RECEIVER_PARAMETER_NAME = "$receiver";
@@ -113,6 +105,14 @@ public final class Namer {
private static final JsNameRef JS_OBJECT_CREATE_FUNCTION = new JsNameRef("create", JS_OBJECT);
public static final String LOCAL_MODULE_PREFIX = "$module$";
public static final String METADATA = "$metadata$";
public static final String METADATA_SUPERTYPES = "baseClasses";
public static final String OBJECT_INSTANCE_VAR_SUFFIX = "_instance";
public static final String OBJECT_INSTANCE_FUNCTION_SUFFIX = "_getInstance";
public static final String ENUM_NAME_FIELD = "name$";
public static final String ENUM_ORDINAL_FIELD = "ordinal$";
public static boolean isUndefined(@NotNull JsExpression expr) {
if (expr instanceof JsPrefixOperation) {
@@ -148,50 +148,11 @@ public final class Namer {
return ROOT_PACKAGE;
}
@NotNull
public static JsNameRef superMethodNameRef(@NotNull JsName superClassJsName) {
return pureFqn(SUPER_METHOD_NAME, superClassJsName.makeRef());
}
@NotNull
public static String getNameForAccessor(@NotNull String propertyName, boolean isGetter, boolean useNativeAccessor) {
if (useNativeAccessor) {
return propertyName;
}
if (isGetter) {
return getNameForGetter(propertyName);
}
else {
return getNameForSetter(propertyName);
}
}
@NotNull
public static String getKotlinBackingFieldName(@NotNull String propertyName) {
return getNameWithPrefix(propertyName, BACKING_FIELD_PREFIX);
}
@NotNull
private static String getNameForGetter(@NotNull String propertyName) {
return getNameWithPrefix(propertyName, GETTER_PREFIX);
}
@NotNull
private static String getNameForSetter(@NotNull String propertyName) {
return getNameWithPrefix(propertyName, SETTER_PREFIX);
}
@NotNull
public static String getPrototypeName() {
return PROTOTYPE_NAME;
}
@NotNull
private static JsNameRef getRefToPrototype(@NotNull JsExpression classOrTraitExpression) {
return pureFqn(getPrototypeName(), classOrTraitExpression);
}
@NotNull
public static String getDelegatePrefix() {
return DELEGATE;
@@ -207,11 +168,6 @@ public final class Namer {
return new JsNameRef(getDelegateName(propertyName), JsLiteral.THIS);
}
@NotNull
private static String getNameWithPrefix(@NotNull String name, @NotNull String prefix) {
return prefix + name;
}
@NotNull
public static JsNameRef getFunctionCallRef(@NotNull JsExpression functionExpression) {
return pureFqn(CALL_FUNCTION, functionExpression);
@@ -224,7 +180,7 @@ public final class Namer {
@NotNull
public static JsInvocation createObjectWithPrototypeFrom(JsNameRef referenceToClass) {
return new JsInvocation(JS_OBJECT_CREATE_FUNCTION, getRefToPrototype(referenceToClass));
return new JsInvocation(JS_OBJECT_CREATE_FUNCTION, JsAstUtils.prototypeOf(referenceToClass));
}
@NotNull
@@ -245,18 +201,6 @@ public final class Namer {
@NotNull
private final JsObjectScope kotlinScope;
@NotNull
private final JsName classCreationMethodReference;
@NotNull
private final JsName enumClassCreationMethodName;
@NotNull
private final JsName interfaceCreationMethodName;
@NotNull
private final JsExpression definePackage;
@NotNull
private final JsExpression defineRootPackage;
@NotNull
private final JsName objectCreationMethodName;
@NotNull
private final JsName callableRefForMemberFunctionName;
@NotNull
private final JsName callableRefForExtensionFunctionName;
@@ -280,17 +224,10 @@ public final class Namer {
private Namer(@NotNull JsScope rootScope) {
kotlinScope = JsObjectScope(rootScope, "Kotlin standard object");
interfaceCreationMethodName = kotlinScope.declareName(TRAIT_OBJECT_NAME);
definePackage = kotlin("definePackage");
defineRootPackage = kotlin("defineRootPackage");
callGetProperty = kotlin("callGetter");
callSetProperty = kotlin("callSetter");
classCreationMethodReference = kotlinScope.declareName(CLASS_OBJECT_NAME);
enumClassCreationMethodName = kotlinScope.declareName(ENUM_CLASS_OBJECT_NAME);
objectCreationMethodName = kotlinScope.declareName(OBJECT_OBJECT_NAME);
callableRefForMemberFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME);
callableRefForExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME);
callableRefForLocalExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_LOCAL_EXTENSION_FUNCTION_NAME);
@@ -313,16 +250,6 @@ public final class Namer {
return suggested.getNames().get(0);
}
@NotNull
public JsExpression packageDefinitionMethodReference() {
return definePackage;
}
@NotNull
public JsExpression rootPackageDefinitionMethodReference() {
return defineRootPackage;
}
@NotNull
public JsExpression callableRefForMemberFunctionReference() {
return kotlin(callableRefForMemberFunctionName);
@@ -463,24 +390,6 @@ public final class Namer {
return packageFqName.isRoot() ? getRootPackageName() : packageFqName.shortName().asString();
}
@NotNull
public JsExpression classCreateInvocation(@NotNull ClassDescriptor descriptor) {
switch (descriptor.getKind()) {
case INTERFACE:
return kotlin(interfaceCreationMethodName);
case ENUM_CLASS:
return kotlin(enumClassCreationMethodName);
case ENUM_ENTRY:
case OBJECT:
return kotlin(objectCreationMethodName);
case ANNOTATION_CLASS:
case CLASS:
return kotlin(classCreationMethodReference);
default:
throw new UnsupportedOperationException("Unsupported class kind: " + descriptor);
}
}
@NotNull
public static JsExpression getUndefinedExpression() {
return new JsPrefixOperation(JsUnaryOperator.VOID, JsNumberLiteral.ZERO);
@@ -488,12 +397,12 @@ public final class Namer {
@NotNull
public JsExpression getCallGetProperty() {
return callGetProperty;
return callGetProperty.deepCopy();
}
@NotNull
public JsExpression getCallSetProperty() {
return callSetProperty;
return callSetProperty.deepCopy();
}
public static JsNameRef kotlinLong() {
@@ -113,6 +113,7 @@ public final class StandardClasses {
standardClasses.declare().forFQ("kotlin.Comparable").kotlinClass("Comparable");
standardClasses.declare().forFQ("kotlin.Throwable").kotlinClass("Throwable");
standardClasses.declare().forFQ("kotlin.Annotation").kotlinClass("Annotation");
}
@@ -27,7 +27,9 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.hash.LinkedHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
import org.jetbrains.kotlin.js.config.JsConfig;
import org.jetbrains.kotlin.js.naming.NameSuggestion;
import org.jetbrains.kotlin.js.naming.SuggestedName;
@@ -36,10 +38,12 @@ import org.jetbrains.kotlin.js.translate.context.generator.Rule;
import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import java.util.*;
@@ -63,7 +67,8 @@ public final class StaticContext {
Namer namer = Namer.newInstance(program.getRootScope());
Intrinsics intrinsics = new Intrinsics();
StandardClasses standardClasses = StandardClasses.bindImplementations(namer.getKotlinScope());
return new StaticContext(program, bindingTrace, namer, intrinsics, standardClasses, program.getRootScope(), config,
JsFunction rootFunction = JsAstUtils.createFunctionWithEmptyBody(program.getScope());
return new StaticContext(program, rootFunction, bindingTrace, namer, intrinsics, standardClasses, program.getRootScope(), config,
moduleDescriptor);
}
@@ -84,10 +89,14 @@ public final class StaticContext {
@NotNull
private final JsScope rootScope;
@NotNull
private final Generator<JsName> innerNames = new InnerNameGenerator();
@NotNull
private final Map<FqName, JsName> packageNames = Maps.newHashMap();
@NotNull
private final Generator<JsScope> scopes = new ScopeGenerator();
@NotNull
private final Generator<JsName> objectInstanceNames = new ObjectInstanceNameGenerator();
@NotNull
private final Map<JsScope, JsFunction> scopeToFunction = Maps.newHashMap();
@@ -124,9 +133,31 @@ public final class StaticContext {
@NotNull
private final JsScope rootPackageScope;
@NotNull
private JsFunction rootFunction;
@NotNull
private final List<JsStatement> declarationStatements = new ArrayList<JsStatement>();
@NotNull
private final List<JsStatement> importStatements = new ArrayList<JsStatement>();
@NotNull
private final List<JsStatement> exportStatements = new ArrayList<JsStatement>();
@NotNull
private final Set<ClassDescriptor> classes = new HashSet<ClassDescriptor>();
@NotNull
private final ExportedPackage rootPackage = new ExportedPackage("");
@NotNull
private final JsObjectLiteral exportObject = rootPackage.objectLiteral;
//TODO: too many parameters in constructor
private StaticContext(
@NotNull JsProgram program,
@NotNull JsFunction rootFunction,
@NotNull BindingTrace bindingTrace,
@NotNull Namer namer,
@NotNull Intrinsics intrinsics,
@@ -136,13 +167,15 @@ public final class StaticContext {
@NotNull ModuleDescriptor moduleDescriptor
) {
this.program = program;
this.rootFunction = rootFunction;
this.bindingTrace = bindingTrace;
this.namer = namer;
this.intrinsics = intrinsics;
this.rootScope = rootScope;
this.standardClasses = standardClasses;
this.config = config;
currentModule = moduleDescriptor;
this.currentModule = moduleDescriptor;
this.rootFunction = rootFunction;
rootPackageScope = new JsObjectScope(rootScope, "<root package>", "root-package");
}
@@ -171,11 +204,6 @@ public final class StaticContext {
return namer;
}
@NotNull
private JsScope getRootScope() {
return rootScope;
}
@NotNull
public Map<String, JsName> getImportedModules() {
if (readOnlyImportedModules == null) {
@@ -219,6 +247,10 @@ public final class StaticContext {
@NotNull
private JsExpression buildQualifiedExpression(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof ClassDescriptor && KotlinBuiltIns.isAny((ClassDescriptor) descriptor)) {
return new JsNameRef("Object");
}
SuggestedName suggested = nameSuggestion.suggest(descriptor);
if (suggested == null) {
ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
@@ -288,6 +320,20 @@ public final class StaticContext {
return name;
}
@NotNull
public JsName getInnerNameForDescriptor(@NotNull DeclarationDescriptor descriptor) {
JsName name = innerNames.get(descriptor.getOriginal());
assert name != null : "Must have inner name for descriptor";
return name;
}
@NotNull
public JsName getNameForObjectInstance(@NotNull ClassDescriptor descriptor) {
JsName name = objectInstanceNames.get(descriptor.getOriginal());
assert name != null : "Must have inner name for object instance";
return name;
}
@NotNull
private List<JsName> getActualNameFromSuggested(@NotNull SuggestedName suggested) {
JsScope scope = getScopeForDescriptor(suggested.getScope());
@@ -362,6 +408,100 @@ public final class StaticContext {
return config;
}
private final class InnerNameGenerator extends Generator<JsName> {
public InnerNameGenerator() {
addRule(new Rule<JsName>() {
@Nullable
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof ModuleDescriptor) {
return getModuleInnerName(descriptor);
}
if (descriptor instanceof LocalVariableDescriptor || descriptor instanceof ParameterDescriptor) {
return getNameForDescriptor(descriptor);
}
if (descriptor instanceof ConstructorDescriptor) {
if (((ConstructorDescriptor) descriptor).isPrimary()) {
return getInnerNameForDescriptor(((ConstructorDescriptor) descriptor).getConstructedClass());
}
}
JsName result = rootFunction.getScope().declareFreshName(getSuggestedName(descriptor));
ModuleDescriptor module = DescriptorUtilsKt.getModule(descriptor);
if (module != currentModule) {
importStatements.add(JsAstUtils.newVar(result, getQualifiedReference(descriptor)));
}
return result;
}
});
}
}
private final class ObjectInstanceNameGenerator extends Generator<JsName> {
public ObjectInstanceNameGenerator() {
addRule(new Rule<JsName>() {
@Nullable
@Override
public JsName apply(@NotNull DeclarationDescriptor descriptor) {
String suggested = getSuggestedName(descriptor) + Namer.OBJECT_INSTANCE_FUNCTION_SUFFIX;
JsName result = rootFunction.getScope().declareFreshName(suggested);
ModuleDescriptor module = DescriptorUtilsKt.getModule(descriptor);
if (module != currentModule) {
importStatements.add(JsAstUtils.newVar(result, getQualifiedReference(descriptor)));
}
return result;
}
});
}
}
@NotNull
public static String getSuggestedName(@NotNull DeclarationDescriptor descriptor) {
String suggestedName;
if (descriptor instanceof PropertyGetterDescriptor) {
PropertyGetterDescriptor getter = (PropertyGetterDescriptor) descriptor;
suggestedName = "get_" + getSuggestedName(getter.getCorrespondingProperty());
}
else if (descriptor instanceof PropertySetterDescriptor) {
PropertySetterDescriptor setter = (PropertySetterDescriptor) descriptor;
suggestedName = "set_" + getSuggestedName(setter.getCorrespondingProperty());
}
else if (descriptor instanceof ConstructorDescriptor) {
ConstructorDescriptor constructor = (ConstructorDescriptor) descriptor;
suggestedName = getSuggestedName(constructor.getContainingDeclaration()) + "_init";
descriptor = descriptor.getContainingDeclaration();
assert descriptor != null : "ConstructorDescriptor should have containing declaration: " + constructor;
}
else {
if (descriptor.getName().isSpecial()) {
if (descriptor instanceof ClassDescriptor) {
if (DescriptorUtils.isAnonymousObject(descriptor)) {
suggestedName = "ObjectLiteral";
}
else {
suggestedName = "Anonymous";
}
}
else if (descriptor instanceof FunctionDescriptor) {
suggestedName = "lambda";
}
else {
suggestedName = "anonymous";
}
}
else {
suggestedName = descriptor.getName().asString();
}
}
if (!(descriptor instanceof PackageFragmentDescriptor) && !DescriptorUtils.isTopLevelDeclaration(descriptor)) {
DeclarationDescriptor container = descriptor.getContainingDeclaration();
assert container != null : "We just figured out that descriptor is not for a top-level declaration: " + descriptor;
suggestedName = getSuggestedName(container) + "$" + suggestedName;
}
return suggestedName;
}
@NotNull
public JsName declarePropertyOrPropertyAccessorName(@NotNull DeclarationDescriptor descriptor, @NotNull String name, boolean fresh) {
JsScope scope = getEnclosingScope(descriptor);
@@ -384,7 +524,7 @@ public final class StaticContext {
return null;
}
if (getSuperclass((ClassDescriptor) descriptor) == null) {
return getRootScope().innerObjectScope("Scope for class " + descriptor.getName());
return rootFunction.getScope();
}
return null;
}
@@ -405,10 +545,7 @@ public final class StaticContext {
Rule<JsScope> generateNewScopesForPackageDescriptors = new Rule<JsScope>() {
@Override
public JsScope apply(@NotNull DeclarationDescriptor descriptor) {
if (!(descriptor instanceof PackageFragmentDescriptor)) {
return null;
}
return getRootScope().innerObjectScope("Package " + descriptor.getName());
return rootFunction.getScope();
}
};
//TODO: never get there
@@ -426,7 +563,7 @@ public final class StaticContext {
return null;
}
JsFunction correspondingFunction = JsAstUtils.createFunctionWithEmptyBody(getRootScope());
JsFunction correspondingFunction = JsAstUtils.createFunctionWithEmptyBody(rootFunction.getScope());
assert (!scopeToFunction.containsKey(correspondingFunction.getScope())) : "Scope to function value overridden for " + descriptor;
scopeToFunction.put(correspondingFunction.getScope(), correspondingFunction);
return correspondingFunction.getScope();
@@ -442,9 +579,15 @@ public final class StaticContext {
@Nullable
public JsExpression getModuleExpressionFor(@NotNull DeclarationDescriptor descriptor) {
JsName name = getModuleInnerName(descriptor);
return name != null ? JsAstUtils.pureFqn(name, null) : null;
}
@Nullable
private JsName getModuleInnerName(@NotNull DeclarationDescriptor descriptor) {
ModuleDescriptor module = DescriptorUtils.getContainingModule(descriptor);
if (currentModule == module) {
return pureFqn(Namer.getRootPackageName(), null);
return rootScope.declareName(Namer.getRootPackageName());
}
String moduleName;
if (module == module.getBuiltIns().getBuiltInsModule()) {
@@ -464,7 +607,7 @@ public final class StaticContext {
importedModules.put(moduleName, moduleId);
}
return JsAstUtils.pureFqn(moduleId, null);
return moduleId;
}
private static JsExpression applySideEffects(JsExpression expression, DeclarationDescriptor descriptor) {
@@ -493,4 +636,115 @@ public final class StaticContext {
public Map<ClassDescriptor, List<DeferredCallSite>> getDeferredCallSites() {
return deferredCallSites;
}
@NotNull
public JsFunction getRootFunction() {
return rootFunction;
}
@NotNull
public List<JsStatement> getDeclarationStatements() {
return declarationStatements;
}
public void addRootStatement(@NotNull JsStatement statement) {
declarationStatements.add(statement);
}
public void addClass(@NotNull ClassDescriptor classDescriptor) {
classes.add(classDescriptor);
}
public void export(@NotNull DeclarationDescriptor descriptor) {
DeclarationDescriptor container = descriptor.getContainingDeclaration();
if (descriptor instanceof ConstructorDescriptor) {
ConstructorDescriptor constructor = (ConstructorDescriptor) descriptor;
container = constructor.getConstructedClass().getContainingDeclaration();
}
if (!(container instanceof PackageFragmentDescriptor)) {
throw new IllegalArgumentException("Declaration " + descriptor + " is not a top-level declaration");
}
PackageFragmentDescriptor packageDescriptor = (PackageFragmentDescriptor) container;
ExportedPackage exportedPackage = rootPackage;
for (Name packageName : packageDescriptor.getFqName().pathSegments()) {
exportedPackage = exportedPackage.getSubpackage(packageName.asString());
}
JsExpression initializerExpr = DeclarationExporter.exportDeclaration(this, descriptor, exportStatements);
if (initializerExpr != null) {
JsPropertyInitializer initializer = new JsPropertyInitializer(
getNameForDescriptor(descriptor).makeRef(), initializerExpr);
exportedPackage.objectLiteral.getPropertyInitializers().add(initializer);
}
}
@NotNull
public NameSuggestion getNameSuggestion() {
return nameSuggestion;
}
@NotNull
public ModuleDescriptor getCurrentModule() {
return currentModule;
}
public void postProcess() {
rootFunction.getBody().getStatements().addAll(importStatements);
addClassPrototypes();
rootFunction.getBody().getStatements().addAll(declarationStatements);
JsName rootPackageName = rootFunction.getScope().declareName(Namer.getRootPackageName());
rootFunction.getBody().getStatements().add(JsAstUtils.newVar(rootPackageName, exportObject));
rootFunction.getBody().getStatements().addAll(exportStatements);
}
private void addClassPrototypes() {
Set<ClassDescriptor> visited = new HashSet<ClassDescriptor>();
for (ClassDescriptor cls : classes) {
addClassPrototypes(cls, visited);
}
}
private void addClassPrototypes(@NotNull ClassDescriptor cls, @NotNull Set<ClassDescriptor> visited) {
if (DescriptorUtilsKt.getModule(cls) != currentModule) return;
if (!visited.add(cls)) return;
ClassDescriptor superclass = DescriptorUtilsKt.getSuperClassNotAny(cls);
if (superclass != null) {
addClassPrototypes(superclass, visited);
List<JsStatement> statements = rootFunction.getBody().getStatements();
JsExpression superPrototype = JsAstUtils.prototypeOf(new JsNameRef(getInnerNameForDescriptor(superclass)));
JsExpression superPrototypeInstance = new JsInvocation(new JsNameRef("create", "Object"), superPrototype);
JsExpression classRef = new JsNameRef(getInnerNameForDescriptor(cls));
JsExpression prototype = JsAstUtils.prototypeOf(classRef);
statements.add(JsAstUtils.assignment(prototype, superPrototypeInstance).makeStmt());
JsExpression constructorRef = new JsNameRef("constructor", prototype.deepCopy());
statements.add(JsAstUtils.assignment(constructorRef, classRef.deepCopy()).makeStmt());
}
}
private static class ExportedPackage {
@NotNull final String name;
@NotNull final Map<String, ExportedPackage> subpackages = new HashMap<String, ExportedPackage>();
@NotNull final JsObjectLiteral objectLiteral = new JsObjectLiteral(true);
public ExportedPackage(@NotNull String name) {
this.name = name;
}
@NotNull
public ExportedPackage getSubpackage(@NotNull String name) {
ExportedPackage subpackage = subpackages.get(name);
if (subpackage == null) {
subpackage = new ExportedPackage(name);
subpackages.put(name, subpackage);
objectLiteral.getPropertyInitializers().add(new JsPropertyInitializer(new JsNameRef(name), subpackage.objectLiteral));
}
return subpackage;
}
}
}
@@ -24,12 +24,14 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
import org.jetbrains.kotlin.js.config.JsConfig;
import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver;
import java.util.*;
@@ -52,17 +54,19 @@ public class TranslationContext {
@Nullable
private final TranslationContext parent;
@Nullable
private final DefinitionPlace definitionPlace;
@Nullable
private final DeclarationDescriptor declarationDescriptor;
@Nullable
private final ClassDescriptor classDescriptor;
@NotNull
public static TranslationContext rootContext(@NotNull StaticContext staticContext, JsFunction rootFunction) {
DynamicContext rootDynamicContext = DynamicContext.rootContext(rootFunction.getScope(), rootFunction.getBody());
public static TranslationContext rootContext(
@NotNull StaticContext staticContext,
@NotNull JsFunction rootFunction
) {
JsBlock block = new JsBlock(staticContext.getDeclarationStatements());
DynamicContext rootDynamicContext = DynamicContext.rootContext(rootFunction.getScope(), block);
AliasingContext rootAliasingContext = AliasingContext.getCleanContext();
return new TranslationContext(null, staticContext, rootDynamicContext, rootAliasingContext, null, null, null);
return new TranslationContext(null, staticContext, rootDynamicContext, rootAliasingContext, null, null);
}
private final Map<JsExpression, TemporaryConstVariable> expressionToTempConstVariableCache = new HashMap<JsExpression, TemporaryConstVariable>();
@@ -73,7 +77,6 @@ public class TranslationContext {
@NotNull DynamicContext dynamicContext,
@NotNull AliasingContext aliasingContext,
@Nullable UsageTracker usageTracker,
@Nullable DefinitionPlace definitionPlace,
@Nullable DeclarationDescriptor declarationDescriptor
) {
this.parent = parent;
@@ -81,7 +84,6 @@ public class TranslationContext {
this.staticContext = staticContext;
this.aliasingContext = aliasingContext;
this.usageTracker = usageTracker;
this.definitionPlace = definitionPlace;
this.declarationDescriptor = declarationDescriptor;
if (declarationDescriptor instanceof ClassDescriptor) {
this.classDescriptor = (ClassDescriptor) declarationDescriptor;
@@ -119,27 +121,25 @@ public class TranslationContext {
aliasingContext = this.aliasingContext.inner();
}
return new TranslationContext(this, this.staticContext, dynamicContext, aliasingContext, this.usageTracker, null, descriptor);
return new TranslationContext(this, this.staticContext, dynamicContext, aliasingContext, this.usageTracker, descriptor);
}
@NotNull
public TranslationContext newFunctionBodyWithUsageTracker(@NotNull JsFunction fun, @NotNull MemberDescriptor descriptor) {
DynamicContext dynamicContext = DynamicContext.newContext(fun.getScope(), fun.getBody());
UsageTracker usageTracker = new UsageTracker(this.usageTracker, descriptor, fun.getScope());
return new TranslationContext(this, this.staticContext, dynamicContext, this.aliasingContext.inner(), usageTracker,
this.definitionPlace, descriptor);
return new TranslationContext(this, this.staticContext, dynamicContext, this.aliasingContext.inner(), usageTracker, descriptor);
}
@NotNull
public TranslationContext innerWithUsageTracker(@NotNull JsScope scope, @NotNull MemberDescriptor descriptor) {
UsageTracker usageTracker = new UsageTracker(this.usageTracker, descriptor, scope);
return new TranslationContext(this, staticContext, dynamicContext, aliasingContext.inner(), usageTracker, definitionPlace,
descriptor);
return new TranslationContext(this, staticContext, dynamicContext, aliasingContext.inner(), usageTracker, descriptor);
}
@NotNull
public TranslationContext innerBlock(@NotNull JsBlock block) {
return new TranslationContext(this, staticContext, dynamicContext.innerBlock(block), aliasingContext, usageTracker, null,
return new TranslationContext(this, staticContext, dynamicContext.innerBlock(block), aliasingContext, usageTracker,
this.declarationDescriptor);
}
@@ -149,14 +149,18 @@ public class TranslationContext {
}
@NotNull
public TranslationContext newDeclaration(@NotNull DeclarationDescriptor descriptor, @Nullable DefinitionPlace place) {
DynamicContext dynamicContext = DynamicContext.newContext(getScopeForDescriptor(descriptor), getBlockForDescriptor(descriptor));
return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, place, descriptor);
public TranslationContext newDeclaration(@NotNull DeclarationDescriptor descriptor) {
JsBlock innerBlock = getBlockForDescriptor(descriptor);
if (innerBlock == null) {
innerBlock = dynamicContext.jsBlock();
}
DynamicContext dynamicContext = DynamicContext.newContext(getScopeForDescriptor(descriptor), innerBlock);
return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, descriptor);
}
@NotNull
private TranslationContext innerWithAliasingContext(AliasingContext aliasingContext) {
return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, null, declarationDescriptor);
return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, declarationDescriptor);
}
@NotNull
@@ -174,13 +178,13 @@ public class TranslationContext {
return this.innerWithAliasingContext(aliasingContext.withDescriptorsAliased(aliases));
}
@NotNull
@Nullable
private JsBlock getBlockForDescriptor(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof CallableDescriptor) {
return getFunctionObject((CallableDescriptor) descriptor).getBody();
}
else {
return new JsBlock();
return null;
}
}
@@ -211,8 +215,13 @@ public class TranslationContext {
}
@NotNull
public JsName getNameForPackage(@NotNull FqName fqName) {
return staticContext.getNameForPackage(fqName);
public JsName getInnerNameForDescriptor(@NotNull DeclarationDescriptor descriptor) {
return staticContext.getInnerNameForDescriptor(descriptor);
}
@NotNull
public JsName getNameForObjectInstance(@NotNull ClassDescriptor descriptor) {
return staticContext.getNameForObjectInstance(descriptor);
}
@NotNull
@@ -225,6 +234,11 @@ public class TranslationContext {
return staticContext.getQualifiedReference(descriptor);
}
@NotNull
public JsNameRef getInnerReference(@NotNull DeclarationDescriptor descriptor) {
return JsAstUtils.pureFqn(getInnerNameForDescriptor(descriptor), null);
}
@NotNull
public JsNameRef getQualifiedReference(@NotNull FqName packageFqName) {
return staticContext.getQualifiedReference(packageFqName);
@@ -358,7 +372,9 @@ public class TranslationContext {
return JsLiteral.THIS;
}
else {
return getQualifiedReference(descriptor.getContainingDeclaration());
ClassDescriptor objectDescriptor = (ClassDescriptor) descriptor.getContainingDeclaration();
JsExpression instanceFunctionRef = JsAstUtils.pureFqn(getNameForObjectInstance(objectDescriptor), null);
return new JsInvocation(instanceFunctionRef);
}
}
@@ -381,7 +397,7 @@ public class TranslationContext {
}
private boolean isConstructorOrDirectScope(DeclarationDescriptor descriptor) {
if (declarationDescriptor instanceof ClassDescriptor && !DescriptorUtils.isCompanionObject(declarationDescriptor)) {
if (declarationDescriptor instanceof ClassDescriptor) {
return descriptor == declarationDescriptor;
}
else {
@@ -402,8 +418,7 @@ public class TranslationContext {
return thisExpression;
}
ClassDescriptor parentDescriptor = parent.classDescriptor;
if (classDescriptor != parentDescriptor) {
if (classDescriptor != parent.classDescriptor) {
return new JsNameRef(Namer.OUTER_FIELD_NAME, parent.getDispatchReceiverPath(cls, thisExpression));
}
else {
@@ -411,20 +426,6 @@ public class TranslationContext {
}
}
@NotNull
public DefinitionPlace getDefinitionPlace() {
if (definitionPlace != null) return definitionPlace;
if (parent != null) return parent.getDefinitionPlace();
throw new AssertionError("Can not find definition place from rootContext(definitionPlace and parent is null)");
}
@NotNull
public JsNameRef define(DeclarationDescriptor descriptor, JsExpression expression) {
String suggestedName = TranslationUtils.getSuggestedNameForInnerDeclaration(staticContext, descriptor);
return getDefinitionPlace().define(suggestedName, expression);
}
@Nullable
private JsNameRef captureIfNeedAndGetCapturedName(DeclarationDescriptor descriptor) {
if (usageTracker != null) {
@@ -560,4 +561,49 @@ public class TranslationContext {
public JsExpression getModuleExpressionFor(@NotNull DeclarationDescriptor descriptor) {
return staticContext.getModuleExpressionFor(descriptor);
}
@NotNull
public JsFunction getRootFunction() {
return staticContext.getRootFunction();
}
public void addRootStatement(@NotNull JsStatement statement) {
staticContext.addRootStatement(statement);
}
@NotNull
public JsFunction defineTopLevelFunction(@NotNull DeclarationDescriptor descriptor) {
JsFunction function = createTopLevelFunction(descriptor);
addRootStatement(function.makeStmt());
return function;
}
@NotNull
public JsName createGlobalName(@NotNull String suggestedName) {
return staticContext.getRootFunction().getScope().declareFreshName(suggestedName);
}
@NotNull
public JsFunction createTopLevelFunction(@NotNull DeclarationDescriptor descriptor) {
JsFunction function = createTopLevelAnonymousFunction(descriptor);
function.setName(staticContext.getInnerNameForDescriptor(descriptor));
return function;
}
@NotNull
public JsFunction createTopLevelAnonymousFunction(@NotNull DeclarationDescriptor descriptor) {
return new JsFunction(getRootFunction().getScope(), new JsBlock(), descriptor.toString());
}
public void addClass(@NotNull ClassDescriptor classDescriptor) {
staticContext.addClass(classDescriptor);
}
public void export(@NotNull DeclarationDescriptor descriptor) {
staticContext.export(descriptor);
}
public boolean isFromCurrentModule(@NotNull DeclarationDescriptor descriptor) {
return staticContext.getCurrentModule() == DescriptorUtilsKt.getModule(descriptor);
}
}
@@ -0,0 +1,82 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:JvmName("DeclarationExporter")
package org.jetbrains.kotlin.js.translate.context
import com.google.dart.compiler.backend.js.ast.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
fun StaticContext.exportDeclaration(declaration: DeclarationDescriptor, additionalStatements: MutableList<in JsStatement>): JsExpression? {
return when {
declaration is ClassDescriptor && declaration.kind == ClassKind.OBJECT -> {
exportObject(declaration, additionalStatements)
null
}
declaration is PropertyDescriptor -> {
exportProperty(declaration, additionalStatements)
null
}
else -> {
getInnerNameForDescriptor(declaration).makeRef()
}
}
}
private fun StaticContext.exportObject(declaration: ClassDescriptor, additionalStatements: MutableList<in JsStatement>) {
val suggestedName = nameSuggestion.suggest(declaration)!!
val qualifier = getQualifiedReference(suggestedName.scope)
val name = getNameForDescriptor(declaration)
additionalStatements += JsAstUtils.defineGetter(program, qualifier, name.ident, getNameForObjectInstance(declaration).makeRef())
}
private fun StaticContext.exportProperty(declaration: PropertyDescriptor, additionalStatements: MutableList<in JsStatement>) {
val propertyLiteral = JsObjectLiteral(true)
val suggestedName = nameSuggestion.suggest(declaration)!!
val qualifier = getQualifiedReference(suggestedName.scope)
val name = getNameForDescriptor(declaration).ident
val getterBody: JsExpression = if (JsDescriptorUtils.isSimpleFinalProperty(declaration)) {
val accessToField = JsReturn(getInnerNameForDescriptor(declaration).makeRef())
JsFunction(rootFunction.scope, JsBlock(accessToField), "$declaration getter")
}
else {
getInnerNameForDescriptor(declaration.getter!!).makeRef()
}
propertyLiteral.propertyInitializers += JsPropertyInitializer(JsNameRef("get"), getterBody)
if (declaration.isVar) {
val setterBody: JsExpression = if (JsDescriptorUtils.isSimpleFinalProperty(declaration)) {
val statements = mutableListOf<JsStatement>()
val function = JsFunction(rootFunction.scope, JsBlock(statements), "$declaration setter")
val valueName = function.scope.declareFreshName("value")
function.parameters += JsParameter(valueName)
statements += JsAstUtils.assignment(getInnerNameForDescriptor(declaration).makeRef(), valueName.makeRef()).makeStmt()
function
}
else {
getInnerNameForDescriptor(declaration.setter!!).makeRef()
}
propertyLiteral.propertyInitializers += JsPropertyInitializer(JsNameRef("set"), setterBody)
}
additionalStatements += JsAstUtils.defineProperty(qualifier, name, propertyLiteral, program).makeStmt()
}
@@ -0,0 +1,116 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.translate.declaration
import com.google.dart.compiler.backend.js.ast.JsExpression
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.general.Translation
import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor
import org.jetbrains.kotlin.js.translate.utils.BindingUtils
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
override fun emptyResult(context: TranslationContext) { }
override fun visitClassOrObject(classOrObject: KtClassOrObject, context: TranslationContext) {
ClassTranslator.translate(classOrObject, context)
val descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), classOrObject)
addClass(descriptor)
}
override fun visitProperty(expression: KtProperty, context: TranslationContext) {
val descriptor = BindingUtils.getPropertyDescriptor(context.bindingContext(), expression)
if (descriptor.modality === Modality.ABSTRACT) return
val propertyContext = context.newDeclaration(descriptor)
val defaultTranslator = DefaultPropertyTranslator(descriptor, context, getBackingFieldReference(descriptor))
val getter = descriptor.getter!!
val getterExpr = if (expression.hasCustomGetter()) {
translateFunction(getter, expression.getter!!, propertyContext)
}
else {
val function = context.getFunctionObject(getter)
defaultTranslator.generateDefaultGetterFunction(getter, function)
function
}
val setterExpr = if (descriptor.isVar) {
val setter = descriptor.setter!!
if (expression.hasCustomSetter()) {
translateFunction(setter, expression.setter!!, propertyContext)
}
else {
val function = context.getFunctionObject(setter)
defaultTranslator.generateDefaultSetterFunction(setter, function)
function
}
}
else {
null
}
if (TranslationUtils.shouldAccessViaFunctions(descriptor) || descriptor.isExtensionProperty) {
addFunction(descriptor.getter!!, getterExpr)
descriptor.setter?.let { addFunction(it, setterExpr!!) }
}
else {
addProperty(descriptor, getterExpr, setterExpr)
}
}
override fun visitNamedFunction(expression: KtNamedFunction, context: TranslationContext) {
val descriptor = BindingUtils.getFunctionDescriptor(context.bindingContext(), expression)
if (descriptor.modality === Modality.ABSTRACT) return
addFunction(descriptor, translateFunction(descriptor, expression, context))
}
override fun visitTypeAlias(typeAlias: KtTypeAlias, data: TranslationContext?) {}
private fun translateFunction(
descriptor: FunctionDescriptor,
expression: KtDeclarationWithBody,
context: TranslationContext
): JsExpression {
val innerContext = context.newDeclaration(descriptor)
innerContext.getInnerNameForDescriptor(descriptor)
val function = context.getFunctionObject(descriptor)
return Translation.functionTranslator(expression, innerContext, function).translateAsMethod()
}
protected abstract fun addClass(descriptor: ClassDescriptor)
protected abstract fun addFunction(
descriptor: FunctionDescriptor,
expression: JsExpression
)
protected abstract fun addProperty(
descriptor: PropertyDescriptor,
getter: JsExpression,
setter: JsExpression?
)
protected abstract fun getBackingFieldReference(descriptor: PropertyDescriptor): JsExpression
}
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.js.translate.declaration
import com.google.dart.compiler.backend.js.ast.*
import com.intellij.util.SmartList
import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.backend.common.bridges.Bridge
import org.jetbrains.kotlin.backend.common.bridges.generateBridgesForFunctionDescriptor
@@ -30,21 +29,19 @@ import org.jetbrains.kotlin.js.translate.context.*
import org.jetbrains.kotlin.js.translate.expression.FunctionTranslator
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
import org.jetbrains.kotlin.js.translate.initializer.ClassInitializerTranslator
import org.jetbrains.kotlin.js.translate.utils.BindingUtils
import org.jetbrains.kotlin.js.translate.utils.*
import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getClassDescriptor
import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getPropertyDescriptorForConstructorParameter
import org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getSupertypesWithoutFakes
import org.jetbrains.kotlin.js.translate.utils.PsiUtils.getPrimaryConstructorParameters
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunction
import org.jetbrains.kotlin.js.translate.utils.generateDelegateCall
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.toInvocationWith
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtSecondaryConstructor
import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.*
import org.jetbrains.kotlin.resolve.DescriptorUtils.getClassDescriptorForType
import org.jetbrains.kotlin.resolve.DescriptorUtils.getClassDescriptorForTypeConstructor
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.types.CommonSupertypes.topologicallySortSuperclassesAndRecordAllInstances
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.TypeConstructor
@@ -60,20 +57,13 @@ class ClassTranslator private constructor(
) : AbstractTranslator(context) {
private val descriptor = getClassDescriptor(context.bindingContext(), classDeclaration)
private val invocationArguments = mutableListOf<JsExpression>()
private val secondaryConstructors = mutableListOf<ConstructorInfo>()
private val secondaryConstructorProperties = mutableListOf<JsPropertyInitializer>()
private var primaryConstructor: ConstructorInfo? = null
private lateinit var definitionPlace: DefinitionPlace
private lateinit var cachedInstanceName: JsName
private val metadataLiteral = JsObjectLiteral(true)
private fun translate(): TranslationResult {
private fun translate() {
generateClassCreateInvocationArguments()
val classNameRef = context().getNameForDescriptor(descriptor).makeRef()
val classCreation = JsInvocation(context().namer().classCreateInvocation(descriptor), invocationArguments)
val properties = listOf(JsPropertyInitializer(classNameRef, classCreation)) + secondaryConstructorProperties
return TranslationResult(properties, definitionPlace)
}
private fun isTrait(): Boolean = descriptor.kind == ClassKind.INTERFACE
@@ -81,35 +71,35 @@ class ClassTranslator private constructor(
private fun isAnnotation(): Boolean = descriptor.kind == ClassKind.ANNOTATION_CLASS
private fun generateClassCreateInvocationArguments() {
val properties = SmartList<JsPropertyInitializer>()
val staticProperties = SmartList<JsPropertyInitializer>()
val qualifiedReference = context().getQualifiedReference(descriptor)
val scope = context().getScopeForDescriptor(descriptor)
val definitionPlace = DefinitionPlace(scope as JsObjectScope, qualifiedReference, staticProperties)
val context = context().newDeclaration(descriptor, definitionPlace)
val context = context().newDeclaration(descriptor)
invocationArguments += getSuperclassReferences(context)
val constructorFunction = context.defineTopLevelFunction(descriptor)
val nonConstructorContext = context.innerWithUsageTracker(scope, descriptor)
nonConstructorContext.startDeclaration()
val delegationTranslator = DelegationTranslator(classDeclaration, nonConstructorContext)
translatePropertiesAsConstructorParameters(nonConstructorContext, properties)
val bodyVisitor = DeclarationBodyVisitor(properties, staticProperties, scope)
translatePropertiesAsConstructorParameters(nonConstructorContext)
val bodyVisitor = DeclarationBodyVisitor(descriptor, nonConstructorContext)
bodyVisitor.traverseContainer(classDeclaration, nonConstructorContext)
delegationTranslator.generateDelegated(properties)
constructorFunction.body.statements += bodyVisitor.initializerStatements
delegationTranslator.generateDelegated()
translatePrimaryConstructor(context, delegationTranslator)
translatePrimaryConstructor(constructorFunction, context, delegationTranslator)
addMetadataObject()
addMetadataType()
context.addClass(descriptor)
addSuperclassReferences()
classDeclaration.getSecondaryConstructors().forEach { generateSecondaryConstructor(context, it) }
generatedBridgeMethods(properties)
if (descriptor.isData) {
JsDataClassGenerator(classDeclaration, context, properties).generate()
if (descriptor.kind != ClassKind.INTERFACE) {
addInterfaceDefaultMembers()
}
if (isEnumClass(descriptor)) {
val enumEntries = JsObjectLiteral(bodyVisitor.enumEntryList, true)
invocationArguments += simpleReturnFunction(nonConstructorContext.getScopeForDescriptor(descriptor), enumEntries)
generatedBridgeMethods()
if (descriptor.isData) {
JsDataClassGenerator(classDeclaration, context).generate()
}
emitConstructors(nonConstructorContext, nonConstructorContext.endDeclaration())
@@ -117,40 +107,63 @@ class ClassTranslator private constructor(
addClosureParameters(constructor, nonConstructorContext)
}
// ExpressionVisitor.visitObjectLiteralExpression uses DefinitionPlace of the translated class to generate call to
// super constructor. Sometimes, when generating super call, we may translate another anonymous class passed as an
// argument. This class will be declared in the DefinitionPlace and put it static properties. See full explanation
// in ExpressionVisitor.visitObjectLiteralExpression
// TODO: It's a hack, we should think how to generate staticProperties lazily, whenever somebody tries to put
// definition into DefinitionPlace.
val hasStaticProperties = !staticProperties.isEmpty() || DescriptorUtils.isAnonymousObject(descriptor)
if (!properties.isEmpty() || hasStaticProperties) {
if (properties.isEmpty()) {
invocationArguments += JsLiteral.NULL
}
else {
// about "prototype" - see http://code.google.com/p/jsdoc-toolkit/wiki/TagLends
invocationArguments += JsDocComment(JsAstUtils.LENDS_JS_DOC_TAG, JsNameRef("prototype", qualifiedReference))
invocationArguments += JsObjectLiteral(properties, true)
}
if (isObjectLike()) {
addObjectMethods()
}
if (hasStaticProperties) {
invocationArguments += JsDocComment(JsAstUtils.LENDS_JS_DOC_TAG, qualifiedReference)
invocationArguments += JsObjectLiteral(staticProperties, true)
}
this.definitionPlace = definitionPlace
}
private fun translatePrimaryConstructor(classContext: TranslationContext, delegationTranslator: DelegationTranslator) {
if (isTrait()) return
private fun translatePrimaryConstructor(
constructorFunction: JsFunction,
classContext: TranslationContext,
delegationTranslator: DelegationTranslator
) {
if (!isTrait()) {
val constructorContext = classContext.innerWithUsageTracker(constructorFunction.scope, descriptor)
if (isObjectLike()) {
addObjectCache(constructorFunction.body.statements)
}
ClassInitializerTranslator(classDeclaration, constructorContext, constructorFunction)
.generateInitializeMethod(delegationTranslator)
primaryConstructor = ConstructorInfo(constructorFunction, constructorContext, descriptor)
val scope = JsFunctionScope(classContext.scope(), "$descriptor: primary constructor")
val constructorContext = classContext.innerWithUsageTracker(scope, descriptor)
val initializer = ClassInitializerTranslator(classDeclaration, constructorContext).generateInitializeMethod(delegationTranslator)
invocationArguments += initializer
if (descriptor.kind == ClassKind.ENUM_CLASS) {
addEnumClassParameters(constructorFunction)
}
}
}
this.primaryConstructor = ConstructorInfo(initializer, constructorContext, descriptor)
private fun addEnumClassParameters(constructorFunction: JsFunction) {
val nameParamName = constructorFunction.scope.declareFreshName("name")
val ordinalParamName = constructorFunction.scope.declareFreshName("ordinal")
constructorFunction.parameters += listOf(JsParameter(nameParamName), JsParameter(ordinalParamName))
constructorFunction.body.statements += JsAstUtils.assignmentToThisField(Namer.ENUM_NAME_FIELD, nameParamName.makeRef())
constructorFunction.body.statements += JsAstUtils.assignmentToThisField(Namer.ENUM_ORDINAL_FIELD, ordinalParamName.makeRef())
}
private fun isObjectLike() = when (descriptor.kind) {
ClassKind.OBJECT,
ClassKind.ENUM_ENTRY -> true
else -> false
}
private fun addMetadataObject() {
context().addRootStatement(JsAstUtils.assignment(createMetadataRef(), metadataLiteral).makeStmt())
}
private fun createMetadataRef() = JsNameRef(Namer.METADATA, context().getInnerReference(descriptor))
private fun addMetadataType() {
val kotlinType = JsNameRef("TYPE", Namer.KOTLIN_NAME)
val typeRef = when {
DescriptorUtils.isInterface(descriptor) -> JsNameRef("TRAIT", kotlinType)
DescriptorUtils.isObject(descriptor) -> JsNameRef("OBJECT", kotlinType)
else -> JsNameRef("CLASS", kotlinType)
}
val typeIndex = JsInvocation(JsNameRef("newClassIndex", Namer.KOTLIN_NAME))
metadataLiteral.propertyInitializers += JsPropertyInitializer(JsNameRef("type"), typeRef)
metadataLiteral.propertyInitializers += JsPropertyInitializer(JsNameRef("classIndex"), typeIndex)
}
private fun generateSecondaryConstructor(classContext: TranslationContext, constructor: KtSecondaryConstructor) {
@@ -177,12 +190,12 @@ class ClassTranslator private constructor(
}
// Translate constructor body
val constructorInitializer = FunctionTranslator.newInstance(constructor, context).translateAsMethod()
val constructorFunction = constructorInitializer.valueExpr as JsFunction
val constructorInitializer = context.defineTopLevelFunction(constructorDescriptor)
FunctionTranslator.newInstance(constructor, context, constructorInitializer).translateAsMethodWithoutMetadata()
// Translate super/this call
val superCallGenerators = mutableListOf<(MutableList<JsStatement>) -> Unit>()
val referenceToClass = context.getQualifiedReference(classDescriptor)
val referenceToClass = context.getInnerReference(classDescriptor)
superCallGenerators += { it += FunctionBodyTranslator.setDefaultValueForArguments(constructorDescriptor, context) }
@@ -194,11 +207,11 @@ class ClassTranslator private constructor(
val leadingArgs = mutableListOf<JsExpression>()
if (outerClassName != null) {
constructorFunction.parameters.add(0, JsParameter(outerClassName))
constructorInitializer.parameters.add(0, JsParameter(outerClassName))
leadingArgs += outerClassName.makeRef()
}
constructorFunction.parameters += JsParameter(thisName)
constructorInitializer.parameters += JsParameter(thisName)
// Generate super/this call to insert to beginning of the function
val resolvedCall = BindingContextUtils.getDelegationConstructorCall(context.bindingContext(), constructorDescriptor)
@@ -223,18 +236,17 @@ class ClassTranslator private constructor(
}
}
constructorFunction.body.statements += JsReturn(thisNameRef)
constructorInitializer.body.statements += JsReturn(thisNameRef)
val compositeSuperCallGenerator: () -> Unit = {
val additionalStatements = mutableListOf<JsStatement>()
for (partGenerator in superCallGenerators) {
partGenerator(additionalStatements)
}
constructorFunction.body.statements.addAll(0, additionalStatements)
constructorInitializer.body.statements.addAll(0, additionalStatements)
}
secondaryConstructors += ConstructorInfo(constructorFunction, context, constructorDescriptor, compositeSuperCallGenerator)
secondaryConstructorProperties += constructorInitializer
secondaryConstructors += ConstructorInfo(constructorInitializer, context, constructorDescriptor, compositeSuperCallGenerator)
}
private val allConstructors: Sequence<ConstructorInfo>
@@ -317,14 +329,9 @@ class ClassTranslator private constructor(
function.body.statements.addAll(0, additionalStatements)
}
private fun getSuperclassReferences(declarationContext: TranslationContext): JsExpression {
val superClassReferences = getSupertypesNameReferences()
if (superClassReferences.isEmpty()) {
return JsLiteral.NULL
}
else {
return simpleReturnFunction(declarationContext.scope(), JsArrayLiteral(superClassReferences))
}
private fun addSuperclassReferences() {
val supertypeReferences = JsArrayLiteral(getSupertypesNameReferences())
metadataLiteral.propertyInitializers += JsPropertyInitializer(JsNameRef(Namer.METADATA_SUPERTYPES), supertypeReferences)
}
private fun getSupertypesNameReferences(): List<JsExpression> {
@@ -336,7 +343,7 @@ class ClassTranslator private constructor(
if (supertypes.size == 1) {
val type = supertypes[0]
val supertypeDescriptor = getClassDescriptorForType(type)
return listOf<JsExpression>(getClassReference(supertypeDescriptor))
return listOf(context().getInnerReference(supertypeDescriptor))
}
val supertypeConstructors = mutableSetOf<TypeConstructor>()
@@ -352,43 +359,111 @@ class ClassTranslator private constructor(
for (typeConstructor in sortedAllSuperTypes) {
if (supertypeConstructors.contains(typeConstructor)) {
val supertypeDescriptor = getClassDescriptorForTypeConstructor(typeConstructor)
supertypesRefs += getClassReference(supertypeDescriptor)
supertypesRefs += context().getInnerReference(supertypeDescriptor)
}
}
return supertypesRefs
}
private fun getClassReference(superClassDescriptor: ClassDescriptor): JsNameRef {
return context().getQualifiedReference(superClassDescriptor)
}
private fun translatePropertiesAsConstructorParameters(classDeclarationContext: TranslationContext,
result: MutableList<JsPropertyInitializer>) {
private fun translatePropertiesAsConstructorParameters(classDeclarationContext: TranslationContext) {
for (parameter in getPrimaryConstructorParameters(classDeclaration)) {
val descriptor = getPropertyDescriptorForConstructorParameter(bindingContext(), parameter)
if (descriptor != null) {
translateAccessors(descriptor, result, classDeclarationContext)
val literal = JsObjectLiteral(true)
translateAccessors(descriptor, literal.propertyInitializers, classDeclarationContext)
if (literal.propertyInitializers.isNotEmpty()) {
classDeclarationContext.addAccessorsToPrototype(this.descriptor, descriptor, literal)
}
}
}
}
private fun generatedBridgeMethods(properties: MutableList<JsPropertyInitializer>) {
private fun addInterfaceDefaultMembers() {
val members = descriptor.unsubstitutedMemberScope
.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS)
.mapNotNull { it as? CallableMemberDescriptor }
for (member in members) {
if (member.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue
if (member.modality == Modality.ABSTRACT || member.overriddenDescriptors.size != 1) continue
val overriddenFunction = generateSequence(member) { it.overriddenDescriptors.firstOrNull() }
.drop(1)
.dropWhile { it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE &&
DescriptorUtils.isInterface(it.containingDeclaration) }
.firstOrNull() ?: continue
val interfaceDescriptor = overriddenFunction.containingDeclaration as ClassDescriptor
if (interfaceDescriptor.kind != ClassKind.INTERFACE) continue
when (member) {
is FunctionDescriptor -> addDefaultMethodFromInterface(member, interfaceDescriptor)
is PropertyDescriptor -> addDefaultPropertyFromInterface(member, interfaceDescriptor)
}
}
}
private fun addDefaultMethodFromInterface(function: FunctionDescriptor, interfaceDescriptor: ClassDescriptor) {
val classPrototype = JsAstUtils.prototypeOf(context().getInnerReference(descriptor))
val interfacePrototype = JsAstUtils.prototypeOf(context().getInnerReference(interfaceDescriptor))
val functionName = context().getNameForDescriptor(function)
val classFunction = JsNameRef(functionName, classPrototype)
val interfaceFunction = JsNameRef(functionName, interfacePrototype)
context().addRootStatement(JsAstUtils.assignment(classFunction, interfaceFunction).makeStmt())
}
private fun addDefaultPropertyFromInterface(property: PropertyDescriptor, interfaceDescriptor: ClassDescriptor) {
val classPrototype = JsAstUtils.prototypeOf(context().getInnerReference(descriptor))
val interfacePrototype = JsAstUtils.prototypeOf(context().getInnerReference(interfaceDescriptor))
val functionName = context().getNameForDescriptor(property)
val nameLiteral = context().program().getStringLiteral(functionName.ident)
val getPropertyDescriptor = JsInvocation(JsNameRef("getOwnPropertyDescriptor", "Object"), interfacePrototype, nameLiteral)
val defineProperty = JsAstUtils.defineProperty(classPrototype, functionName.ident, getPropertyDescriptor, context().program())
context().addRootStatement(defineProperty.makeStmt())
}
private fun addObjectCache(statements: MutableList<JsStatement>) {
cachedInstanceName = context().createGlobalName(StaticContext.getSuggestedName(descriptor) + Namer.OBJECT_INSTANCE_VAR_SUFFIX)
statements += JsAstUtils.assignment(cachedInstanceName.makeRef(), JsObjectLiteral.THIS).makeStmt()
}
private fun addObjectMethods() {
context().addRootStatement(JsAstUtils.newVar(cachedInstanceName, JsLiteral.NULL))
val instanceFun = JsFunction(context().rootFunction.scope, JsBlock(), "Instance function: " + descriptor)
instanceFun.name = context().getNameForObjectInstance(descriptor)
val instanceCreatedCondition = JsAstUtils.equality(cachedInstanceName.makeRef(), JsLiteral.NULL)
val instanceCreationBlock = JsBlock()
val instanceCreatedGuard = JsIf(instanceCreatedCondition, instanceCreationBlock)
instanceFun.body.statements += instanceCreatedGuard
val objectRef = context().getInnerReference(descriptor)
instanceCreationBlock.statements += JsAstUtils.assignment(cachedInstanceName.makeRef(), JsNew(objectRef)).makeStmt()
instanceFun.body.statements += JsReturn(cachedInstanceName.makeRef())
context().addRootStatement(instanceFun.makeStmt())
}
private fun generatedBridgeMethods() {
if (isAnnotation()) return
generateBridgesToTraitImpl(properties)
generateBridgesToTraitImpl()
generateOtherBridges(properties)
generateOtherBridges()
}
private fun generateBridgesToTraitImpl(properties: MutableList<JsPropertyInitializer>) {
private fun generateBridgesToTraitImpl() {
for ((key, value) in CodegenUtil.getNonPrivateTraitMethods(descriptor)) {
if (!areNamesEqual(key, value)) {
properties += generateDelegateCall(value, key, JsLiteral.THIS, context())
generateDelegateCall(descriptor, value, key, JsLiteral.THIS, context())
}
}
}
private fun generateOtherBridges(properties: MutableList<JsPropertyInitializer>) {
private fun generateOtherBridges() {
for (memberDescriptor in descriptor.defaultType.memberScope.getContributedDescriptors()) {
if (memberDescriptor is FunctionDescriptor) {
val bridgesToGenerate = generateBridgesForFunctionDescriptor(memberDescriptor, identity()) {
@@ -397,13 +472,13 @@ class ClassTranslator private constructor(
}
for (bridge in bridgesToGenerate) {
generateBridge(bridge, properties)
generateBridge(bridge)
}
}
}
}
private fun generateBridge(bridge: Bridge<FunctionDescriptor>, properties: MutableList<JsPropertyInitializer>) {
private fun generateBridge(bridge: Bridge<FunctionDescriptor>) {
val fromDescriptor = bridge.from
val toDescriptor = bridge.to
if (areNamesEqual(fromDescriptor, toDescriptor)) return
@@ -411,7 +486,7 @@ class ClassTranslator private constructor(
if (fromDescriptor.kind.isReal && fromDescriptor.modality != Modality.ABSTRACT && !toDescriptor.kind.isReal)
return
properties += generateDelegateCall(fromDescriptor, toDescriptor, JsLiteral.THIS, context())
generateDelegateCall(descriptor, fromDescriptor, toDescriptor, JsLiteral.THIS, context())
}
private fun areNamesEqual(first: FunctionDescriptor, second: FunctionDescriptor): Boolean {
@@ -421,13 +496,11 @@ class ClassTranslator private constructor(
}
companion object {
@JvmStatic fun translate(classDeclaration: KtClassOrObject, context: TranslationContext): TranslationResult {
@JvmStatic fun translate(classDeclaration: KtClassOrObject, context: TranslationContext) {
return ClassTranslator(classDeclaration, context).translate()
}
}
class TranslationResult(val properties: List<JsPropertyInitializer>, val definitionPlace: DefinitionPlace)
private class ConstructorInfo(
val function: JsFunction,
val context: TranslationContext,
@@ -1,151 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.translate.declaration;
import com.google.dart.compiler.backend.js.ast.*;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.general.Translation;
import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor;
import org.jetbrains.kotlin.js.translate.initializer.ClassInitializerTranslator;
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.types.KotlinType;
import java.util.ArrayList;
import java.util.List;
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getClassDescriptor;
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getFunctionDescriptor;
import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getSupertypesWithoutFakes;
public class DeclarationBodyVisitor extends TranslatorVisitor<Void> {
protected final List<JsPropertyInitializer> result;
private final List<JsPropertyInitializer> staticResult;
private final List<JsPropertyInitializer> enumEntryList = new SmartList<JsPropertyInitializer>();
@NotNull
private final JsScope scope;
@Nullable
private List<JsStatement> initializerStatements;
public DeclarationBodyVisitor(
@NotNull List<JsPropertyInitializer> result, @NotNull List<JsPropertyInitializer> staticResult,
@NotNull JsScope scope
) {
this.result = result;
this.staticResult = staticResult;
this.scope = scope;
}
@NotNull
public List<JsPropertyInitializer> getResult() {
return result;
}
public List<JsPropertyInitializer> getEnumEntryList() {
return enumEntryList;
}
@Override
protected Void emptyResult(@NotNull TranslationContext context) {
return null;
}
@Override
public Void visitClassOrObject(@NotNull KtClassOrObject declaration, TranslationContext context) {
staticResult.addAll(ClassTranslator.translate(declaration, context).getProperties());
if (declaration instanceof KtObjectDeclaration) {
KtObjectDeclaration objectDeclaration = (KtObjectDeclaration) declaration;
if (objectDeclaration.isCompanion()) {
DeclarationDescriptor descriptor = BindingUtils.getDescriptorForElement(context.bindingContext(), declaration);
addInitializerStatement(context.getQualifiedReference(descriptor).makeStmt());
}
}
return null;
}
@Override
public Void visitEnumEntry(@NotNull KtEnumEntry enumEntry, TranslationContext data) {
ClassDescriptor descriptor = getClassDescriptor(data.bindingContext(), enumEntry);
List<KotlinType> supertypes = getSupertypesWithoutFakes(descriptor);
if (enumEntry.getBody() != null || supertypes.size() > 1) {
enumEntryList.addAll(ClassTranslator.translate(enumEntry, data).getProperties());
} else {
assert supertypes.size() == 1 : "Simple Enum entry must have one supertype";
JsExpression jsEnumEntryCreation = new ClassInitializerTranslator(enumEntry, data)
.generateEnumEntryInstanceCreation(supertypes.get(0));
jsEnumEntryCreation = TranslationUtils.simpleReturnFunction(data.scope(), jsEnumEntryCreation);
enumEntryList.add(new JsPropertyInitializer(data.getNameForDescriptor(descriptor).makeRef(), jsEnumEntryCreation));
}
return null;
}
@Override
public Void visitNamedFunction(@NotNull KtNamedFunction expression, TranslationContext context) {
FunctionDescriptor descriptor = getFunctionDescriptor(context.bindingContext(), expression);
if (descriptor.getModality() == Modality.ABSTRACT) {
return null;
}
context = context.newDeclaration(descriptor, context.getDefinitionPlace());
JsPropertyInitializer methodAsPropertyInitializer = Translation.functionTranslator(expression, context).translateAsMethod();
result.add(methodAsPropertyInitializer);
return null;
}
@Override
public Void visitProperty(@NotNull KtProperty expression, TranslationContext context) {
PropertyDescriptor propertyDescriptor = BindingUtils.getPropertyDescriptor(context.bindingContext(), expression);
context = context.newDeclaration(propertyDescriptor, context.getDefinitionPlace());
PropertyTranslatorKt.translateAccessors(propertyDescriptor, expression, result, context);
return null;
}
@Override
public Void visitAnonymousInitializer(@NotNull KtAnonymousInitializer expression, TranslationContext context) {
// parsed it in initializer visitor => no additional actions are needed
return null;
}
@Override
public Void visitSecondaryConstructor(@NotNull KtSecondaryConstructor constructor, TranslationContext data) {
return null;
}
private void addInitializerStatement(@NotNull JsStatement statement) {
if (initializerStatements == null) {
initializerStatements = new ArrayList<JsStatement>();
JsFunction initializerFunction = new JsFunction(scope, new JsBlock(initializerStatements), "class initializer");
staticResult.add(new JsPropertyInitializer(new JsNameRef("object_initializer$"), initializerFunction));
}
initializerStatements.add(statement);
}
@Override
public Void visitTypeAlias(@NotNull KtTypeAlias typeAlias, TranslationContext data) {
// Resolved by front-end, not used by backend
return null;
}
}
@@ -0,0 +1,116 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.translate.declaration
import com.google.dart.compiler.backend.js.ast.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.initializer.ClassInitializerTranslator
import org.jetbrains.kotlin.js.translate.utils.*
import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getClassDescriptor
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getSupertypesWithoutFakes
import org.jetbrains.kotlin.psi.*
import java.util.*
class DeclarationBodyVisitor(
private val containingClass: ClassDescriptor,
private val context: TranslationContext
) : AbstractDeclarationVisitor() {
private var enumEntryOrdinal: Int = 0
val initializerStatements = ArrayList<JsStatement>()
override fun visitClassOrObject(classOrObject: KtClassOrObject, context: TranslationContext) {
super.visitClassOrObject(classOrObject, context)
if (classOrObject is KtObjectDeclaration) {
if (classOrObject.isCompanion()) {
val descriptor = BindingUtils.getDescriptorForElement(context.bindingContext(), classOrObject) as ClassDescriptor
addInitializerStatement(JsInvocation(context.getNameForObjectInstance(descriptor).makeRef()).makeStmt())
}
}
}
override fun visitEnumEntry(enumEntry: KtEnumEntry, context: TranslationContext) {
val descriptor = getClassDescriptor(context.bindingContext(), enumEntry)
val supertypes = getSupertypesWithoutFakes(descriptor)
if (enumEntry.getBody() != null || supertypes.size > 1) {
ClassTranslator.translate(enumEntry, context)
}
else {
// Simplify by omitting _getInstance() function
val enumName = context.getInnerNameForDescriptor(descriptor)
val enumInstanceName = context.createGlobalName(enumName.ident + "_instance")
assert(supertypes.size == 1) { "Simple Enum entry must have one supertype" }
val jsEnumEntryCreation = ClassInitializerTranslator
.generateEnumEntryInstanceCreation(context, supertypes[0], enumEntry, enumEntryOrdinal)
val jsEnumEntryFunction = context.createTopLevelAnonymousFunction(descriptor)
jsEnumEntryFunction.body.statements.add(JsReturn(jsEnumEntryCreation))
val enumInstanceFunction = context.createTopLevelAnonymousFunction(descriptor)
enumInstanceFunction.name = context.getNameForObjectInstance(descriptor)
context.addRootStatement(enumInstanceFunction.makeStmt())
val classRef = context.getInnerReference(descriptor.containingDeclaration)
val enumExtName = context.getNameForDescriptor(descriptor)
val enumExtFq = JsNameRef(enumExtName, classRef)
context.addRootStatement(JsAstUtils.assignment(enumExtFq, enumInstanceFunction.name.makeRef()).makeStmt())
context.addRootStatement(JsAstUtils.newVar(enumInstanceName, jsEnumEntryCreation))
enumInstanceFunction.body.statements.add(JsReturn(enumInstanceName.makeRef()))
}
enumEntryOrdinal++
}
override fun visitAnonymousInitializer(expression: KtAnonymousInitializer, context: TranslationContext) {
// parsed it in initializer visitor => no additional actions are needed
}
override fun visitSecondaryConstructor(constructor: KtSecondaryConstructor, data: TranslationContext) { }
private fun addInitializerStatement(statement: JsStatement) {
initializerStatements.add(statement)
}
override fun addClass(descriptor: ClassDescriptor) {
//context.export(descriptor)
}
override fun addFunction(descriptor: FunctionDescriptor, expression: JsExpression) {
context.addFunctionToPrototype(containingClass, descriptor, expression)
}
override fun addProperty(descriptor: PropertyDescriptor, getter: JsExpression, setter: JsExpression?) {
if (!JsDescriptorUtils.isSimpleFinalProperty(descriptor)) {
val literal = JsObjectLiteral(true)
literal.propertyInitializers += JsPropertyInitializer(context.program().getStringLiteral("get"), getter)
if (setter != null) {
literal.propertyInitializers += JsPropertyInitializer(context.program().getStringLiteral("set"), setter)
}
context.addAccessorsToPrototype(containingClass, descriptor, literal)
}
}
override fun getBackingFieldReference(descriptor: PropertyDescriptor): JsExpression {
return Namer.getDelegateNameRef(descriptor.name.asString())
}
}
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.js.translate.declaration
import com.google.dart.compiler.backend.js.ast.*
import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.descriptors.*
@@ -25,15 +24,14 @@ import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
import org.jetbrains.kotlin.js.translate.general.Translation
import org.jetbrains.kotlin.js.translate.utils.BindingUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.*
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunction
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateFunctionAsEcma5PropertyDescriptor
import org.jetbrains.kotlin.js.translate.utils.generateDelegateCall
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
import org.jetbrains.kotlin.psi.KtSuperTypeListEntry
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
class DelegationTranslator(
classDeclaration: KtClassOrObject,
@@ -53,7 +51,6 @@ class DelegationTranslator(
for (specifier in delegationBySpecifiers) {
val expression = specifier.delegateExpression ?:
throw IllegalArgumentException("delegate expression should not be null: ${specifier.text}")
val descriptor = getSuperClass(specifier)
val propertyDescriptor = CodegenUtil.getDelegatePropertyIfAny(expression, classDescriptor, bindingContext())
if (CodegenUtil.isFinalPropertyWithBackingField(propertyDescriptor, bindingContext())) {
@@ -84,22 +81,22 @@ class DelegationTranslator(
}
}
fun generateDelegated(properties: MutableList<JsPropertyInitializer>) {
fun generateDelegated() {
for (specifier in delegationBySpecifiers) {
generateDelegates(getSuperClass(specifier), fields[specifier]!!, properties)
generateDelegates(getSuperClass(specifier), fields[specifier]!!)
}
}
private fun getSuperClass(specifier: KtSuperTypeListEntry): ClassDescriptor =
CodegenUtil.getSuperClassBySuperTypeListEntry(specifier, bindingContext())
private fun generateDelegates(toClass: ClassDescriptor, field: Field, properties: MutableList<JsPropertyInitializer>) {
private fun generateDelegates(toClass: ClassDescriptor, field: Field) {
for ((descriptor, overriddenDescriptor) in CodegenUtil.getDelegates(classDescriptor, toClass)) {
when (descriptor) {
is PropertyDescriptor ->
generateDelegateCallForPropertyMember(descriptor, field.name, properties)
generateDelegateCallForPropertyMember(descriptor, field.name)
is FunctionDescriptor ->
generateDelegateCallForFunctionMember(descriptor, overriddenDescriptor as FunctionDescriptor, field.name, properties)
generateDelegateCallForFunctionMember(descriptor, overriddenDescriptor as FunctionDescriptor, field.name)
else ->
throw IllegalArgumentException("Expected property or function $descriptor")
}
@@ -108,8 +105,7 @@ class DelegationTranslator(
private fun generateDelegateCallForPropertyMember(
descriptor: PropertyDescriptor,
delegateName: JsName,
properties: MutableList<JsPropertyInitializer>
delegateName: JsName
) {
val propertyName: String = descriptor.name.asString()
@@ -174,17 +170,29 @@ class DelegationTranslator(
return generateDelegateAccessor(setterDescriptor, generateDelegateSetterFunction(setterDescriptor))
}
properties.addGetterAndSetter(descriptor, context(), ::generateDelegateGetter, ::generateDelegateSetter)
// TODO: same logic as in AbstractDeclarationVisitor
if (descriptor.isExtensionProperty || TranslationUtils.shouldAccessViaFunctions(descriptor)) {
val getter = descriptor.getter!!
context().addFunctionToPrototype(classDescriptor, getter, generateDelegateGetterFunction(getter))
if (descriptor.isVar) {
val setter = descriptor.setter!!
context().addFunctionToPrototype(classDescriptor, setter, generateDelegateSetterFunction(setter))
}
}
else {
val literal = JsObjectLiteral(true)
literal.propertyInitializers.addGetterAndSetter(descriptor, ::generateDelegateGetter, ::generateDelegateSetter)
context().addAccessorsToPrototype(classDescriptor, descriptor, literal)
}
}
private fun generateDelegateCallForFunctionMember(
descriptor: FunctionDescriptor,
overriddenDescriptor: FunctionDescriptor,
delegateName: JsName,
properties: MutableList<JsPropertyInitializer>
delegateName: JsName
) {
val delegateRef = JsNameRef(delegateName, JsLiteral.THIS)
properties.add(generateDelegateCall(descriptor, overriddenDescriptor, delegateRef, context()))
generateDelegateCall(classDescriptor, descriptor, overriddenDescriptor, delegateRef, context())
}
}
@@ -1,71 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.translate.declaration
import com.google.dart.compiler.backend.js.ast.JsFunction
import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer
import com.google.dart.compiler.backend.js.ast.JsScope
import com.intellij.util.SmartList
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.general.Translation
import org.jetbrains.kotlin.js.translate.initializer.InitializerUtils.generateInitializerForDelegate
import org.jetbrains.kotlin.js.translate.initializer.InitializerUtils.generateInitializerForProperty
import org.jetbrains.kotlin.js.translate.initializer.InitializerVisitor
import org.jetbrains.kotlin.js.translate.utils.BindingUtils.getPropertyDescriptor
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.psi.*
class FileDeclarationVisitor(
val context: TranslationContext,
scope: JsScope,
initializers: List<JsPropertyInitializer> = SmartList()
) : DeclarationBodyVisitor(initializers, SmartList(), scope) {
private val initializer = JsAstUtils.createFunctionWithEmptyBody(context.scope())
private val initializerContext = context.contextWithScope(initializer).innerBlock(initializer.body)
private val initializerVisitor = InitializerVisitor()
fun computeInitializer(): JsFunction? {
return if (initializer.body.statements.isNotEmpty()) initializer else null
}
override fun visitClassOrObject(declaration: KtClassOrObject, context: TranslationContext?): Void? {
result += ClassTranslator.translate(declaration, context!!).properties
return null
}
override fun visitProperty(expression: KtProperty, context: TranslationContext?): Void? {
context!! // hack
super.visitProperty(expression, context)
val initializer = expression.initializer
if (initializer != null) {
val value = Translation.translateAsExpression(initializer, initializerContext)
val propertyDescriptor: PropertyDescriptor = getPropertyDescriptor(context.bindingContext(), expression)
this.initializer.body.statements += generateInitializerForProperty(context, propertyDescriptor, value)
}
generateInitializerForDelegate(context, expression)?.let { this.initializer.body.statements += it }
return null
}
override fun visitAnonymousInitializer(expression: KtAnonymousInitializer, context: TranslationContext?): Void? {
expression.accept(initializerVisitor, initializerContext)
return null
}
}
@@ -0,0 +1,82 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.js.translate.declaration
import com.google.dart.compiler.backend.js.ast.JsExpression
import com.google.dart.compiler.backend.js.ast.JsFunction
import com.google.dart.compiler.backend.js.ast.JsName
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.general.Translation
import org.jetbrains.kotlin.js.translate.utils.BindingUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.resolve.BindingContext
class FileDeclarationVisitor(private val context: TranslationContext) : AbstractDeclarationVisitor() {
override fun visitProperty(expression: KtProperty, context: TranslationContext) {
val propertyDescriptor = BindingUtils.getPropertyDescriptor(context.bindingContext(), expression)
val innerName = context.getInnerNameForDescriptor(propertyDescriptor)
val backingFieldRequired = context.bindingContext()[BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor] ?: false
if (backingFieldRequired || expression.delegateExpression != null) {
val initializer = expression.delegateExpressionOrInitializer?.let { Translation.translateAsExpression(it, context) }
context.addRootStatement(JsAstUtils.newVar(innerName, initializer))
}
super.visitProperty(expression, context)
}
override fun addClass(descriptor: ClassDescriptor) {
context.export(descriptor)
}
override fun addFunction(descriptor: FunctionDescriptor, expression: JsExpression) {
addFunctionButNotExport(descriptor, expression)
context.export(descriptor)
}
override fun addProperty(descriptor: PropertyDescriptor, getter: JsExpression, setter: JsExpression?) {
if (!JsDescriptorUtils.isSimpleFinalProperty(descriptor)) {
addFunctionButNotExport(descriptor.getter!!, getter)
if (setter != null) {
addFunctionButNotExport(descriptor.setter!!, setter)
}
}
context.export(descriptor)
}
override fun getBackingFieldReference(descriptor: PropertyDescriptor): JsExpression {
return context.getInnerReference(descriptor)
}
private fun addFunctionButNotExport(descriptor: FunctionDescriptor, expression: JsExpression): JsName {
val name = context.getInnerNameForDescriptor(descriptor)
when (expression) {
is JsFunction -> {
expression.name = name
context.addRootStatement(expression.makeStmt())
}
else -> {
context.addRootStatement(JsAstUtils.newVar(name, expression))
}
}
return name
}
}
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.js.translate.context.Namer;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.js.translate.utils.UtilsKt;
import org.jetbrains.kotlin.psi.KtClassOrObject;
import org.jetbrains.kotlin.psi.KtParameter;
import org.jetbrains.kotlin.resolve.BindingContext;
@@ -37,12 +38,10 @@ import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.or;
class JsDataClassGenerator extends DataClassMethodGenerator {
private final TranslationContext context;
private final List<? super JsPropertyInitializer> output;
JsDataClassGenerator(KtClassOrObject klass, TranslationContext context, List<? super JsPropertyInitializer> output) {
JsDataClassGenerator(KtClassOrObject klass, TranslationContext context) {
super(klass, context.bindingContext());
this.context = context;
this.output = output;
}
@Override
@@ -94,7 +93,7 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
ClassDescriptor classDescriptor = (ClassDescriptor) function.getContainingDeclaration();
ClassConstructorDescriptor constructor = classDescriptor.getConstructors().iterator().next();
JsExpression constructorRef = context.getQualifiedReference(constructor);
JsExpression constructorRef = context.getInnerReference(constructor);
JsExpression returnExpression = new JsNew(constructorRef, constructorArguments);
if (context.shouldBeDeferred(constructor)) {
@@ -190,11 +189,9 @@ class JsDataClassGenerator extends DataClassMethodGenerator {
}
private JsFunction generateJsMethod(@NotNull FunctionDescriptor functionDescriptor) {
JsName functionName = context.getNameForDescriptor(functionDescriptor);
JsScope enclosingScope = context.scope();
JsFunction functionObject = JsAstUtils.createFunctionWithEmptyBody(enclosingScope);
JsPropertyInitializer initializer = new JsPropertyInitializer(functionName.makeRef(), functionObject);
output.add(initializer);
JsFunction functionObject = context.createTopLevelAnonymousFunction(functionDescriptor);
ClassDescriptor containingClass = (ClassDescriptor) functionDescriptor.getContainingDeclaration();
UtilsKt.addFunctionToPrototype(context, containingClass, functionDescriptor, functionObject);
return functionObject;
}
}
@@ -16,30 +16,22 @@
package org.jetbrains.kotlin.js.translate.declaration;
import com.google.dart.compiler.backend.js.ast.*;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
import org.jetbrains.kotlin.js.facade.exceptions.TranslationRuntimeException;
import org.jetbrains.kotlin.js.translate.context.Namer;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import java.util.*;
import static com.google.dart.compiler.backend.js.ast.JsVars.JsVar;
import java.util.Collection;
public final class PackageDeclarationTranslator extends AbstractTranslator {
private final Iterable<KtFile> files;
private final Map<PackageFragmentDescriptor, PackageTranslator> packageFragmentToTranslator =
new LinkedHashMap<PackageFragmentDescriptor, PackageTranslator>();
public static List<JsStatement> translateFiles(@NotNull Collection<KtFile> files, @NotNull TranslationContext context) {
return new PackageDeclarationTranslator(files, context).translate();
public static void translateFiles(@NotNull Collection<KtFile> files, @NotNull TranslationContext context) {
new PackageDeclarationTranslator(files, context).translate();
}
private PackageDeclarationTranslator(@NotNull Iterable<KtFile> files, @NotNull TranslationContext context) {
@@ -48,21 +40,12 @@ public final class PackageDeclarationTranslator extends AbstractTranslator {
this.files = files;
}
@NotNull
private List<JsStatement> translate() {
// predictable order
Map<FqName, DefineInvocation> packageFqNameToDefineInvocation = new THashMap<FqName, DefineInvocation>();
private void translate() {
for (KtFile file : files) {
PackageFragmentDescriptor packageFragment =
BindingContextUtils.getNotNull(context().bindingContext(), BindingContext.FILE_TO_PACKAGE_FRAGMENT, file);
PackageTranslator translator = packageFragmentToTranslator.get(packageFragment);
if (translator == null) {
createRootPackageDefineInvocationIfNeeded(packageFqNameToDefineInvocation);
translator = PackageTranslator.create(packageFragment, context());
packageFragmentToTranslator.put(packageFragment, translator);
}
PackageTranslator translator = PackageTranslator.create(packageFragment, context());
try {
translator.translate(file);
@@ -77,26 +60,5 @@ public final class PackageDeclarationTranslator extends AbstractTranslator {
throw new TranslationRuntimeException(file, e);
}
}
for (PackageTranslator translator : packageFragmentToTranslator.values()) {
translator.add(packageFqNameToDefineInvocation);
}
JsVars vars = new JsVars(true);
vars.addIfHasInitializer(getRootPackageDeclaration(packageFqNameToDefineInvocation.get(FqName.ROOT)));
return Collections.<JsStatement>singletonList(vars);
}
private void createRootPackageDefineInvocationIfNeeded(@NotNull Map<FqName, DefineInvocation> packageFqNameToDefineInvocation) {
if (!packageFqNameToDefineInvocation.containsKey(FqName.ROOT)) {
packageFqNameToDefineInvocation.put(
FqName.ROOT, DefineInvocation.create(FqName.ROOT, null, new JsObjectLiteral(true), context()));
}
}
private JsVar getRootPackageDeclaration(@NotNull DefineInvocation defineInvocation) {
JsExpression rootPackageVar = new JsInvocation(context().namer().rootPackageDefinitionMethodReference(), defineInvocation.asList());
return new JsVar(context().scope().declareName(Namer.getRootPackageName()), rootPackageVar);
}
}
@@ -16,51 +16,32 @@
package org.jetbrains.kotlin.js.translate.declaration;
import com.google.dart.compiler.backend.js.ast.*;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
import org.jetbrains.kotlin.js.translate.context.DefinitionPlace;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.KtDeclaration;
import org.jetbrains.kotlin.psi.KtFile;
import java.util.List;
import java.util.Map;
final class PackageTranslator extends AbstractTranslator {
static PackageTranslator create(
@NotNull PackageFragmentDescriptor descriptor,
@NotNull TranslationContext context
) {
JsScope scope = context.getScopeForDescriptor(descriptor);
JsNameRef reference = context.getQualifiedReference(descriptor);
SmartList<JsPropertyInitializer> properties = new SmartList<JsPropertyInitializer>();
DefinitionPlace definitionPlace = new DefinitionPlace((JsObjectScope) scope, reference, properties);
TranslationContext newContext = context.newDeclaration(descriptor, definitionPlace);
FileDeclarationVisitor visitor = new FileDeclarationVisitor(newContext, scope, definitionPlace.getProperties());
return new PackageTranslator(descriptor, newContext, visitor);
TranslationContext newContext = context.newDeclaration(descriptor);
FileDeclarationVisitor visitor = new FileDeclarationVisitor(newContext);
return new PackageTranslator(newContext, visitor);
}
@NotNull
private final PackageFragmentDescriptor descriptor;
private final FileDeclarationVisitor visitor;
private PackageTranslator(
@NotNull PackageFragmentDescriptor descriptor,
@NotNull TranslationContext context,
@NotNull FileDeclarationVisitor visitor
) {
super(context);
this.descriptor = descriptor;
this.visitor = visitor;
}
@@ -71,69 +52,4 @@ final class PackageTranslator extends AbstractTranslator {
}
}
}
private void createDefinitionPlace(
@Nullable JsExpression initializer,
Map<FqName, DefineInvocation> packageFqNameToDefineInvocation
) {
FqName fqName = descriptor.getFqName();
DefineInvocation place = DefineInvocation.create(fqName, initializer, new JsObjectLiteral(visitor.getResult(), true), context());
packageFqNameToDefineInvocation.put(fqName, place);
addToParent(fqName.parent(), getEntry(fqName, place), packageFqNameToDefineInvocation);
}
public void add(@NotNull Map<FqName, DefineInvocation> packageFqNameToDefineInvocation) {
JsExpression initializer = visitor.computeInitializer();
DefineInvocation defineInvocation = packageFqNameToDefineInvocation.get(descriptor.getFqName());
if (defineInvocation == null) {
if (initializer != null || !visitor.getResult().isEmpty()) {
createDefinitionPlace(initializer, packageFqNameToDefineInvocation);
}
}
else {
if (initializer != null) {
assert defineInvocation.getInitializer() == JsLiteral.NULL;
defineInvocation.setInitializer(initializer);
}
List<JsPropertyInitializer> listFromPlace = defineInvocation.getMembers();
// if equals, so, inner functions was added
if (listFromPlace != visitor.getResult()) {
listFromPlace.addAll(visitor.getResult());
}
}
}
private JsPropertyInitializer getEntry(@NotNull FqName fqName, DefineInvocation defineInvocation) {
return new JsPropertyInitializer(context().getNameForPackage(fqName).makeRef(),
new JsInvocation(context().namer().packageDefinitionMethodReference(), defineInvocation.asList()));
}
private static boolean addEntryIfParentExists(
FqName parentFqName,
JsPropertyInitializer entry,
Map<FqName, DefineInvocation> packageFqNameToDeclarationPlace
) {
DefineInvocation parentDefineInvocation = packageFqNameToDeclarationPlace.get(parentFqName);
if (parentDefineInvocation != null) {
parentDefineInvocation.getMembers().add(entry);
return true;
}
return false;
}
private void addToParent(@NotNull FqName parentFqName,
JsPropertyInitializer entry,
Map<FqName, DefineInvocation> packageFqNameToDefineInvocation) {
while (!addEntryIfParentExists(parentFqName, entry, packageFqNameToDefineInvocation)) {
JsObjectLiteral members = new JsObjectLiteral(new SmartList<JsPropertyInitializer>(entry), true);
DefineInvocation defineInvocation = DefineInvocation.create(parentFqName, null, members, context());
entry = getEntry(parentFqName, defineInvocation);
packageFqNameToDefineInvocation.put(parentFqName, defineInvocation);
parentFqName = parentFqName.parent();
}
}
}
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.js.translate.declaration
import com.google.dart.compiler.backend.js.ast.*
import com.intellij.util.SmartList
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.LocalVariableAccessorDescriptor
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
@@ -27,12 +26,10 @@ import org.jetbrains.kotlin.js.translate.context.Namer.getReceiverParameterName
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator
import org.jetbrains.kotlin.js.translate.general.Translation
import org.jetbrains.kotlin.js.translate.utils.BindingUtils
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.assignmentToBackingField
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.backingFieldReference
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateFunctionAsEcma5PropertyDescriptor
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.*
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.addParameter
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.addStatement
import org.jetbrains.kotlin.psi.KtProperty
@@ -68,87 +65,40 @@ fun translateAccessors(
fun MutableList<JsPropertyInitializer>.addGetterAndSetter(
descriptor: VariableDescriptorWithAccessors,
context: TranslationContext,
generateGetter: () -> JsPropertyInitializer,
generateSetter: () -> JsPropertyInitializer
) {
val to: MutableList<JsPropertyInitializer>
if (!descriptor.isExtension && !TranslationUtils.shouldGenerateAccessors(descriptor)) {
to = SmartList<JsPropertyInitializer>()
this.add(JsPropertyInitializer(context.getNameForDescriptor(descriptor).makeRef(), JsObjectLiteral(to, true)))
}
else {
to = this
}
to.add(generateGetter())
add(generateGetter())
if (descriptor.isVar) {
to.add(generateSetter())
add(generateSetter())
}
}
private class PropertyTranslator(
class DefaultPropertyTranslator(
val descriptor: VariableDescriptorWithAccessors,
val declaration: KtProperty?,
context: TranslationContext
context: TranslationContext,
val delegateReference: JsExpression
) : AbstractTranslator(context) {
private val propertyName: String = descriptor.name.asString()
fun translate(result: MutableList<JsPropertyInitializer>) {
result.addGetterAndSetter(descriptor, context(), { generateGetter() }, { generateSetter() })
}
private fun generateGetter(): JsPropertyInitializer =
if (hasCustomGetter()) translateCustomAccessor(getCustomGetterDeclaration()) else generateDefaultGetter()
private fun generateSetter(): JsPropertyInitializer =
if (hasCustomSetter()) translateCustomAccessor(getCustomSetterDeclaration()) else generateDefaultSetter()
private fun hasCustomGetter() = declaration?.getter != null && getCustomGetterDeclaration().hasBody()
private fun hasCustomSetter() = declaration?.setter != null && getCustomSetterDeclaration().hasBody()
private fun getCustomGetterDeclaration(): KtPropertyAccessor =
declaration?.getter ?:
throw IllegalStateException("declaration and getter should not be null descriptor=$descriptor declaration=$declaration")
private fun getCustomSetterDeclaration(): KtPropertyAccessor =
declaration?.setter ?:
throw IllegalStateException("declaration and setter should not be null descriptor=$descriptor declaration=$declaration")
private fun generateDefaultGetter(): JsPropertyInitializer {
val getterDescriptor = descriptor.getter ?: throw IllegalStateException("Getter descriptor should not be null")
return generateDefaultAccessor(getterDescriptor, generateDefaultGetterFunction(getterDescriptor))
}
private fun generateDefaultGetterFunction(getterDescriptor: VariableAccessorDescriptor): JsFunction {
val delegatedCall = bindingContext().get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, getterDescriptor)
fun generateDefaultGetterFunction(getterDescriptor: VariableAccessorDescriptor, function: JsFunction) {
val delegatedCall = bindingContext()[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, getterDescriptor]
if (delegatedCall != null) {
return generateDelegatedGetterFunction(getterDescriptor, delegatedCall)
return generateDelegatedGetterFunction(getterDescriptor, delegatedCall, function)
}
assert(!descriptor.isExtension) { "Unexpected extension property $descriptor}" }
assert(descriptor is PropertyDescriptor) { "Property descriptor expected: $descriptor" }
val scope = context().getScopeForDescriptor(getterDescriptor.containingDeclaration)
val result = backingFieldReference(context(), descriptor as PropertyDescriptor)
val body = JsBlock(JsReturn(result))
return JsFunction(scope, body, accessorDescription(getterDescriptor))
function.body.statements += JsReturn(result)
}
private fun generateDelegatedGetterFunction(
getterDescriptor: VariableAccessorDescriptor,
delegatedCall: ResolvedCall<FunctionDescriptor>
): JsFunction {
val scope = context().getScopeForDescriptor(getterDescriptor.containingDeclaration)
val function = JsFunction(scope, JsBlock(), accessorDescription(getterDescriptor))
val delegateRef = getDelegateNameRef(propertyName)
val delegatedJsCall = CallTranslator.translate(
contextWithPropertyMetadataCreationIntrinsified(context(), delegatedCall, getterDescriptor), delegatedCall, delegateRef
)
getterDescriptor: VariableAccessorDescriptor,
delegatedCall: ResolvedCall<FunctionDescriptor>,
function: JsFunction
) {
val delegateContext = contextWithPropertyMetadataCreationIntrinsified(context(), delegatedCall, getterDescriptor)
val delegatedJsCall = CallTranslator.translate(delegateContext, delegatedCall, delegateReference)
if (getterDescriptor.isExtension) {
val receiver = function.addParameter(getReceiverParameterName()).name
@@ -158,40 +108,18 @@ private class PropertyTranslator(
val returnResult = JsReturn(delegatedJsCall)
function.addStatement(returnResult)
return function
}
private fun contextWithPropertyMetadataCreationIntrinsified(
context: TranslationContext, delegatedCall: ResolvedCall<FunctionDescriptor>, accessor: VariableAccessorDescriptor
): TranslationContext {
val propertyNameLiteral = context.program().getStringLiteral(accessor.correspondingVariable.name.asString())
// 0th argument is instance, 1st is KProperty, 2nd (for setter) is value
val fakeArgumentExpression =
(delegatedCall.valueArgumentsByIndex!![1] as ExpressionValueArgument).valueArgument!!.getArgumentExpression()
return context.innerContextWithAliasesForExpressions(mapOf(
fakeArgumentExpression to JsNew(pureFqn("PropertyMetadata", Namer.kotlinObject()), listOf(propertyNameLiteral))
))
}
private fun generateDefaultSetter(): JsPropertyInitializer {
val setterDescriptor = descriptor.setter ?: throw IllegalStateException("Setter descriptor should not be null")
return generateDefaultAccessor(setterDescriptor, generateDefaultSetterFunction(setterDescriptor))
}
private fun generateDefaultSetterFunction(setterDescriptor: VariableAccessorDescriptor): JsFunction {
val function = JsFunction(context().program().rootScope, JsBlock(), accessorDescription(setterDescriptor))
fun generateDefaultSetterFunction(setterDescriptor: VariableAccessorDescriptor, function: JsFunction) {
assert(setterDescriptor.valueParameters.size == 1) { "Setter must have 1 parameter" }
val correspondingPropertyName = setterDescriptor.correspondingVariable.name.asString()
val valueParameter = function.addParameter(correspondingPropertyName).name
val withAliased = context().innerContextWithAliased(setterDescriptor.valueParameters[0], valueParameter.makeRef())
val delegatedCall = context().bindingContext().get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, setterDescriptor)
val delegatedCall = bindingContext()[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, setterDescriptor]
if (delegatedCall != null) {
val delegatedJsCall = CallTranslator.translate(
contextWithPropertyMetadataCreationIntrinsified(withAliased, delegatedCall, setterDescriptor),
delegatedCall, getDelegateNameRef(correspondingPropertyName)
)
val delegateContext = contextWithPropertyMetadataCreationIntrinsified(withAliased, delegatedCall, setterDescriptor)
val delegatedJsCall = CallTranslator.translate(delegateContext, delegatedCall, delegateReference)
function.addStatement(delegatedJsCall.makeStmt())
if (setterDescriptor.isExtension) {
@@ -205,15 +133,79 @@ private class PropertyTranslator(
val assignment = assignmentToBackingField(withAliased, descriptor as PropertyDescriptor, valueParameter.makeRef())
function.addStatement(assignment.makeStmt())
}
}
return function
private fun contextWithPropertyMetadataCreationIntrinsified(
context: TranslationContext, delegatedCall: ResolvedCall<FunctionDescriptor>, accessor: VariableAccessorDescriptor
): TranslationContext {
val propertyNameLiteral = context.program().getStringLiteral(accessor.correspondingVariable.name.asString())
// 0th argument is instance, 1st is KProperty, 2nd (for setter) is value
val fakeArgumentExpression =
(delegatedCall.valueArgumentsByIndex!![1] as ExpressionValueArgument).valueArgument!!.getArgumentExpression()
return context.innerContextWithAliasesForExpressions(mapOf(
fakeArgumentExpression to JsNew(pureFqn("PropertyMetadata", Namer.kotlinObject()), listOf(propertyNameLiteral))
))
}
}
fun KtProperty.hasCustomGetter() = getter?.hasBody() ?: false
fun KtProperty.hasCustomSetter() = setter?.hasBody() ?: false
private class PropertyTranslator(
val descriptor: VariableDescriptorWithAccessors,
val declaration: KtProperty?,
context: TranslationContext
) : AbstractTranslator(context) {
fun translate(result: MutableList<JsPropertyInitializer>) {
result.addGetterAndSetter(descriptor, { generateGetter() }, { generateSetter() })
}
private fun generateGetter(): JsPropertyInitializer =
if (declaration?.hasCustomGetter() ?: false) translateCustomAccessor(getCustomGetterDeclaration()) else generateDefaultGetter()
private fun generateSetter(): JsPropertyInitializer =
if (declaration?.hasCustomSetter() ?: false) translateCustomAccessor(getCustomSetterDeclaration()) else generateDefaultSetter()
private fun getCustomGetterDeclaration(): KtPropertyAccessor =
declaration?.getter ?:
throw IllegalStateException("declaration and getter should not be null descriptor=$descriptor declaration=$declaration")
private fun getCustomSetterDeclaration(): KtPropertyAccessor =
declaration?.setter ?:
throw IllegalStateException("declaration and setter should not be null descriptor=$descriptor declaration=$declaration")
private fun generateDefaultGetter(): JsPropertyInitializer {
val getterDescriptor = descriptor.getter ?: throw IllegalStateException("Getter descriptor should not be null")
val defaultFunction = createFunction(getterDescriptor).apply {
val delegateRef = getDelegateNameRef(descriptor.name.asString())
DefaultPropertyTranslator(descriptor, context(), delegateRef).generateDefaultGetterFunction(getterDescriptor, this)
}
return generateDefaultAccessor(getterDescriptor, defaultFunction)
}
private fun generateDefaultSetter(): JsPropertyInitializer {
val setterDescriptor = descriptor.setter ?: throw IllegalStateException("Setter descriptor should not be null")
val defaultFunction = createFunction(setterDescriptor).apply {
val delegateRef = getDelegateNameRef(descriptor.name.asString())
DefaultPropertyTranslator(descriptor, context(), delegateRef).generateDefaultSetterFunction(setterDescriptor, this)
}
return generateDefaultAccessor(setterDescriptor, defaultFunction)
}
private fun generateDefaultAccessor(accessorDescriptor: VariableAccessorDescriptor, function: JsFunction): JsPropertyInitializer =
translateFunctionAsEcma5PropertyDescriptor(function, accessorDescriptor, context())
private fun translateCustomAccessor(expression: KtPropertyAccessor): JsPropertyInitializer =
Translation.functionTranslator(expression, context()).translateAsEcma5PropertyDescriptor()
private fun translateCustomAccessor(expression: KtPropertyAccessor): JsPropertyInitializer {
val descriptor = BindingUtils.getFunctionDescriptor(bindingContext(), expression)
val function = JsFunction(context().getScopeForDescriptor(descriptor), JsBlock(), descriptor.toString())
return Translation.functionTranslator(expression, context(), function).translateAsEcma5PropertyDescriptor()
}
private fun createFunction(descriptor: VariableAccessorDescriptor) =
JsFunction(context().getScopeForDescriptor(descriptor), JsBlock(), accessorDescription(descriptor))
private fun accessorDescription(accessorDescriptor: VariableAccessorDescriptor): String {
val accessorType =
@@ -201,13 +201,12 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
if (delegateExpression != null) {
SmartList<JsPropertyInitializer> propertyInitializers = new SmartList<JsPropertyInitializer>();
PropertyTranslatorKt.translateAccessors((VariableDescriptorWithAccessors) descriptor, propertyInitializers, context);
assert propertyInitializers.size() == 1 : descriptor;
initializer = propertyInitializers.get(0).getValueExpr();
JsPropertyInitializer delegateInitializer = new JsPropertyInitializer(
context.program().getStringLiteral(Namer.getDelegateName(descriptor.getName().asString())),
Translation.translateAsExpression(delegateExpression, context)
);
((JsObjectLiteral) initializer).getPropertyInitializers().add(delegateInitializer);
propertyInitializers.add(delegateInitializer);
initializer = new JsObjectLiteral(propertyInitializers, true);
}
JsName name = context.getNameForDescriptor(descriptor);
@@ -519,11 +518,9 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@NotNull
public JsNode visitObjectLiteralExpression(@NotNull KtObjectLiteralExpression expression, @NotNull TranslationContext context) {
ClassDescriptor descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), expression.getObjectDeclaration());
ClassTranslator.TranslationResult result = translateClassOrObject(expression.getObjectDeclaration(), descriptor, context);
List<JsPropertyInitializer> properties = result.getProperties();
context.getDefinitionPlace().getProperties().addAll(properties);
translateClassOrObject(expression.getObjectDeclaration(), descriptor, context);
JsExpression constructor = context.getQualifiedReference(descriptor);
JsExpression constructor = context.getInnerReference(descriptor);
List<DeclarationDescriptor> closure = context.getClassOrConstructorClosure(descriptor);
List<JsExpression> closureArgs = new ArrayList<JsExpression>();
if (closure != null) {
@@ -551,7 +548,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
if (superCall != null) {
assert context.getDeclarationDescriptor() != null : "This expression should be inside declaration: " +
PsiUtilsKt.getTextWithLocation(expression);
TranslationContext superCallContext = context.newDeclaration(context.getDeclarationDescriptor(), result.getDefinitionPlace());
TranslationContext superCallContext = context.newDeclaration(context.getDeclarationDescriptor());
closureArgs.addAll(CallArgumentTranslator.translate(superCall, null, superCallContext).getTranslateArguments());
}
@@ -583,7 +580,7 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
@Override
public JsNode visitClass(@NotNull KtClass klass, TranslationContext context) {
ClassDescriptor descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), klass);
context.getDefinitionPlace().getProperties().addAll(translateClassOrObject(klass, descriptor, context).getProperties());
translateClassOrObject(klass, descriptor, context);
return JsEmpty.INSTANCE;
}
@@ -593,13 +590,13 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
return JsEmpty.INSTANCE;
}
private static ClassTranslator.TranslationResult translateClassOrObject(
private static void translateClassOrObject(
@NotNull KtClassOrObject declaration,
@NotNull ClassDescriptor descriptor,
@NotNull TranslationContext context
) {
JsScope scope = context.getScopeForDescriptor(descriptor);
TranslationContext classContext = context.innerWithUsageTracker(scope, descriptor);
return ClassTranslator.translate(declaration, classContext);
ClassTranslator.translate(declaration, classContext);
}
}
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.js.translate.context.AliasingContext;
import org.jetbrains.kotlin.js.translate.context.Namer;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils;
import org.jetbrains.kotlin.psi.KtDeclarationWithBody;
import org.jetbrains.kotlin.psi.KtLambdaExpression;
@@ -44,9 +45,12 @@ import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.setParameters;
public final class FunctionTranslator extends AbstractTranslator {
@NotNull
public static FunctionTranslator newInstance(@NotNull KtDeclarationWithBody function,
@NotNull TranslationContext context) {
return new FunctionTranslator(function, context);
public static FunctionTranslator newInstance(
@NotNull KtDeclarationWithBody declaration,
@NotNull TranslationContext context,
@NotNull JsFunction function
) {
return new FunctionTranslator(declaration, context, function);
}
@NotNull
@@ -60,11 +64,12 @@ public final class FunctionTranslator extends AbstractTranslator {
@NotNull
private final FunctionDescriptor descriptor;
private FunctionTranslator(@NotNull KtDeclarationWithBody functionDeclaration, @NotNull TranslationContext context) {
private FunctionTranslator(@NotNull KtDeclarationWithBody functionDeclaration, @NotNull TranslationContext context,
@NotNull JsFunction function) {
super(context);
this.descriptor = getFunctionDescriptor(context.bindingContext(), functionDeclaration);
this.functionDeclaration = functionDeclaration;
this.functionObject = context().getFunctionObject(descriptor);
this.functionObject = function;
assert this.functionObject.getParameters().isEmpty()
: message(descriptor, "Function " + functionDeclaration.getText() + " processed for the second time.");
//NOTE: it's important we compute the context before we start the computation
@@ -94,17 +99,21 @@ public final class FunctionTranslator extends AbstractTranslator {
return TranslationUtils.translateFunctionAsEcma5PropertyDescriptor(functionObject, descriptor, context());
}
@NotNull
public JsPropertyInitializer translateAsMethod() {
JsName functionName = context().getNameForDescriptor(descriptor);
public void translateAsMethodWithoutMetadata() {
generateFunctionObject();
}
@NotNull
public JsExpression translateAsMethod() {
translateAsMethodWithoutMetadata();
if (shouldBeInlined(descriptor) && DescriptorUtilsKt.isEffectivelyPublicApi(descriptor)) {
InlineMetadata metadata = InlineMetadata.compose(functionObject, descriptor);
return new JsPropertyInitializer(functionName.makeRef(), metadata.getFunctionWithMetadata());
return metadata.getFunctionWithMetadata();
}
else {
return functionObject;
}
return new JsPropertyInitializer(functionName.makeRef(), functionObject);
}
private void generateFunctionObject() {
@@ -21,6 +21,7 @@ import com.google.dart.compiler.backend.js.ast.metadata.*
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.js.inline.util.getInnerFunction
import org.jetbrains.kotlin.js.inline.util.refreshLabelNames
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.context.getNameForCapturedDescriptor
import org.jetbrains.kotlin.js.translate.context.hasCapturedExceptContaining
@@ -58,18 +59,27 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
val isRecursive = tracker.isCaptured(descriptor)
if (isRecursive) {
lambda.name = tracker.getNameForCapturedDescriptor(descriptor)
lambda.name = if (isRecursive) {
tracker.getNameForCapturedDescriptor(descriptor)
}
else {
context().getInnerNameForDescriptor(descriptor)
}
if (tracker.hasCapturedExceptContaining()) {
val lambdaCreator = simpleReturnFunction(invokingContext.scope(), lambda)
lambdaCreator.name = context().getInnerNameForDescriptor(descriptor)
lambdaCreator.isLocal = true
return lambdaCreator.withCapturedParameters(functionContext, invokingContext, descriptor)
if (!isRecursive) {
lambda.name = null
}
return lambdaCreator.withCapturedParameters(functionContext, invokingContext)
}
lambda.isLocal = true
return invokingContext.define(descriptor, lambda).apply { sideEffects = SideEffectKind.PURE }
context().addRootStatement(lambda.makeStmt())
return lambda.name.makeRef().apply { sideEffects = SideEffectKind.PURE }
}
fun ValueParameterDescriptorImpl.WithDestructuringDeclaration.translate(context: TranslationContext): JsVars {
@@ -82,8 +92,12 @@ class LiteralFunctionTranslator(context: TranslationContext) : AbstractTranslato
}
}
fun JsFunction.withCapturedParameters(context: TranslationContext, invokingContext: TranslationContext, descriptor: MemberDescriptor): JsExpression {
val ref = invokingContext.define(descriptor, this).apply { sideEffects = SideEffectKind.PURE }
fun JsFunction.withCapturedParameters(
context: TranslationContext,
invokingContext: TranslationContext
): JsExpression {
context.addRootStatement(makeStmt())
val ref = name.makeRef().apply { sideEffects = SideEffectKind.PURE }
val invocation = JsInvocation(ref).apply { sideEffects = SideEffectKind.PURE }
val invocationArguments = invocation.arguments
@@ -169,7 +169,7 @@ public final class PatternTranslator extends AbstractTranslator {
ClassDescriptor referencedClass = DescriptorUtils.getClassDescriptorForType(type);
JsNameRef typeName = context().getQualifiedReference(referencedClass);
JsNameRef typeName = context().getInnerReference(referencedClass);
return referencedClass.getKind() != ClassKind.OBJECT ? namer().isInstanceOf(typeName) : namer().isInstanceOfObject(typeName);
}
@@ -48,7 +48,6 @@ import org.jetbrains.kotlin.psi.KtDeclarationWithBody;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.psi.KtNamedFunction;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
@@ -66,7 +65,6 @@ import java.util.List;
import static org.jetbrains.kotlin.js.translate.general.ModuleWrapperTranslation.wrapIfNecessary;
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getFunctionDescriptor;
import static org.jetbrains.kotlin.js.translate.utils.ErrorReportingUtils.message;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.convertToStatement;
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.toStringLiteralList;
import static org.jetbrains.kotlin.js.translate.utils.mutator.LastExpressionMutator.mutateLastExpression;
@@ -81,9 +79,12 @@ public final class Translation {
}
@NotNull
public static FunctionTranslator functionTranslator(@NotNull KtDeclarationWithBody function,
@NotNull TranslationContext context) {
return FunctionTranslator.newInstance(function, context);
public static FunctionTranslator functionTranslator(
@NotNull KtDeclarationWithBody declaration,
@NotNull TranslationContext context,
@NotNull JsFunction function
) {
return FunctionTranslator.newInstance(declaration, context, function);
}
@NotNull
@@ -252,17 +253,16 @@ public final class Translation {
) {
StaticContext staticContext = StaticContext.generateStaticContext(bindingTrace, config, moduleDescriptor);
JsProgram program = staticContext.getProgram();
// Prohibit using "_" as a variable name
program.getRootScope().declareName("_");
JsFunction rootFunction = JsAstUtils.createFunctionWithEmptyBody(program.getScope());
JsFunction rootFunction = staticContext.getRootFunction();
JsBlock rootBlock = rootFunction.getBody();
List<JsStatement> statements = rootBlock.getStatements();
statements.add(program.getStringLiteral("use strict").makeStmt());
TranslationContext context = TranslationContext.rootContext(staticContext, rootFunction);
statements.addAll(PackageDeclarationTranslator.translateFiles(files, context));
PackageDeclarationTranslator.translateFiles(files, context);
staticContext.postProcess();
statements.add(0, program.getStringLiteral("use strict").makeStmt());
defineModule(context, statements, config.getModuleId());
mayBeGenerateTests(files, config, rootBlock, context);
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.js.translate.declaration.DelegationTranslator;
import org.jetbrains.kotlin.js.translate.general.AbstractTranslator;
import org.jetbrains.kotlin.js.translate.reference.CallArgumentTranslator;
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
import org.jetbrains.kotlin.js.translate.utils.BindingUtils;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.js.translate.utils.jsAstUtils.AstUtilsKt;
import org.jetbrains.kotlin.lexer.KtTokens;
@@ -39,9 +40,11 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.types.KotlinType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -56,16 +59,23 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
private final KtClassOrObject classDeclaration;
@NotNull
private final JsFunction initFunction;
@NotNull
private final TranslationContext context;
@NotNull
private final ClassDescriptor classDescriptor;
public ClassInitializerTranslator(
@NotNull KtClassOrObject classDeclaration,
@NotNull TranslationContext context
@NotNull TranslationContext context,
@NotNull JsFunction initFunction
) {
super(context);
this.classDeclaration = classDeclaration;
this.initFunction = createInitFunction(classDeclaration, context);
this.initFunction = initFunction;
this.context = context.contextWithScope(initFunction);
classDescriptor = BindingUtils.getClassDescriptor(bindingContext(), classDeclaration);
fillInitFunction(classDeclaration, context);
}
@NotNull
@@ -74,8 +84,7 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
return context;
}
@NotNull
private static JsFunction createInitFunction(KtClassOrObject declaration, TranslationContext context) {
private static void fillInitFunction(KtClassOrObject declaration, TranslationContext context) {
//TODO: it's inconsistent that we have scope for class and function for constructor, currently have problems implementing better way
ClassDescriptor classDescriptor = getClassDescriptor(context.bindingContext(), declaration);
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
@@ -104,20 +113,16 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
}
ctorFunction.setName(ctorFunction.getScope().declareName(functionName));
}
return ctorFunction;
}
@NotNull
public JsFunction generateInitializeMethod(DelegationTranslator delegationTranslator) {
ClassDescriptor classDescriptor = getClassDescriptor(bindingContext(), classDeclaration);
public void generateInitializeMethod(DelegationTranslator delegationTranslator) {
addOuterClassReference(classDescriptor);
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
if (primaryConstructor != null) {
initFunction.getBody().getStatements().addAll(setDefaultValueForArguments(primaryConstructor, context()));
mayBeAddCallToSuperMethod(initFunction, classDescriptor);
mayBeAddCallToSuperMethod(initFunction);
//NOTE: while we translate constructor parameters we also add property initializer statements
// for properties declared as constructor parameters
@@ -126,8 +131,6 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
delegationTranslator.addInitCode(initFunction.getBody().getStatements());
new InitializerVisitor().traverseContainer(classDeclaration, context().innerBlock(initFunction.getBody()));
return initFunction;
}
private void addOuterClassReference(ClassDescriptor classDescriptor) {
@@ -142,26 +145,33 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
}
@NotNull
public JsExpression generateEnumEntryInstanceCreation(@NotNull KotlinType enumClassType) {
ResolvedCall<FunctionDescriptor> superCall = getSuperCall(bindingContext(), classDeclaration);
public static JsExpression generateEnumEntryInstanceCreation(
@NotNull TranslationContext context,
@NotNull KotlinType enumClassType,
@NotNull KtClassOrObject classDeclaration,
int ordinal
) {
ResolvedCall<FunctionDescriptor> superCall = getSuperCall(context.bindingContext(), classDeclaration);
if (superCall == null) {
ClassDescriptor classDescriptor = getClassDescriptorForType(enumClassType);
JsNameRef reference = context().getQualifiedReference(classDescriptor);
return new JsNew(reference);
JsNameRef reference = context.getInnerReference(classDescriptor);
JsExpression nameArg = context.program().getStringLiteral(classDeclaration.getName());
JsExpression ordinalArg = context.program().getNumberLiteral(ordinal);
return new JsNew(reference, Arrays.asList(nameArg, ordinalArg));
}
return CallTranslator.translate(context(), superCall);
return CallTranslator.translate(context, superCall);
}
private void mayBeAddCallToSuperMethod(JsFunction initializer, @NotNull ClassDescriptor descriptor) {
private void mayBeAddCallToSuperMethod(JsFunction initializer) {
if (classDeclaration.hasModifier(KtTokens.ENUM_KEYWORD)) {
addCallToSuperMethod(Collections.<JsExpression>emptyList(), initializer);
}
else if (hasAncestorClass(bindingContext(), classDeclaration)) {
ResolvedCall<FunctionDescriptor> superCall = getSuperCall(bindingContext(), classDeclaration);
if (superCall == null) {
if (DescriptorUtils.isEnumEntry(descriptor)) {
if (DescriptorUtils.isEnumEntry(classDescriptor)) {
addCallToSuperMethod(Collections.<JsExpression>emptyList(), initializer);
}
return;
@@ -182,18 +192,18 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
if (superclassClosure != null) {
UsageTracker tracker = context.usageTracker();
assert tracker != null : "Closure exists, therefore UsageTracker must exist too. Translating constructor of " +
descriptor;
classDescriptor;
for (DeclarationDescriptor capturedValue : superclassClosure) {
tracker.used(capturedValue);
arguments.add(tracker.getCapturedDescriptorToJsName().get(capturedValue).makeRef());
}
}
if (superDescriptor.getContainingDeclaration().isInner() && descriptor.isInner()) {
if (superDescriptor.getContainingDeclaration().isInner() && classDescriptor.isInner()) {
arguments.add(pureFqn(Namer.OUTER_FIELD_NAME, JsLiteral.THIS));
}
if (!DescriptorUtils.isAnonymousObject(descriptor)) {
if (!DescriptorUtils.isAnonymousObject(classDescriptor)) {
arguments.addAll(CallArgumentTranslator.translate(superCall, null, context()).getTranslateArguments());
}
else {
@@ -225,20 +235,22 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
}
}
private void addCallToSuperMethod(@NotNull List<JsExpression> arguments, JsFunction initializer) {
private void addCallToSuperMethod(@NotNull List<JsExpression> arguments, @NotNull JsFunction initializer) {
if (initializer.getName() == null) {
JsName ref = context().scope().declareName(Namer.CALLEE_NAME);
initializer.setName(ref);
}
JsInvocation call = new JsInvocation(Namer.getFunctionCallRef(Namer.superMethodNameRef(initializer.getName())));
ClassDescriptor superclassDescriptor = DescriptorUtilsKt.getSuperClassOrAny(classDescriptor);
JsExpression superConstructorRef = context().getInnerReference(superclassDescriptor);
JsInvocation call = new JsInvocation(Namer.getFunctionCallRef(superConstructorRef));
call.getArguments().add(JsLiteral.THIS);
call.getArguments().addAll(arguments);
initFunction.getBody().getStatements().add(call.makeStmt());
}
private void addCallToSuperSecondaryConstructor(@NotNull List<JsExpression> arguments, @NotNull ConstructorDescriptor descriptor) {
JsExpression reference = context.getQualifiedReference(descriptor);
JsExpression reference = context.getInnerReference(descriptor);
JsInvocation call = new JsInvocation(reference);
call.getArguments().addAll(arguments);
call.getArguments().add(JsLiteral.THIS);
@@ -257,8 +269,7 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
@NotNull
private JsParameter translateParameter(@NotNull KtParameter jetParameter) {
DeclarationDescriptor parameterDescriptor =
getDescriptorForElement(bindingContext(), jetParameter);
DeclarationDescriptor parameterDescriptor = getDescriptorForElement(bindingContext(), jetParameter);
JsName parameterName = context().getNameForDescriptor(parameterDescriptor);
JsParameter jsParameter = new JsParameter(parameterName);
mayBeAddInitializerStatementForProperty(jsParameter, jetParameter);
@@ -267,8 +278,7 @@ public final class ClassInitializerTranslator extends AbstractTranslator {
private void mayBeAddInitializerStatementForProperty(@NotNull JsParameter jsParameter,
@NotNull KtParameter jetParameter) {
PropertyDescriptor propertyDescriptor =
getPropertyDescriptorForConstructorParameter(bindingContext(), jetParameter);
PropertyDescriptor propertyDescriptor = getPropertyDescriptorForConstructorParameter(bindingContext(), jetParameter);
if (propertyDescriptor == null) {
return;
}
@@ -108,20 +108,20 @@ object CallableReferenceTranslator {
}
private fun translateForExtensionProperty(descriptor: PropertyDescriptor, context: TranslationContext): JsExpression {
val jsGetterNameRef = context.getQualifiedReference(descriptor.getter!!)
val jsGetterNameRef = context.getInnerReference(descriptor.getter!!)
val propertyName = descriptor.name
val jsPropertyNameAsString = context.program().getStringLiteral(propertyName.asString())
val argumentList = ArrayList<JsExpression>(3)
argumentList.add(jsPropertyNameAsString)
argumentList.add(jsGetterNameRef)
if (descriptor.isVar) {
val jsSetterNameRef = context.getQualifiedReference(descriptor.setter!!)
val jsSetterNameRef = context.getInnerReference(descriptor.setter!!)
argumentList.add(jsSetterNameRef)
}
if (AnnotationsUtils.isNativeObject(descriptor))
return translateForMemberProperty(descriptor, context)
return if (AnnotationsUtils.isNativeObject(descriptor))
translateForMemberProperty(descriptor, context)
else
return JsInvocation(context.namer().callableRefForExtensionPropertyReference(), argumentList)
JsInvocation(context.namer().callableRefForExtensionPropertyReference(), argumentList)
}
private fun translateForConstructor(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression {
@@ -130,8 +130,8 @@ object CallableReferenceTranslator {
}
private fun translateForExtensionFunction(descriptor: FunctionDescriptor, context: TranslationContext): JsExpression {
val receiverParameterDescriptor = descriptor.extensionReceiverParameter
assert(receiverParameterDescriptor != null) { "receiverParameter for extension should not be null" }
val receiverParameterDescriptor = descriptor.extensionReceiverParameter ?:
error("receiverParameter for extension should not be null")
val jsFunctionRef = ReferenceTranslator.translateAsFQReference(descriptor, context)
if (descriptor.visibility == Visibilities.LOCAL) {
@@ -139,7 +139,7 @@ object CallableReferenceTranslator {
}
else if (AnnotationsUtils.isNativeObject(descriptor)) {
val jetType = receiverParameterDescriptor!!.type
val jetType = receiverParameterDescriptor.type
val receiverClassDescriptor = DescriptorUtils.getClassDescriptorForType(jetType)
return translateAsMemberFunctionReference(descriptor, receiverClassDescriptor, context)
}
@@ -159,7 +159,12 @@ object CallableReferenceTranslator {
classDescriptor: ClassDescriptor,
context: TranslationContext
): JsExpression {
val jsClassNameRef = context.getQualifiedReference(classDescriptor)
val jsClassNameRef = if (AnnotationsUtils.isNativeObject(classDescriptor)) {
context.getQualifiedReference(classDescriptor)
}
else {
context.getInnerReference(classDescriptor)
}
val funName = context.getNameForDescriptor(descriptor)
val funNameAsString = context.program().getStringLiteral(funName.toString())
return JsInvocation(context.namer().callableRefForMemberFunctionReference(), jsClassNameRef, funNameAsString)
@@ -17,15 +17,16 @@
package org.jetbrains.kotlin.js.translate.reference;
import com.google.dart.compiler.backend.js.ast.JsExpression;
import com.google.dart.compiler.backend.js.ast.JsInvocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
import org.jetbrains.kotlin.descriptors.VariableDescriptor;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils;
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.psi.KtQualifiedExpression;
import org.jetbrains.kotlin.psi.KtSimpleNameExpression;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.getDescriptorForReferenceExpression;
import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getSelectorAsSimpleName;
@@ -45,7 +46,20 @@ public final class ReferenceTranslator {
public static JsExpression translateAsFQReference(@NotNull DeclarationDescriptor referencedDescriptor,
@NotNull TranslationContext context) {
JsExpression alias = context.getAliasForDescriptor(referencedDescriptor);
return alias != null ? alias : context.getQualifiedReference(referencedDescriptor);
if (alias != null) return alias;
if (isLocalVarOrFunction(referencedDescriptor) ||
AnnotationsUtils.isNativeObject(referencedDescriptor) ||
AnnotationsUtils.isLibraryObject(referencedDescriptor)
) {
return context.getQualifiedReference(referencedDescriptor);
}
return context.getInnerReference(referencedDescriptor);
}
private static boolean isLocalVarOrFunction(DeclarationDescriptor descriptor) {
return descriptor.getContainingDeclaration() instanceof FunctionDescriptor && !(descriptor instanceof ClassDescriptor);
}
@NotNull
@@ -57,7 +71,22 @@ public final class ReferenceTranslator {
return alias;
}
}
return context.getQualifiedReference(descriptor);
if (DescriptorUtils.isObject(descriptor) || DescriptorUtils.isEnumEntry(descriptor)) {
if (AnnotationsUtils.isNativeObject(descriptor)) {
return context.getQualifiedReference(descriptor);
}
else if (!context.isFromCurrentModule(descriptor)) {
DeclarationDescriptor container = descriptor.getContainingDeclaration();
assert container != null : "Object must have containing declaration: " + descriptor;
JsExpression qualifier = context.getInnerReference(container);
return JsAstUtils.pureFqn(context.getNameForDescriptor(descriptor), qualifier);
}
else {
JsExpression functionRef = JsAstUtils.pureFqn(context.getNameForObjectInstance((ClassDescriptor) descriptor), null);
return new JsInvocation(functionRef);
}
}
return context.getInnerReference(descriptor);
}
@NotNull
@@ -339,6 +339,11 @@ public final class JsAstUtils {
return new JsBinaryOperation(JsBinaryOperator.ASG, left, right);
}
@NotNull
public static JsStatement assignmentToThisField(@NotNull String fieldName, @NotNull JsExpression right) {
return assignment(new JsNameRef(fieldName, JsLiteral.THIS), right).makeStmt();
}
public static JsStatement asSyntheticStatement(@NotNull JsExpression expression) {
JsExpressionStatement statement = new JsExpressionStatement(expression);
MetadataProperties.setSynthetic(statement, true);
@@ -460,11 +465,12 @@ public final class JsAstUtils {
@NotNull
public static JsInvocation defineProperty(
@NotNull JsExpression receiver,
@NotNull String name,
@NotNull JsObjectLiteral value,
@NotNull TranslationContext context
@NotNull JsExpression value,
@NotNull JsProgram program
) {
return new JsInvocation(DEFINE_PROPERTY, JsLiteral.THIS, context.program().getStringLiteral(name), value);
return new JsInvocation(DEFINE_PROPERTY.deepCopy(), receiver, program.getStringLiteral(name), value);
}
@NotNull
@@ -544,4 +550,21 @@ public final class JsAstUtils {
JsUnaryOperation unary = (JsUnaryOperation) expression;
return unary.getOperator() == JsUnaryOperator.VOID;
}
@NotNull
public static JsStatement defineGetter(
@NotNull JsProgram program,
@NotNull JsExpression receiver,
@NotNull String name,
@NotNull JsExpression body
) {
JsObjectLiteral propertyLiteral = new JsObjectLiteral(true);
propertyLiteral.getPropertyInitializers().add(new JsPropertyInitializer(new JsNameRef("get"), body));
return defineProperty(receiver, name, propertyLiteral, program).makeStmt();
}
@NotNull
public static JsExpression prototypeOf(@NotNull JsExpression expression) {
return pureFqn("prototype", expression);
}
}
@@ -150,7 +150,7 @@ public final class JsDescriptorUtils {
return !isExtension(propertyDescriptor) &&
isDefaultAccessor(propertyDescriptor.getGetter()) &&
isDefaultAccessor(propertyDescriptor.getSetter()) &&
!TranslationUtils.shouldGenerateAccessors(propertyDescriptor) &&
!TranslationUtils.shouldAccessViaFunctions(propertyDescriptor) &&
!ModalityKt.isOverridableOrOverrides(propertyDescriptor);
}
@@ -54,7 +54,7 @@ public final class TranslationUtils {
@NotNull TranslationContext context) {
if (DescriptorUtils.isExtension(descriptor) ||
descriptor instanceof PropertyAccessorDescriptor &&
shouldGenerateAccessors(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty())
shouldAccessViaFunctions(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty())
) {
return translateExtensionFunctionAsEcma5DataDescriptor(function, descriptor, context);
}
@@ -146,19 +146,20 @@ public final class TranslationUtils {
}
@NotNull
public static JsNameRef backingFieldReference(@NotNull TranslationContext context,
@NotNull PropertyDescriptor descriptor) {
JsName backingFieldName = context.getNameForDescriptor(descriptor);
if(!JsDescriptorUtils.isSimpleFinalProperty(descriptor)) {
public static JsNameRef backingFieldReference(@NotNull TranslationContext context, @NotNull PropertyDescriptor descriptor) {
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
JsName backingFieldName = containingDescriptor instanceof PackageFragmentDescriptor ?
context.getInnerNameForDescriptor(descriptor) :
context.getNameForDescriptor(descriptor);
if (!JsDescriptorUtils.isSimpleFinalProperty(descriptor) && !(containingDescriptor instanceof PackageFragmentDescriptor)) {
JsName backingFieldMangledName = context.getNameForBackingField(descriptor);
backingFieldName = context.declarePropertyOrPropertyAccessorName(descriptor, backingFieldMangledName.getIdent(), false);
}
DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration();
JsExpression receiver;
if (containingDescriptor instanceof PackageFragmentDescriptor) {
// used inside package initializer
receiver = JsLiteral.THIS;
receiver = null;
}
else {
receiver = context.getDispatchReceiver(JsDescriptorUtils.getReceiverParameterForDeclaration(containingDescriptor));
@@ -296,22 +297,22 @@ public final class TranslationUtils {
return !(descriptor instanceof LocalVariableDescriptor) || !((LocalVariableDescriptor) descriptor).isDelegated();
}
public static boolean shouldGenerateAccessors(@NotNull CallableDescriptor descriptor) {
public static boolean shouldAccessViaFunctions(@NotNull CallableDescriptor descriptor) {
if (descriptor instanceof PropertyDescriptor) {
return shouldGenerateAccessors((PropertyDescriptor) descriptor);
return shouldAccessViaFunctions((PropertyDescriptor) descriptor);
}
else if (descriptor instanceof PropertyAccessorDescriptor) {
return shouldGenerateAccessors(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty());
return shouldAccessViaFunctions(((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty());
}
else {
return false;
}
}
private static boolean shouldGenerateAccessors(@NotNull PropertyDescriptor property) {
private static boolean shouldAccessViaFunctions(@NotNull PropertyDescriptor property) {
if (AnnotationsUtils.hasJsNameInAccessors(property)) return true;
for (PropertyDescriptor overriddenProperty : property.getOverriddenDescriptors()) {
if (shouldGenerateAccessors(overriddenProperty)) return true;
if (shouldAccessViaFunctions(overriddenProperty)) return true;
}
return false;
}
@@ -18,10 +18,7 @@ package org.jetbrains.kotlin.js.translate.utils
import com.google.dart.compiler.backend.js.ast.*
import com.intellij.util.SmartList
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunction
@@ -29,12 +26,12 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.KotlinType
fun generateDelegateCall(
classDescriptor: ClassDescriptor,
fromDescriptor: FunctionDescriptor,
toDescriptor: FunctionDescriptor,
thisObject: JsExpression,
context: TranslationContext
): JsPropertyInitializer {
val delegateMemberFunctionName = context.getNameForDescriptor(fromDescriptor)
) {
val overriddenMemberFunctionName = context.getNameForDescriptor(toDescriptor)
val overriddenMemberFunctionRef = JsNameRef(overriddenMemberFunctionName, thisObject)
@@ -57,7 +54,8 @@ fun generateDelegateCall(
val functionObject = simpleReturnFunction(context.getScopeForDescriptor(fromDescriptor), JsInvocation(overriddenMemberFunctionRef, args))
functionObject.parameters.addAll(parameters)
return JsPropertyInitializer(delegateMemberFunctionName.makeRef(), functionObject)
context.addFunctionToPrototype(classDescriptor, fromDescriptor, functionObject)
}
fun <T, S> List<T>.splitToRanges(classifier: (T) -> S): List<Pair<List<T>, S>> {
@@ -86,7 +84,7 @@ fun getReferenceToJsClass(type: KotlinType, context: TranslationContext): JsName
val classifierDescriptor = type.constructor.declarationDescriptor
if (classifierDescriptor is ClassDescriptor) {
val reference = context.getQualifiedReference(classifierDescriptor)
val reference = context.getInnerReference(classifierDescriptor)
if (classifierDescriptor.kind == ClassKind.OBJECT) {
referenceToJsClass = JsAstUtils.pureFqn("constructor", JsInvocation(JsNameRef("getPrototypeOf", JsNameRef("Object")), reference))
}
@@ -105,3 +103,20 @@ fun getReferenceToJsClass(type: KotlinType, context: TranslationContext): JsName
return referenceToJsClass
}
fun TranslationContext.addFunctionToPrototype(classDescriptor: ClassDescriptor, descriptor: FunctionDescriptor, function: JsExpression) {
val prototypeRef = JsAstUtils.prototypeOf(getInnerReference(classDescriptor))
val functionRef = JsNameRef(getNameForDescriptor(descriptor), prototypeRef)
addRootStatement(JsAstUtils.assignment(functionRef, function).makeStmt())
}
fun TranslationContext.addAccessorsToPrototype(
containingClass: ClassDescriptor,
propertyDescriptor: PropertyDescriptor,
literal: JsObjectLiteral
) {
val prototypeRef = JsAstUtils.prototypeOf(getInnerReference(containingClass))
val propertyName = getNameForDescriptor(propertyDescriptor)
val defineProperty = JsAstUtils.defineProperty(prototypeRef, propertyName.ident, literal, program())
addRootStatement(defineProperty.makeStmt())
}
@@ -0,0 +1,10 @@
class A
class B {
val A.x: String
get() = "OK"
fun result(a: A) = a.x
}
fun box() = B().result(A())
@@ -0,0 +1,9 @@
interface I {
fun foo() = "OK"
}
abstract class A : I
class B : A()
fun box() = B().foo()
@@ -0,0 +1,7 @@
interface I {
fun foo() = "OK"
}
class A : I
fun box() = A().foo()
@@ -0,0 +1,9 @@
interface I {
fun foo() = "OK"
}
interface J : I
class A : J
fun box() = A().foo()
@@ -0,0 +1,8 @@
interface I {
val foo: String
get() = "OK"
}
class A : I
fun box() = A().foo
@@ -20,7 +20,7 @@ fun box(): String {
if (foo + bar != OK) return "$foo + $bar != $OK"
val actualAsString = funToString("actual_0")
val expectedAsString = funToString("expected_0")
val expectedAsString = funToString("expected_0").replace("expected", "actual")
if (actualAsString != expectedAsString) return "$actualAsString != $expectedAsString"
if (actual("asd", "12345") != "asd12345") return "${actual("asd", "12345")} != \"asd12345\""