JS: introduce new flat JS declaration structure
This commit is contained in:
@@ -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")
|
||||
|
||||
+11
-11
@@ -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
|
||||
|
||||
+4
-2
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-10
@@ -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!!))
|
||||
}
|
||||
|
||||
+47
-29
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
||||
+269
-15
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+85
-39
@@ -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()
|
||||
}
|
||||
+116
@@ -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
|
||||
}
|
||||
+174
-101
@@ -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,
|
||||
|
||||
-151
@@ -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;
|
||||
}
|
||||
}
|
||||
+116
@@ -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())
|
||||
}
|
||||
}
|
||||
+24
-16
@@ -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
|
||||
}
|
||||
}
|
||||
+82
@@ -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
|
||||
}
|
||||
}
|
||||
+6
-9
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-43
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-87
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+88
-96
@@ -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 =
|
||||
|
||||
+8
-11
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+20
-11
@@ -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() {
|
||||
|
||||
+20
-6
@@ -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
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+39
-29
@@ -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;
|
||||
}
|
||||
|
||||
+14
-9
@@ -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)
|
||||
|
||||
+35
-6
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+14
-13
@@ -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())
|
||||
Vendored
+9
@@ -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()
|
||||
Vendored
+9
@@ -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\""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user