From 0252fe57af3f12c2cd391bfe0b87f3543c34634a Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 26 Oct 2016 17:14:54 +0300 Subject: [PATCH] JS: refactor flat declaration generator. Add more tests on inter-module dependencies --- .../kotlin/js/naming/NameSuggestion.kt | 1 + .../js/test/semantics/BoxJsTestGenerated.java | 69 ++++++++++++++++++ .../callTranslator/CallInfoExtensions.kt | 1 - .../callTranslator/FunctionCallCases.kt | 3 - .../callTranslator/VariableCallCases.kt | 2 +- .../translate/context/DeclarationExporter.kt | 21 ++++-- .../translate/context/TranslationContext.java | 27 ++----- .../translate/declaration/ClassTranslator.kt | 14 ++-- .../declaration/DeclarationBodyVisitor.kt | 2 +- .../declaration/JsDataClassGenerator.java | 2 +- .../js/translate/general/Translation.java | 2 + .../ClassInitializerTranslator.java | 36 ---------- .../functions/FunctionIntrinsics.java | 1 - .../reference/CallableReferenceTranslator.kt | 1 + .../reference/ReferenceTranslator.java | 9 ++- .../kotlin/js/translate/utils/JsAstUtils.java | 2 - .../box/crossModuleRef/callableObjectRef.kt | 25 +++++++ .../box/crossModuleRef/constructor.kt | 70 +++++++++++++++++++ .../box/crossModuleRef/inheritance.kt | 25 +++++++ .../testData/box/crossModuleRef/object.kt | 35 ++++++++++ .../crossModuleRef/objectInInlineClosure.kt | 25 +++++++ .../box/crossModuleRef/objectIsObject.kt | 19 +++++ .../box/crossModuleRef/topLevelExtension.kt | 42 +++++++++++ .../box/crossModuleRef/topLevelFunction.kt | 49 +++++++++++++ .../crossModuleRef/topLevelMutableProperty.kt | 36 ++++++++++ .../box/crossModuleRef/topLevelProperty.kt | 45 ++++++++++++ 26 files changed, 483 insertions(+), 81 deletions(-) create mode 100644 js/js.translator/testData/box/crossModuleRef/callableObjectRef.kt create mode 100644 js/js.translator/testData/box/crossModuleRef/constructor.kt create mode 100644 js/js.translator/testData/box/crossModuleRef/inheritance.kt create mode 100644 js/js.translator/testData/box/crossModuleRef/object.kt create mode 100644 js/js.translator/testData/box/crossModuleRef/objectInInlineClosure.kt create mode 100644 js/js.translator/testData/box/crossModuleRef/objectIsObject.kt create mode 100644 js/js.translator/testData/box/crossModuleRef/topLevelExtension.kt create mode 100644 js/js.translator/testData/box/crossModuleRef/topLevelFunction.kt create mode 100644 js/js.translator/testData/box/crossModuleRef/topLevelMutableProperty.kt create mode 100644 js/js.translator/testData/box/crossModuleRef/topLevelProperty.kt diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt index e8e91afa812..5fa5c4e7e22 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/naming/NameSuggestion.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.js.naming import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName +import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.getNameForAnnotatedObject import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.isNativeObject import org.jetbrains.kotlin.resolve.DescriptorUtils diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index 0c0502b2737..e7e961e95ed 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -777,6 +777,75 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { } } + @TestMetadata("js/js.translator/testData/box/crossModuleRef") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class CrossModuleRef extends AbstractBoxJsTest { + public void testAllFilesPresentInCrossModuleRef() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/crossModuleRef"), Pattern.compile("^([^_](.+))\\.kt$"), true); + } + + @TestMetadata("callableObjectRef.kt") + public void testCallableObjectRef() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/callableObjectRef.kt"); + doTest(fileName); + } + + @TestMetadata("constructor.kt") + public void testConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/constructor.kt"); + doTest(fileName); + } + + @TestMetadata("inheritance.kt") + public void testInheritance() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/inheritance.kt"); + doTest(fileName); + } + + @TestMetadata("object.kt") + public void testObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/object.kt"); + doTest(fileName); + } + + @TestMetadata("objectInInlineClosure.kt") + public void testObjectInInlineClosure() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/objectInInlineClosure.kt"); + doTest(fileName); + } + + @TestMetadata("objectIsObject.kt") + public void testObjectIsObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/objectIsObject.kt"); + doTest(fileName); + } + + @TestMetadata("topLevelExtension.kt") + public void testTopLevelExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/topLevelExtension.kt"); + doTest(fileName); + } + + @TestMetadata("topLevelFunction.kt") + public void testTopLevelFunction() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/topLevelFunction.kt"); + doTest(fileName); + } + + @TestMetadata("topLevelMutableProperty.kt") + public void testTopLevelMutableProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/topLevelMutableProperty.kt"); + doTest(fileName); + } + + @TestMetadata("topLevelProperty.kt") + public void testTopLevelProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/crossModuleRef/topLevelProperty.kt"); + doTest(fileName); + } + } + @TestMetadata("js/js.translator/testData/box/dataClass") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfoExtensions.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfoExtensions.kt index 573caddb61f..58df5585059 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfoExtensions.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/CallInfoExtensions.kt @@ -25,7 +25,6 @@ import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor -import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.js.translate.utils.JsAstUtils diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt index abd3817dfdc..b5b07e0669f 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/FunctionCallCases.kt @@ -77,9 +77,6 @@ object DefaultFunctionCallCase : FunctionCallCase() { val functionCallRef = Namer.getFunctionApplyRef(JsNameRef(context.getNameForDescriptor(callableDescriptor))) return JsInvocation(functionCallRef, argumentsInfo.translateArguments) } - if (isNative) { - return JsInvocation(JsNameRef(context.getNameForDescriptor(callableDescriptor)), argumentsInfo.translateArguments) - } val functionRef = ReferenceTranslator.translateAsValueReference(callableDescriptor, context) return JsInvocation(functionRef, argumentsInfo.translateArguments) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt index 9cb4581a680..ce28943a58d 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/callTranslator/VariableCallCases.kt @@ -82,7 +82,7 @@ object DefaultVariableAccessCase : VariableAccessCase() { } if (descriptor is FakeCallableDescriptorForObject) { - return JsInvocation(pureFqn(context.getNameForObjectInstance (descriptor.getReferencedObject()), null)) + return ReferenceTranslator.translateAsValueReference(descriptor.getReferencedObject(), context) } val functionRef = ReferenceTranslator.translateAsValueReference(callableDescriptor, context) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt index 669624ad78c..978c2017b06 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DeclarationExporter.kt @@ -23,7 +23,9 @@ import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils import org.jetbrains.kotlin.js.translate.utils.JsAstUtils import org.jetbrains.kotlin.js.translate.utils.JsAstUtils.assignment import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils +import org.jetbrains.kotlin.js.translate.utils.TranslationUtils import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyPublicApi internal class DeclarationExporter(val context: StaticContext) { @@ -42,9 +44,16 @@ internal class DeclarationExporter(val context: StaticContext) { if (!descriptor.shouldBeExported(force)) return exportedDeclarations.add(descriptor) - val qualifier = when (container) { - is PackageFragmentDescriptor -> getLocalPackageReference(container.fqName) - else -> context.getInnerNameForDescriptor(container).makeRef() + val qualifier = when { + container is PackageFragmentDescriptor -> { + getLocalPackageReference(container.fqName) + } + DescriptorUtils.isObject(container) -> { + JsAstUtils.prototypeOf(context.getInnerNameForDescriptor(container).makeRef()) + } + else -> { + context.getInnerNameForDescriptor(container).makeRef() + } } when { @@ -80,8 +89,10 @@ internal class DeclarationExporter(val context: StaticContext) { val propertyLiteral = JsObjectLiteral(true) val name = context.getNameForDescriptor(declaration).ident + val simpleProperty = JsDescriptorUtils.isSimpleFinalProperty(declaration) && + !TranslationUtils.shouldAccessViaFunctions(declaration) - val getterBody: JsExpression = if (JsDescriptorUtils.isSimpleFinalProperty(declaration)) { + val getterBody: JsExpression = if (simpleProperty) { val accessToField = JsReturn(context.getInnerNameForDescriptor(declaration).makeRef()) JsFunction(context.rootFunction.scope, JsBlock(accessToField), "$declaration getter") } @@ -91,7 +102,7 @@ internal class DeclarationExporter(val context: StaticContext) { propertyLiteral.propertyInitializers += JsPropertyInitializer(JsNameRef("get"), getterBody) if (declaration.isVar) { - val setterBody: JsExpression = if (JsDescriptorUtils.isSimpleFinalProperty(declaration)) { + val setterBody: JsExpression = if (simpleProperty) { val statements = mutableListOf() val function = JsFunction(context.rootFunction.scope, JsBlock(statements), "$declaration setter") val valueName = function.scope.declareFreshName("value") diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java index e6bc169d6ed..2ede2d38cb3 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java @@ -59,10 +59,7 @@ public class TranslationContext { private final ClassDescriptor classDescriptor; @NotNull - public static TranslationContext rootContext( - @NotNull StaticContext staticContext, - @NotNull JsFunction rootFunction - ) { + public static TranslationContext rootContext(@NotNull StaticContext staticContext, @NotNull JsFunction rootFunction) { JsBlock block = new JsBlock(staticContext.getTopLevelStatements()); DynamicContext rootDynamicContext = DynamicContext.rootContext(rootFunction.getScope(), block); AliasingContext rootAliasingContext = AliasingContext.getCleanContext(); @@ -565,11 +562,6 @@ public class TranslationContext { return staticContext.getModuleExpressionFor(descriptor); } - @NotNull - public JsFunction getRootFunction() { - return staticContext.getRootFunction(); - } - public void addDeclarationStatement(@NotNull JsStatement statement) { staticContext.getDeclarationStatements().add(statement); } @@ -578,28 +570,19 @@ public class TranslationContext { staticContext.getTopLevelStatements().add(statement); } - @NotNull - public JsFunction defineTopLevelFunction(@NotNull DeclarationDescriptor descriptor) { - JsFunction function = createTopLevelFunction(descriptor); - addDeclarationStatement(function.makeStmt()); - return function; - } - @NotNull public JsName createGlobalName(@NotNull String suggestedName) { return staticContext.getRootFunction().getScope().declareFreshName(suggestedName); } @NotNull - private JsFunction createTopLevelFunction(@NotNull DeclarationDescriptor descriptor) { - JsFunction function = createTopLevelAnonymousFunction(descriptor); - function.setName(staticContext.getInnerNameForDescriptor(descriptor)); - return function; + public JsFunction createTopLevelFunction(@NotNull DeclarationDescriptor descriptor) { + return createTopLevelFunction(descriptor.toString()); } @NotNull - public JsFunction createTopLevelAnonymousFunction(@NotNull DeclarationDescriptor descriptor) { - return new JsFunction(getRootFunction().getScope(), new JsBlock(), descriptor.toString()); + public JsFunction createTopLevelFunction(@NotNull String description) { + return new JsFunction(staticContext.getRootFunction().getScope(), new JsBlock(), description); } public void addClass(@NotNull ClassDescriptor classDescriptor) { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt index b23d3bf0ae0..b942aa77026 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/ClassTranslator.kt @@ -74,7 +74,9 @@ class ClassTranslator private constructor( val scope = context().getScopeForDescriptor(descriptor) val context = context().newDeclaration(descriptor) - val constructorFunction = context.defineTopLevelFunction(descriptor) + val constructorFunction = context.createTopLevelFunction(descriptor) + constructorFunction.name = context.getInnerNameForDescriptor(descriptor) + context.addDeclarationStatement(constructorFunction.makeStmt()) val enumInitFunction = if (descriptor.kind == ClassKind.ENUM_CLASS) createEnumInitFunction() else null val nonConstructorContext = context.innerWithUsageTracker(scope, descriptor) @@ -139,9 +141,9 @@ class ClassTranslator private constructor( } private fun createEnumInitFunction(): JsFunction { - val function = context().createTopLevelAnonymousFunction(descriptor) + val function = context().createTopLevelFunction(descriptor) function.name = context().createGlobalName(StaticContext.getSuggestedName(descriptor) + "_initFields") - val emptyFunction = context().createTopLevelAnonymousFunction(descriptor) + val emptyFunction = context().createTopLevelFunction(descriptor) function.body.statements += JsAstUtils.assignment(JsAstUtils.pureFqn(function.name, null), emptyFunction).makeStmt() context().addDeclarationStatement(function.makeStmt()) return function @@ -211,7 +213,9 @@ class ClassTranslator private constructor( } // Translate constructor body - val constructorInitializer = context.defineTopLevelFunction(constructorDescriptor) + val constructorInitializer = context.getFunctionObject(constructorDescriptor) + constructorInitializer.name = context.getInnerNameForDescriptor(constructorDescriptor) + context.addTopLevelStatement(constructorInitializer.makeStmt()) FunctionTranslator.newInstance(constructor, context, constructorInitializer).translateAsMethodWithoutMetadata() // Translate super/this call @@ -415,7 +419,7 @@ class ClassTranslator private constructor( private fun addObjectMethods() { context().addDeclarationStatement(JsAstUtils.newVar(cachedInstanceName, JsLiteral.NULL)) - val instanceFun = JsFunction(context().rootFunction.scope, JsBlock(), "Instance function: " + descriptor) + val instanceFun = context().createTopLevelFunction("Instance function: " + descriptor) instanceFun.name = context().getNameForObjectInstance(descriptor) if (enumInitializerName == null) { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt index d1032f4d200..c3e87ef1f49 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.kt @@ -69,7 +69,7 @@ class DeclarationBodyVisitor( context.addDeclarationStatement(JsAstUtils.newVar(enumInstanceName, null)) enumInitializer.body.statements += JsAstUtils.assignment(pureFqn(enumInstanceName, null), jsEnumEntryCreation).makeStmt() - val enumInstanceFunction = context.createTopLevelAnonymousFunction(descriptor) + val enumInstanceFunction = context.createTopLevelFunction(descriptor) enumInstanceFunction.name = context.getNameForObjectInstance(descriptor) context.addDeclarationStatement(enumInstanceFunction.makeStmt()) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsDataClassGenerator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsDataClassGenerator.java index f969d0ade99..fe57bec011e 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsDataClassGenerator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/JsDataClassGenerator.java @@ -189,7 +189,7 @@ class JsDataClassGenerator extends DataClassMethodGenerator { } private JsFunction generateJsMethod(@NotNull FunctionDescriptor functionDescriptor) { - JsFunction functionObject = context.createTopLevelAnonymousFunction(functionDescriptor); + JsFunction functionObject = context.createTopLevelFunction(functionDescriptor); ClassDescriptor containingClass = (ClassDescriptor) functionDescriptor.getContainingDeclaration(); UtilsKt.addFunctionToPrototype(context, containingClass, functionDescriptor, functionObject); return functionObject; diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java index 61aa54d5714..c33910995ca 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/general/Translation.java @@ -259,6 +259,8 @@ public final class Translation { JsBlock rootBlock = rootFunction.getBody(); List statements = rootBlock.getStatements(); + program.getScope().declareName("_"); + TranslationContext context = TranslationContext.rootContext(staticContext, rootFunction); PackageDeclarationTranslator.translateFiles(files, context); staticContext.postProcess(); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java index 4dbb83a93e8..9faf81ed7a7 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/ClassInitializerTranslator.java @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.js.translate.initializer; -import com.google.dart.compiler.backend.js.JsReservedIdentifiers; import com.google.dart.compiler.backend.js.ast.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.descriptors.*; @@ -27,12 +26,10 @@ import org.jetbrains.kotlin.js.translate.context.UsageTracker; 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; -import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.KtClassOrObject; import org.jetbrains.kotlin.psi.KtEnumEntry; import org.jetbrains.kotlin.psi.KtParameter; @@ -76,8 +73,6 @@ public final class ClassInitializerTranslator extends AbstractTranslator { this.initFunction = initFunction; this.context = context.contextWithScope(initFunction); classDescriptor = BindingUtils.getClassDescriptor(bindingContext(), classDeclaration); - - fillInitFunction(classDeclaration, context); } public void setOrdinal(int ordinal) { @@ -90,37 +85,6 @@ public final class ClassInitializerTranslator extends AbstractTranslator { return 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(); - - String functionName = AnnotationsUtils.getJsName(classDescriptor); - if (functionName == null) { - Name name = classDescriptor.getName(); - if (!name.isSpecial()) { - functionName = name.asString(); - } - } - - JsFunction ctorFunction; - if (primaryConstructor != null) { - ctorFunction = context.getFunctionObject(primaryConstructor); - } - else { - ctorFunction = new JsFunction(context.scope(), new JsBlock(), "fake constructor for " + functionName); - } - - if (functionName != null) { - if (JsReservedIdentifiers.reservedGlobalSymbols.contains(functionName) || - JsFunctionScope.Companion.getRESERVED_WORDS().contains(functionName) - ) { - functionName += "$"; - } - ctorFunction.setName(ctorFunction.getScope().declareName(functionName)); - } - } - public void generateInitializeMethod(DelegationTranslator delegationTranslator) { addOuterClassReference(classDescriptor); ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/FunctionIntrinsics.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/FunctionIntrinsics.java index a6291b05b60..c545ec1a2b4 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/FunctionIntrinsics.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/FunctionIntrinsics.java @@ -43,7 +43,6 @@ public final class FunctionIntrinsics { register(LongOperationFIF.INSTANCE); register(PrimitiveUnaryOperationFIF.INSTANCE); register(PrimitiveBinaryOperationFIF.INSTANCE); - //register(StringOperationFIF.INSTANCE); register(ArrayFIF.INSTANCE); register(TopLevelFIF.INSTANCE); register(NumberAndCharConversionFIF.INSTANCE); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallableReferenceTranslator.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallableReferenceTranslator.kt index 4052dce66e4..c1782736c80 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallableReferenceTranslator.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/CallableReferenceTranslator.kt @@ -93,6 +93,7 @@ object CallableReferenceTranslator { val packageDescriptor = JsDescriptorUtils.getContainingDeclaration(descriptor) assert(packageDescriptor is PackageFragmentDescriptor) { "Expected PackageFragmentDescriptor: $packageDescriptor" } + // TODO: revisit val jsPackageNameRef = context.getQualifiedReference(packageDescriptor) val jsPropertyName = context.getNameForDescriptor(descriptor) val jsPropertyNameAsString = context.program().getStringLiteral(jsPropertyName.toString()) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ReferenceTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ReferenceTranslator.java index 86dc1c42f71..432e1e18464 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ReferenceTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/reference/ReferenceTranslator.java @@ -91,20 +91,23 @@ public final class ReferenceTranslator { if (!shouldTranslateAsFQN(descriptor, context)) { if (DescriptorUtils.isObject(descriptor) || DescriptorUtils.isEnumEntry(descriptor)) { if (!context.isFromCurrentModule(descriptor)) { - return getLazyReferenceToObject(descriptor, context); + return getPrototypeIfNecessary(descriptor, getLazyReferenceToObject(descriptor, context)); } } return context.getInnerReference(descriptor); } - JsExpression reference = context.getQualifiedReference(descriptor); + return getPrototypeIfNecessary(descriptor, context.getQualifiedReference(descriptor)); + } + + @NotNull + private static JsExpression getPrototypeIfNecessary(@NotNull ClassDescriptor descriptor, @NotNull JsExpression reference) { if (DescriptorUtils.isObject(descriptor) || DescriptorUtils.isEnumEntry(descriptor)) { JsNameRef getPrototypeRef = JsAstUtils.pureFqn("getPrototypeOf", JsAstUtils.pureFqn("Object", null)); JsInvocation getPrototypeInvocation = new JsInvocation(getPrototypeRef, reference); MetadataProperties.setSideEffects(getPrototypeInvocation, SideEffectKind.PURE); reference = JsAstUtils.pureFqn("constructor", getPrototypeInvocation); } - return reference; } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java index fa05600585e..e80084320db 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsAstUtils.java @@ -39,8 +39,6 @@ public final class JsAstUtils { private static final JsPropertyInitializer WRITABLE = new JsPropertyInitializer(pureFqn("writable", null), JsLiteral.TRUE); private static final JsPropertyInitializer ENUMERABLE = new JsPropertyInitializer(pureFqn("enumerable", null), JsLiteral.TRUE); - public static final String LENDS_JS_DOC_TAG = "lends"; - static { JsNameRef globalObjectReference = new JsNameRef("Object"); DEFINE_PROPERTY.setQualifier(globalObjectReference); diff --git a/js/js.translator/testData/box/crossModuleRef/callableObjectRef.kt b/js/js.translator/testData/box/crossModuleRef/callableObjectRef.kt new file mode 100644 index 00000000000..d4fdcaf0d36 --- /dev/null +++ b/js/js.translator/testData/box/crossModuleRef/callableObjectRef.kt @@ -0,0 +1,25 @@ +// MODULE: lib +// FILE: lib.kt +package lib + +object O { + operator fun invoke() = "OK" +} + +inline fun callO() = O() + +// MODULE: main(lib) +// FILE: main.kt +package main + +import lib.* + +fun box(): String { + val a = O() + if (a != "OK") return "fail: simple: $a" + + val b = callO() + if (b != "OK") return "fail: inline: $a" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/box/crossModuleRef/constructor.kt b/js/js.translator/testData/box/crossModuleRef/constructor.kt new file mode 100644 index 00000000000..2129bddbbd3 --- /dev/null +++ b/js/js.translator/testData/box/crossModuleRef/constructor.kt @@ -0,0 +1,70 @@ +// MODULE: lib +// FILE: lib.kt +package lib + +class A(val x: Int) { + constructor(a: Int, b: Int) : this(a + b) +} + +@native class B(x: Int) { + constructor(a: Int, b: Int) : this(0) {} + + val x: Int +} + +// TODO: may be useful after implementing local classes in inline functions +/* +inline fun foo(p: Int, q: Int, r: Int): Pair { + class C(val x : Int) { + constructor(a: Int, b: Int) : this(a + b) + } + return Pair(C(p).x, C(q, r).x) +} +*/ + +inline fun callPrimaryConstructor(x: Int) = A(x).x + +inline fun callSecondaryConstructor(x: Int, y: Int) = A(x, y).x + +// FILE: lib.js + +function B(x, y) { + this.x = x; + if (typeof y !== 'undefined') { + this.x += y; + } +} + +// MODULE: main(lib) +// FILE: main.kt +package main + +import lib.* + +fun box(): String { + val a = A(23).x + if (a != 23) return "fail: primary constructor: $a" + + val b = A(40, 2).x + if (b != 42) return "fail: secondary constructor: $b" + + val c = B(99).x + if (c != 99) return "fail: native primary constructor: $c" + + val d = B(100, 11).x + if (d != 111) return "fail: native secondary constructor: $d" + + /* + val (e, f) = foo(123, 320, 1) + if (e != 123) return "fail: local primary constructor: $e" + if (f != 321) return "fail: local secondary constructor: $f" + */ + + val g = callPrimaryConstructor(55) + if (g != 55) return "fail: primary constructor from inline function: $g" + + val h = callSecondaryConstructor(990, 9) + if (h != 999) return "fail: secondary constructor from inline function: $h" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/box/crossModuleRef/inheritance.kt b/js/js.translator/testData/box/crossModuleRef/inheritance.kt new file mode 100644 index 00000000000..06975c21bb1 --- /dev/null +++ b/js/js.translator/testData/box/crossModuleRef/inheritance.kt @@ -0,0 +1,25 @@ +// MODULE: lib +// FILE: lib.kt + +package lib + +open class A { + fun foo() = 23 +} + +// MODULE: main(lib) +// FILE: main.kt + +package main + +import lib.A + +class B : A() { + fun bar() = foo() + 1 +} + +fun box(): String { + val result = B().bar() + if (result != 24) return "fail: $result" + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/box/crossModuleRef/object.kt b/js/js.translator/testData/box/crossModuleRef/object.kt new file mode 100644 index 00000000000..7628881e3f5 --- /dev/null +++ b/js/js.translator/testData/box/crossModuleRef/object.kt @@ -0,0 +1,35 @@ +// MODULE: lib +// FILE: lib.kt +package lib + +var log = "" + +object O { + init { + log += "O.init;" + } + + fun result() = "OK" +} + +fun getResult(): String { + log += "before;" + val result = O.result() + log += "after;" + return result +} + +// MODULE: main(lib) +// FILE: main.kt +package main + +import lib.* + +fun box(): String { + val result = getResult() + if (result != "OK") return "fail: unexpected result: $result" + + if (log != "before;O.init;after;") return "fail: wrong evaluation order: $log" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/box/crossModuleRef/objectInInlineClosure.kt b/js/js.translator/testData/box/crossModuleRef/objectInInlineClosure.kt new file mode 100644 index 00000000000..b12d49e5039 --- /dev/null +++ b/js/js.translator/testData/box/crossModuleRef/objectInInlineClosure.kt @@ -0,0 +1,25 @@ +// MODULE: lib +// FILE: lib.kt +package lib + +object O { + val result = "OK" + + inline fun foo(): String { + val o = object { + fun bar() = O + } + return fetch(o.bar()) + } +} + +fun fetch(o: O) = o.result + + +// MODULE: main(lib) +// FILE: main.kt +package main + +import lib.* + +fun box() = O.foo() \ No newline at end of file diff --git a/js/js.translator/testData/box/crossModuleRef/objectIsObject.kt b/js/js.translator/testData/box/crossModuleRef/objectIsObject.kt new file mode 100644 index 00000000000..3a6f920c36c --- /dev/null +++ b/js/js.translator/testData/box/crossModuleRef/objectIsObject.kt @@ -0,0 +1,19 @@ +// MODULE: lib +// FILE: lib.kt +package lib + +object O + +// MODULE: main(lib) +// FILE: main.kt +package main + +import lib.* + +fun box(): String { + var o: Any = O + if (o !is O) return "fail1" + if (!(o is O)) return "fail2" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/box/crossModuleRef/topLevelExtension.kt b/js/js.translator/testData/box/crossModuleRef/topLevelExtension.kt new file mode 100644 index 00000000000..e7340953a16 --- /dev/null +++ b/js/js.translator/testData/box/crossModuleRef/topLevelExtension.kt @@ -0,0 +1,42 @@ +// MODULE: lib +// FILE: lib.kt + +package lib + +class A(val x: Int) + +fun A.foo() = 23 + x + +inline fun A.baz() = 99 + x + +inline fun A.callFoo() = foo() + +inline fun A.buzz(): Int { + val o = object { + fun f() = 111 + x + } + return o.f() +} + +// MODULE: main(lib) +// FILE: main.kt + +package main + +import lib.* + +fun box(): String { + val a = A(1).foo() + if (a != 24) return "fail: simple function: $a" + + val c = A(1).baz() + if (c != 100) return "fail: inline function: $c" + + val d = A(1).buzz() + if (d != 112) return "fail: inline function with object expression: $d" + + val e = A(2).callFoo() + if (e != 25) return "fail: inline function calling another function: $e" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/box/crossModuleRef/topLevelFunction.kt b/js/js.translator/testData/box/crossModuleRef/topLevelFunction.kt new file mode 100644 index 00000000000..c1886a8c71d --- /dev/null +++ b/js/js.translator/testData/box/crossModuleRef/topLevelFunction.kt @@ -0,0 +1,49 @@ +// MODULE: lib +// FILE: lib.kt + +package lib + +fun foo() = 23 + +@native fun bar(): Int = noImpl + +inline fun baz() = 99 + +inline fun callFoo() = foo() + +inline fun buzz(): Int { + val o = object { + fun f() = 111 + } + return o.f() +} + +// FILE: lib.js + +function bar() { + return 42; +} + +// MODULE: main(lib) +// FILE: main.kt + +package main + +fun box(): String { + val a = lib.foo() + if (a != 23) return "fail: simple function: $a" + + val b = lib.bar() + if (b != 42) return "fail: native function: $b" + + val c = lib.baz() + if (c != 99) return "fail: inline function: $c" + + val d = lib.buzz() + if (d != 111) return "fail: inline function with object expression: $d" + + val e = lib.callFoo() + if (e != 23) return "fail: inline function calling another function: $e" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/box/crossModuleRef/topLevelMutableProperty.kt b/js/js.translator/testData/box/crossModuleRef/topLevelMutableProperty.kt new file mode 100644 index 00000000000..78c85370d90 --- /dev/null +++ b/js/js.translator/testData/box/crossModuleRef/topLevelMutableProperty.kt @@ -0,0 +1,36 @@ +// MODULE: lib +// FILE: lib.kt +package lib + +var foo = 23 + +var bar: Int = 42 + get() = field + set(value) { + field = value + } + +@JsName("faz") var baz = 99 + +// MODULE: main(lib) +// FILE: lib.kt +package main + +import lib.* + +fun box(): String { + if (foo != 23) return "fail: simple property initial value: $foo" + foo = 24 + if (foo != 24) return "fail: simple property new value: $foo" + + if (bar != 42) return "fail: property with accessor initial value: $bar" + bar = 43 + if (bar != 43) return "fail: property with accessor new value: $bar" + + if (baz != 99) return "fail: renamed property initial value: $baz" + baz = 100 + if (baz != 100) return "fail: renamed property new value: $baz" + + + return "OK" +} diff --git a/js/js.translator/testData/box/crossModuleRef/topLevelProperty.kt b/js/js.translator/testData/box/crossModuleRef/topLevelProperty.kt new file mode 100644 index 00000000000..837464d2dc6 --- /dev/null +++ b/js/js.translator/testData/box/crossModuleRef/topLevelProperty.kt @@ -0,0 +1,45 @@ +// MODULE: lib +// FILE: lib.kt +package lib + +val foo = 23 + +val boo: Int + get() = 42 + +@native val bar: Int = noImpl + +@native val far: Int + get() = noImpl + +// TODO: annotations like this are not serialized properly. Uncomment after KT-14529 gets fixed +/* +val fuzz: Int + @JsName("getBuzz") get() = 55 + */ + +inline fun fetchFoo() = foo + +@JsName("fee") val tee = 2525 + +// FILE: lib.js + +var bar = 99 +var far = 111 + +// MODULE: main(lib) +// FILE: lib.kt +package main + +import lib.* + +fun box(): String { + if (foo != 23) return "fail: simple property: $foo" + if (boo != 42) return "fail: property with accessor: $boo" + if (bar != 99) return "fail: native property: $bar" + if (far != 111) return "fail: native property with accessor: $far" + //if (fuzz != 55) return "fail: property with JsName on accessor: $fuzz" + if (tee != 2525) return "fail: native property with JsName: $tee" + + return "OK" +}