From 1f8c3375fe23111fb3cf5c68580eb79efa86d45a Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 2 Mar 2016 16:49:47 +0300 Subject: [PATCH] KT-11030 Implements local classes that don't have closure --- .../js/translate/context/DefinitionPlace.kt | 10 ++-- .../js/translate/context/StaticContext.java | 47 +++++++++++++++++++ .../translate/context/TranslationContext.java | 7 ++- .../expression/ExpressionVisitor.java | 9 ++++ .../js/translate/utils/TranslationUtils.java | 3 +- 5 files changed, 67 insertions(+), 9 deletions(-) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DefinitionPlace.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DefinitionPlace.kt index 193fd6bff04..71960c81045 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DefinitionPlace.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/DefinitionPlace.kt @@ -16,11 +16,7 @@ package org.jetbrains.kotlin.js.translate.context -import com.google.dart.compiler.backend.js.ast.JsExpression -import com.google.dart.compiler.backend.js.ast.JsPropertyInitializer -import com.google.dart.compiler.backend.js.ast.JsNameRef -import com.google.dart.compiler.backend.js.ast.JsObjectScope -import com.google.dart.compiler.backend.js.ast.JsFunction +import com.google.dart.compiler.backend.js.ast.* import com.google.dart.compiler.backend.js.ast.metadata.staticRef class DefinitionPlace( @@ -28,9 +24,9 @@ class DefinitionPlace( private val fqName: JsExpression, val properties: MutableList ) { - fun define(suggestedName: String, expression : JsExpression): JsNameRef { - val name = scope.declareFreshName(suggestedName) + 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 */ diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java index ed7b6e7dfcd..75d7a709cf0 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/StaticContext.java @@ -38,6 +38,9 @@ import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.DescriptorUtils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Map; import static org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils.*; @@ -255,6 +258,29 @@ public final class StaticContext { } }; + Rule localDeclarations = new Rule() { + @Nullable + @Override + public JsName apply(@NotNull DeclarationDescriptor descriptor) { + if (!DescriptorUtils.isLocal(descriptor) || !DescriptorUtils.isClass(descriptor)) return null; + + List parts = new ArrayList(); + do { + parts.add(descriptor.getName().asString()); + descriptor = descriptor.getContainingDeclaration(); + } while (!(descriptor instanceof ClassOrPackageFragmentDescriptor)); + + Collections.reverse(parts); + StringBuilder suggestedName = new StringBuilder(parts.get(0)); + for (int i = 1; i < parts.size(); ++i) { + suggestedName.append('$').append(parts.get(i)); + } + + JsScope scope = getScopeForDescriptor(descriptor); + return scope.declareFreshName(suggestedName.toString()); + } + }; + Rule namesForStandardClasses = new Rule() { @Override @Nullable @@ -368,6 +394,7 @@ public final class StaticContext { }; addRule(namesForDynamic); + addRule(localDeclarations); addRule(namesForStandardClasses); addRule(constructorOrCompanionObjectHasTheSameNameAsTheClass); addRule(propertyOrPropertyAccessor); @@ -554,6 +581,9 @@ public final class StaticContext { return null; } DeclarationDescriptor container = descriptor.getContainingDeclaration(); + if (container != null && !(container instanceof ClassDescriptor)) { + container = DescriptorUtils.getContainingClass(container); + } if (container == null) { return null; } @@ -574,6 +604,22 @@ public final class StaticContext { } }; + Rule localClassesHavePackageQualifier = new Rule() { + @Nullable + @Override + public JsExpression apply(@NotNull DeclarationDescriptor descriptor) { + if (!DescriptorUtils.isLocal(descriptor) || !(descriptor instanceof ClassDescriptor)) return null; + + descriptor = descriptor.getContainingDeclaration(); + while (descriptor != null && !(descriptor instanceof ClassOrPackageFragmentDescriptor)) { + descriptor = descriptor.getContainingDeclaration(); + } + if (!(descriptor instanceof PackageFragmentDescriptor)) return null; + + return getQualifiedReference(descriptor); + } + }; + addRule(libraryObjectsHaveKotlinQualifier); addRule(constructorOrCompanionObjectHasTheSameQualifierAsTheClass); addRule(standardObjectsHaveKotlinQualifier); @@ -581,6 +627,7 @@ public final class StaticContext { addRule(nativeObjectsHaveNativePartOfFullQualifier); addRule(staticMembersHaveContainerQualifier); addRule(nestedClassesHaveContainerQualifier); + addRule(localClassesHavePackageQualifier); } } 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 c86045cb888..172275c7a9b 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 @@ -399,10 +399,15 @@ public class TranslationContext { @NotNull public JsNameRef define(DeclarationDescriptor descriptor, JsExpression expression) { - String suggestedName = TranslationUtils.getSuggestedNameForInnerDeclaration(this, descriptor); + String suggestedName = TranslationUtils.getSuggestedNameForInnerDeclaration(staticContext, descriptor); return getDefinitionPlace().define(suggestedName, expression); } + @NotNull + public JsNameRef define(JsName name, JsExpression expression) { + return getDefinitionPlace().define(name, expression); + } + @Nullable private JsNameRef captureIfNeedAndGetCapturedName(DeclarationDescriptor descriptor) { if (usageTracker != null) { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java index c5138c7ad65..ebbd8ba7c1d 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor; import org.jetbrains.kotlin.js.translate.operation.BinaryOperationTranslator; import org.jetbrains.kotlin.js.translate.operation.UnaryOperationTranslator; import org.jetbrains.kotlin.js.translate.reference.*; +import org.jetbrains.kotlin.js.translate.utils.BindingUtils; import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; import org.jetbrains.kotlin.js.translate.utils.TranslationUtils; import org.jetbrains.kotlin.lexer.KtTokens; @@ -565,4 +566,12 @@ public final class ExpressionVisitor extends TranslatorVisitor { assert descriptor != null : "Missing declaration descriptor: " + PsiUtilsKt.getTextWithLocation(expression); return descriptor; } + + @Override + public JsNode visitClass(@NotNull KtClass klass, TranslationContext context) { + JsInvocation jsClass = ClassTranslator.generateClassCreation(klass, context); + DeclarationDescriptor descriptor = BindingUtils.getClassDescriptor(context.bindingContext(), klass); + JsName name = context.getNameForDescriptor(descriptor); + return context.define(name, jsClass); + } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java index 8ad8682d17e..b0a7fe17058 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor; import org.jetbrains.kotlin.js.translate.context.Namer; +import org.jetbrains.kotlin.js.translate.context.StaticContext; import org.jetbrains.kotlin.js.translate.context.TemporaryConstVariable; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.general.Translation; @@ -263,7 +264,7 @@ public final class TranslationUtils { } @NotNull - public static String getSuggestedNameForInnerDeclaration(TranslationContext context, DeclarationDescriptor descriptor) { + public static String getSuggestedNameForInnerDeclaration(StaticContext context, DeclarationDescriptor descriptor) { String suggestedName = ""; DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); //noinspection ConstantConditions