From c1c57a06bb81ae2938ae80b0e20abddcb2ea6929 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 24 Mar 2016 16:20:57 +0300 Subject: [PATCH] KT-11030 Refactoring code to properly implement secondary constructors in local classes --- .../js/translate/context/StaticContext.java | 23 +----- .../context/generator/Generator.java | 2 +- .../translate/declaration/ClassTranslator.kt | 72 ++++++++++++------- .../expression/ExpressionVisitor.java | 5 +- .../js/translate/utils/ManglingUtils.java | 34 ++++++++- 5 files changed, 83 insertions(+), 53 deletions(-) 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 608709ad0a6..74d27862d95 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 @@ -28,7 +28,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.ReflectionTypes; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.js.config.Config; -import org.jetbrains.kotlin.js.config.EcmaVersion; import org.jetbrains.kotlin.js.config.LibrarySourcesConfig; import org.jetbrains.kotlin.js.translate.context.generator.Generator; import org.jetbrains.kotlin.js.translate.context.generator.Rule; @@ -39,8 +38,6 @@ 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; @@ -106,9 +103,6 @@ public final class StaticContext { @NotNull private final Config config; - @NotNull - private final EcmaVersion ecmaVersion; - //TODO: too many parameters in constructor private StaticContext(@NotNull JsProgram program, @NotNull BindingTrace bindingTrace, @NotNull Namer namer, @NotNull Intrinsics intrinsics, @@ -120,14 +114,9 @@ public final class StaticContext { this.rootScope = rootScope; this.standardClasses = standardClasses; this.config = config; - this.ecmaVersion = config.getTarget(); this.reflectionTypes = new ReflectionTypes(moduleDescriptor); } - public boolean isEcma5() { - return ecmaVersion == EcmaVersion.v5; - } - @NotNull public JsProgram getProgram() { return program; @@ -272,21 +261,15 @@ public final class StaticContext { return null; } - List parts = new ArrayList(); + String suggested = getSuggestedName(descriptor); + do { - parts.add(descriptor.getName().isSpecial() ? "f" : descriptor.getName().getIdentifier()); descriptor = descriptor.getContainingDeclaration(); } while (descriptor != null && !(descriptor instanceof ClassOrPackageFragmentDescriptor)); assert descriptor != null; - 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()); + return scope.declareFreshName(suggested); } }; diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/generator/Generator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/generator/Generator.java index d5cd80ffda9..2d0a821a312 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/generator/Generator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/generator/Generator.java @@ -31,7 +31,7 @@ public class Generator { @NotNull private final List> rules = Lists.newArrayList(); - public void addRule(@NotNull Rule rule) { + protected final void addRule(@NotNull Rule rule) { rules.add(rule); } 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 50a394be9df..1405b49b9ca 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 @@ -295,6 +295,7 @@ class ClassTranslator private constructor( } private fun generateSecondaryConstructor(constructor: KtSecondaryConstructor, context: TranslationContext): JsPropertyInitializer { + // Prepare val constructorDescriptor = BindingUtils.getDescriptorForElement(context.bindingContext(), constructor) as ConstructorDescriptor val classDescriptor = constructorDescriptor.containingDeclaration @@ -309,6 +310,9 @@ class ClassTranslator private constructor( translationContext = translationContext.newDeclaration(constructorDescriptor, translationContext.definitionPlace) translationContext = translationContext.innerContextWithAliased(receiverDescriptor, thisNameRef) + val closure = translationContext.getLocalClassClosure(classDescriptor) + val usageTracker = context.usageTracker() + val outerName = translationContext.getOuterClassReference(classDescriptor); val outerClass = DescriptorUtils.getContainingClass(classDescriptor) if (outerClass != null && outerName != null) { @@ -316,43 +320,59 @@ class ClassTranslator private constructor( translationContext = translationContext.innerContextWithAliased(outerClassRef, outerName.makeRef()) } + // Translate constructor body val constructorInitializer = FunctionTranslator.newInstance(constructor, translationContext).translateAsMethod() val constructorFunction = constructorInitializer.valueExpr as JsFunction - val leadingArgs = mutableListOf() - - if (outerName != null) { - constructorFunction.parameters.add(0, JsParameter(outerName)) - leadingArgs.add(outerName.makeRef()) - } - constructorFunction.parameters.add(JsParameter(thisName)) + // Translate super/this call + val forAddToBeginning = arrayListOf() val referenceToClass = translationContext.getQualifiedReference(classDescriptor) - val forAddToBeginning: List = - with(arrayListOf()) { - addAll(FunctionBodyTranslator.setDefaultValueForArguments(constructorDescriptor, translationContext)) + forAddToBeginning.addAll(FunctionBodyTranslator.setDefaultValueForArguments(constructorDescriptor, translationContext)) - val createInstance = Namer.createObjectWithPrototypeFrom(referenceToClass) - val instanceVar = JsAstUtils.assignment(thisNameRef, JsAstUtils.or(thisNameRef, createInstance)).makeStmt() - add(instanceVar) + val createInstance = Namer.createObjectWithPrototypeFrom(referenceToClass) + val instanceVar = JsAstUtils.assignment(thisNameRef, JsAstUtils.or(thisNameRef, createInstance)).makeStmt() + forAddToBeginning.add(instanceVar) - val resolvedCall = BindingContextUtils.getDelegationConstructorCall(translationContext.bindingContext(), - constructorDescriptor) - val delegationClassDescriptor = resolvedCall?.resultingDescriptor?.containingDeclaration + val resolvedCall = BindingContextUtils.getDelegationConstructorCall(translationContext.bindingContext(), + constructorDescriptor) + val delegationClassDescriptor = resolvedCall?.resultingDescriptor?.containingDeclaration + val superCall = if (resolvedCall != null && !KotlinBuiltIns.isAny(delegationClassDescriptor!!)) { + CallTranslator.translate(translationContext, resolvedCall) + } + else { + null + } - if (resolvedCall != null && !KotlinBuiltIns.isAny(delegationClassDescriptor!!)) { - val superCall = CallTranslator.translate(translationContext, resolvedCall) - add(superCall.toInvocationWith(leadingArgs, thisNameRef).makeStmt()) - } + // Add parameters for closure and outer instance + val leadingArgs = mutableListOf() - val delegationCtorInTheSameClass = delegationClassDescriptor == classDescriptor - if (!delegationCtorInTheSameClass && !classDescriptor.hasPrimaryConstructor()) { - add(JsInvocation(Namer.getFunctionCallRef(referenceToClass), listOf(thisNameRef) + leadingArgs).makeStmt()) - } + var additionalParameterIndex = 0 + if (closure != null && usageTracker != null) { + for (capturedValue in closure) { + val capturedName = usageTracker.capturedDescriptorToJsName[capturedValue]!! + constructorFunction.parameters.add(additionalParameterIndex++, JsParameter(capturedName)) + leadingArgs.add(capturedName.makeRef()) + } + } - this - } + if (outerName != null) { + constructorFunction.parameters.add(additionalParameterIndex, JsParameter(outerName)) + leadingArgs.add(outerName.makeRef()) + } + + constructorFunction.parameters.add(JsParameter(thisName)) + + // Insert super/this call to beginning of function + if (superCall != null) { + forAddToBeginning.add(superCall.toInvocationWith(leadingArgs, thisNameRef).makeStmt()) + } + + val delegationCtorInTheSameClass = delegationClassDescriptor == classDescriptor + if (!delegationCtorInTheSameClass && !classDescriptor.hasPrimaryConstructor()) { + forAddToBeginning.add(JsInvocation(Namer.getFunctionCallRef(referenceToClass), listOf(thisNameRef) + leadingArgs).makeStmt()) + } with(constructorFunction.body.statements) { addAll(0, forAddToBeginning) 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 1b17b1a0d74..a4bfbfc64a2 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 @@ -572,9 +572,8 @@ public final class ExpressionVisitor extends TranslatorVisitor { JsObjectScope scope = new JsObjectScope(context.scope(), descriptor.toString(), ""); TranslationContext classContext = context.innerWithUsageTracker(scope, descriptor); - JsInvocation jsClass = ClassTranslator.generateClassCreation(klass, classContext); + context.getDefinitionPlace().getProperties().addAll(ClassTranslator.Companion.translate(klass, classContext)); - JsName name = context.getNameForDescriptor(descriptor); - return context.define(name, jsClass); + return JsEmpty.INSTANCE; } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/ManglingUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/ManglingUtils.java index 2f445700c56..8af1e2af610 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/ManglingUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/ManglingUtils.java @@ -40,7 +40,7 @@ import static org.jetbrains.kotlin.resolve.DescriptorUtils.getFqName; public class ManglingUtils { private ManglingUtils() {} - public static final Comparator CALLABLE_COMPARATOR = new CallableComparator(); + private static final Comparator CALLABLE_COMPARATOR = new CallableComparator(); @NotNull public static String getMangledName(@NotNull PropertyDescriptor descriptor, @NotNull String suggestedName) { @@ -49,7 +49,7 @@ public class ManglingUtils { @NotNull public static String getSuggestedName(@NotNull DeclarationDescriptor descriptor) { - String suggestedName = descriptor.getName().asString(); + String suggestedName = descriptor.getName().isSpecial() ? "f" : descriptor.getName().getIdentifier(); if (descriptor instanceof FunctionDescriptor || descriptor instanceof PropertyDescriptor && DescriptorUtils.isExtension((PropertyDescriptor) descriptor) @@ -57,9 +57,37 @@ public class ManglingUtils { suggestedName = getMangledName((CallableMemberDescriptor) descriptor); } + ClassDescriptor localClass = null; + if (descriptor instanceof ConstructorDescriptor) { + ConstructorDescriptor constructor = (ConstructorDescriptor) descriptor; + localClass = constructor.getContainingDeclaration(); + } + else if (descriptor instanceof ClassDescriptor) { + localClass = (ClassDescriptor) descriptor; + } + + if (DescriptorUtils.isDescriptorWithLocalVisibility(localClass)) { + suggestedName = getSuggestedLocalPrefix(localClass) + suggestedName; + } + return suggestedName; } + @NotNull + private static String getSuggestedLocalPrefix(@NotNull DeclarationDescriptor descriptor) { + List parts = new ArrayList(); + while (true) { + descriptor = descriptor.getContainingDeclaration(); + if (descriptor == null || descriptor instanceof ClassOrPackageFragmentDescriptor) { + break; + } + parts.add(descriptor.getName().isSpecial() ? "f" : descriptor.getName().getIdentifier()); + } + + Collections.reverse(parts); + return StringUtil.join(parts, "$") + "$"; + } + @NotNull private static String getMangledName(@NotNull CallableMemberDescriptor descriptor) { if (needsStableMangling(descriptor)) { @@ -142,7 +170,7 @@ public class ManglingUtils { @NotNull private static String getSuggestedName(@NotNull CallableDescriptor descriptor) { if (descriptor instanceof ConstructorDescriptor && !((ConstructorDescriptor) descriptor).isPrimary()) { - return descriptor.getContainingDeclaration().getName().asString(); + return descriptor.getContainingDeclaration().getName().asString() + "_init"; } else { return descriptor.getName().asString();