diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/descriptorUtils/descriptorUtils.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/descriptorUtils/descriptorUtils.kt index fb6c7bb9e58..ef3a4e7a305 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/descriptorUtils/descriptorUtils.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/descriptorUtils/descriptorUtils.kt @@ -16,16 +16,13 @@ package org.jetbrains.kotlin.js.descriptorUtils -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.ClassifierDescriptor +import com.intellij.openapi.util.text.StringUtil +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.types.JetType -import org.jetbrains.kotlin.types.TypeProjection - -import com.intellij.openapi.util.text.StringUtil import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.types.JetType public val JetType.nameIfStandardType: Name? get() { @@ -56,4 +53,6 @@ public fun JetType.getJetTypeFqName(printTypeArguments: Boolean): String { } return DescriptorUtils.getFqName(declaration).asString() + typeArgumentsAsString -} \ No newline at end of file +} + +public fun ClassDescriptor.hasPrimaryConstructor(): Boolean = getUnsubstitutedPrimaryConstructor() != null 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 fa6e9b5e0d8..7fcc89ea963 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 @@ -211,7 +211,12 @@ object ConstructorCallCase : FunctionCallCase { val functionRef = if (isNative()) fqName else context.aliasOrValue(callableDescriptor) { fqName } - return JsNew(functionRef, argumentsInfo.translateArguments) + if((callableDescriptor as ConstructorDescriptor).isPrimary()) { + return JsNew(functionRef, argumentsInfo.translateArguments) + } + else { + return JsInvocation(functionRef, listOf(JsLiteral.UNDEFINED) + argumentsInfo.translateArguments) + } } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java index 5a7e116312a..0128e3a84f2 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java @@ -86,6 +86,7 @@ public final class Namer { private static final String ROOT_PACKAGE = "_"; private static final String RECEIVER_PARAMETER_NAME = "$receiver"; + public static final String ANOTHER_THIS_PARAMETER_NAME = "$this"; private static final String THROW_NPE_FUN_NAME = "throwNPE"; private static final String COMPANION_OBJECT_GETTER = "object"; @@ -98,6 +99,9 @@ public final class Namer { @NotNull public static final JsExpression UNDEFINED_EXPRESSION = new JsPrefixOperation(JsUnaryOperator.VOID, JsNumberLiteral.ZERO); + private static final JsNameRef JS_OBJECT = new JsNameRef("Object"); + private static final JsNameRef JS_OBJECT_CREATE_FUNCTION = new JsNameRef("create", JS_OBJECT); + public static boolean isUndefined(@NotNull JsExpression expr) { if (expr instanceof JsPrefixOperation) { JsUnaryOperator op = ((JsPrefixOperation) expr).getOperator(); @@ -216,6 +220,11 @@ public final class Namer { return new JsNameRef(APPLY_FUNCTION, functionExpression); } + @NotNull + public static JsInvocation createObjectWithPrototypeFrom(JsNameRef referenceToClass) { + return new JsInvocation(JS_OBJECT_CREATE_FUNCTION, getRefToPrototype(referenceToClass)); + } + @NotNull public static JsNameRef getCapturedVarAccessor(@NotNull JsExpression ref) { return new JsNameRef(CAPTURED_VAR_FIELD, ref); 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 b08a5402514..dbc06e97bb3 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 @@ -22,6 +22,7 @@ import com.intellij.openapi.util.Factory; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; 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; @@ -35,7 +36,6 @@ 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.TasksPackage; -import org.jetbrains.kotlin.builtins.ReflectionTypes; import java.util.Map; @@ -267,7 +267,9 @@ public final class StaticContext { Rule constructorOrCompanionObjectHasTheSameNameAsTheClass = new Rule() { @Override public JsName apply(@NotNull DeclarationDescriptor descriptor) { - if (descriptor instanceof ConstructorDescriptor || (DescriptorUtils.isCompanionObject(descriptor))) { + if (descriptor instanceof ConstructorDescriptor && ((ConstructorDescriptor) descriptor).isPrimary() || + DescriptorUtils.isCompanionObject(descriptor) + ) { //noinspection ConstantConditions return getNameForDescriptor(descriptor.getContainingDeclaration()); } 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 60e449a9417..4f31f9dbddb 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 @@ -20,11 +20,11 @@ import com.google.dart.compiler.backend.js.ast.*; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.builtins.ReflectionTypes; import org.jetbrains.kotlin.descriptors.CallableDescriptor; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.MemberDescriptor; import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor; -import org.jetbrains.kotlin.diagnostics.DiagnosticSink; import org.jetbrains.kotlin.js.config.Config; import org.jetbrains.kotlin.js.translate.intrinsic.Intrinsics; import org.jetbrains.kotlin.js.translate.utils.TranslationUtils; @@ -32,7 +32,6 @@ import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.JetExpression; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingTrace; -import org.jetbrains.kotlin.builtins.ReflectionTypes; import java.util.HashMap; import java.util.Map; @@ -130,6 +129,12 @@ public class TranslationContext { return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, place); } + @NotNull + public TranslationContext newDeclarationWithScope(@NotNull DeclarationDescriptor descriptor, @NotNull JsScope scope) { + DynamicContext dynamicContext = DynamicContext.newContext(scope, getBlockForDescriptor(descriptor)); + return new TranslationContext(this, staticContext, dynamicContext, aliasingContext, usageTracker, this.getDefinitionPlace()); + } + @NotNull private TranslationContext innerWithAliasingContext(AliasingContext aliasingContext) { return new TranslationContext(this, this.staticContext, this.dynamicContext, aliasingContext, this.usageTracker, null); 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 335d44cec82..bd95457ece9 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 @@ -22,30 +22,32 @@ import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.backend.common.bridges.Bridge import org.jetbrains.kotlin.backend.common.bridges.generateBridgesForFunctionDescriptor import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ClassKind -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.js.descriptorUtils.hasPrimaryConstructor +import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator import org.jetbrains.kotlin.js.translate.context.DefinitionPlace import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.TranslationContext import org.jetbrains.kotlin.js.translate.declaration.propertyTranslator.translateAccessors +import org.jetbrains.kotlin.js.translate.expression.FunctionTranslator import org.jetbrains.kotlin.js.translate.expression.withCapturedParameters import org.jetbrains.kotlin.js.translate.general.AbstractTranslator import org.jetbrains.kotlin.js.translate.initializer.ClassInitializerTranslator import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator.translateAsFQReference +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.ID -import org.jetbrains.kotlin.js.translate.utils.JsAstUtils import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getReceiverParameterForDeclaration 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.JetClass import org.jetbrains.kotlin.psi.JetClass import org.jetbrains.kotlin.psi.JetClassOrObject import org.jetbrains.kotlin.psi.JetObjectDeclaration +import org.jetbrains.kotlin.psi.JetSecondaryConstructor +import org.jetbrains.kotlin.resolve.BindingContextUtils import org.jetbrains.kotlin.resolve.DescriptorUtils.* import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.TypeConstructor @@ -71,7 +73,7 @@ public class ClassTranslator private constructor( return translateObjectInsideClass(context()) } - public fun translate(declarationContext: TranslationContext = context()): JsInvocation { + private fun translate(declarationContext: TranslationContext = context()): JsInvocation { return JsInvocation(context().namer().classCreateInvocation(descriptor), getClassCreateInvocationArguments(declarationContext)) } @@ -279,6 +281,10 @@ public class ClassTranslator private constructor( result.add(JsPropertyInitializer(classNameRef, classCreation)) + classDeclaration.getSecondaryConstructors().forEach { + result.add(generateSecondaryConstructor(it, context)) + } + return result } @@ -291,5 +297,54 @@ public class ClassTranslator private constructor( public fun generateObjectLiteral(objectDeclaration: JetObjectDeclaration, context: TranslationContext): JsExpression { return ClassTranslator(objectDeclaration, context).translateObjectLiteralExpression() } + + private fun generateSecondaryConstructor(constructor: JetSecondaryConstructor, context: TranslationContext): JsPropertyInitializer { + val constructorDescriptor = BindingUtils.getDescriptorForElement(context.bindingContext(), constructor) as ConstructorDescriptor + val classDescriptor = constructorDescriptor.getContainingDeclaration() + + val constructorScope = context.getScopeForDescriptor(constructorDescriptor) + val thisName = constructorScope.declareName(Namer.ANOTHER_THIS_PARAMETER_NAME) + val thisNameRef = thisName.makeRef() + val receiverDescriptor = JsDescriptorUtils.getReceiverParameterForDeclaration(classDescriptor) + val translationContext = context.innerContextWithAliased(receiverDescriptor, thisNameRef) + + val constructorInitializer = FunctionTranslator.newInstance(constructor, translationContext).translateAsMethod() + val constructorFunction = constructorInitializer.getValueExpr() as JsFunction + + constructorFunction.getParameters().add(0, JsParameter(thisName)) + + val referenceToClass = context.getQualifiedReference(classDescriptor) + + val forAddToBeginning: List = + with(arrayListOf()) { + addAll(FunctionBodyTranslator.setDefaultValueForArguments(constructorDescriptor, context)) + + val createInstance = Namer.createObjectWithPrototypeFrom(referenceToClass) + val instanceVar = JsAstUtils.assignment(thisNameRef, JsAstUtils.or(thisNameRef, createInstance)).makeStmt() + add(instanceVar) + + val resolvedCall = BindingContextUtils.getDelegationConstructorCall(context.bindingContext(), constructorDescriptor) + val delegationClassDescriptor = resolvedCall?.getResultingDescriptor()?.getContainingDeclaration() + + if (resolvedCall != null && !KotlinBuiltIns.isAny(delegationClassDescriptor!!)) { + val superCall = CallTranslator.translate(context, resolvedCall) + add(superCall.toInvocationWith(thisNameRef).makeStmt()) + } + + val delegationCtorInTheSameClass = delegationClassDescriptor == classDescriptor + if (!delegationCtorInTheSameClass && !classDescriptor.hasPrimaryConstructor()) { + add(JsInvocation(Namer.getFunctionCallRef(referenceToClass), thisNameRef).makeStmt()) + } + + this + } + + with(constructorFunction.getBody().getStatements()) { + addAll(0, forAddToBeginning) + add(JsReturn(thisNameRef)) + } + + return constructorInitializer + } } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.java index 1e3978f134d..195fa18d471 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/declaration/DeclarationBodyVisitor.java @@ -126,4 +126,9 @@ public class DeclarationBodyVisitor extends TranslatorVisitor { // parsed it in initializer visitor => no additional actions are needed return null; } + + @Override + public Void visitSecondaryConstructor(@NotNull JetSecondaryConstructor constructor, TranslationContext data) { + return 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 c14229458f8..29630c6d8ad 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 @@ -18,11 +18,13 @@ package org.jetbrains.kotlin.js.translate.expression; import com.google.dart.compiler.backend.js.ast.*; import com.google.dart.compiler.backend.js.ast.metadata.MetadataPackage; +import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.FunctionDescriptor; import org.jetbrains.kotlin.descriptors.VariableDescriptor; +import org.jetbrains.kotlin.js.translate.context.Namer; import org.jetbrains.kotlin.js.translate.context.TranslationContext; import org.jetbrains.kotlin.js.translate.declaration.ClassTranslator; import org.jetbrains.kotlin.js.translate.expression.loopTranslator.LoopTranslatorPackage; @@ -135,6 +137,12 @@ public final class ExpressionVisitor extends TranslatorVisitor { public JsNode visitReturnExpression(@NotNull JetReturnExpression jetReturnExpression, @NotNull TranslationContext context) { JetExpression returned = jetReturnExpression.getReturnedExpression(); + + // TODO: add related descriptor to context and use it here + JetDeclarationWithBody parent = PsiTreeUtil.getParentOfType(jetReturnExpression, JetDeclarationWithBody.class); + if (parent instanceof JetSecondaryConstructor) { + return new JsReturn(new JsNameRef(Namer.ANOTHER_THIS_PARAMETER_NAME)).source(jetReturnExpression); + } if (returned == null) { return new JsReturn(null).source(jetReturnExpression); } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.java index a60983a1f54..f62b01414c7 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/FunctionTranslator.java @@ -32,7 +32,6 @@ import org.jetbrains.kotlin.psi.JetDeclarationWithBody; import org.jetbrains.kotlin.psi.JetFunctionLiteralExpression; import org.jetbrains.kotlin.resolve.DescriptorUtils; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -115,7 +114,7 @@ public final class FunctionTranslator extends AbstractTranslator { private void translateBody() { if (!functionDeclaration.hasBody()) { - assert descriptor.getModality().equals(Modality.ABSTRACT); + assert descriptor instanceof ConstructorDescriptor || descriptor.getModality().equals(Modality.ABSTRACT); return; } functionObject.getBody().getStatements().addAll(translateFunctionBody(descriptor, functionDeclaration, functionBodyContext).getStatements()); 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 8cf6ded4ff4..4db772e4dbc 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 @@ -20,19 +20,15 @@ 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.ConstructorDescriptor; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.descriptors.PropertyDescriptor; +import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator; import org.jetbrains.kotlin.js.translate.context.Namer; import org.jetbrains.kotlin.js.translate.context.TranslationContext; 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.lexer.JetTokens; -import org.jetbrains.kotlin.psi.JetClassOrObject; -import org.jetbrains.kotlin.psi.JetDelegationSpecifier; -import org.jetbrains.kotlin.psi.JetDelegatorToSuperCall; -import org.jetbrains.kotlin.psi.JetParameter; +import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.types.JetType; @@ -44,6 +40,7 @@ import java.util.List; import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.*; import static org.jetbrains.kotlin.js.translate.utils.FunctionBodyTranslator.setDefaultValueForArguments; import static org.jetbrains.kotlin.js.translate.utils.PsiUtils.getPrimaryConstructorParameters; +import static org.jetbrains.kotlin.js.translate.utils.jsAstUtils.JsAstUtilsPackage.toInvocationWith; import static org.jetbrains.kotlin.resolve.DescriptorUtils.getClassDescriptorForType; public final class ClassInitializerTranslator extends AbstractTranslator { @@ -56,26 +53,39 @@ public final class ClassInitializerTranslator extends AbstractTranslator { @NotNull JetClassOrObject classDeclaration, @NotNull TranslationContext context ) { - // Note: it's important we use scope for class descriptor because anonymous function used in property initializers - // belong to the properties themselves - super(context.newDeclaration(getConstructor(context.bindingContext(), classDeclaration), null)); + super(context.newDeclarationWithScope( + getClassDescriptor(context.bindingContext(), classDeclaration), + new JsFunctionScope(context.scope(), "scope for primary/default constructor"))); this.classDeclaration = classDeclaration; } @NotNull public JsFunction generateInitializeMethod(DelegationTranslator delegationTranslator) { //TODO: it's inconsistent that we have scope for class and function for constructor, currently have problems implementing better way - ConstructorDescriptor primaryConstructor = getConstructor(bindingContext(), classDeclaration); - JsFunction result = context().getFunctionObject(primaryConstructor); - //NOTE: while we translate constructor parameters we also add property initializer statements - // for properties declared as constructor parameters - result.getParameters().addAll(translatePrimaryConstructorParameters()); - mayBeAddCallToSuperMethod(result); + ClassDescriptor classDescriptor = getClassDescriptor(bindingContext(), classDeclaration); + ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); + + JsFunction result; + if (primaryConstructor != null) { + result = context().getFunctionObject(primaryConstructor); + + result.getBody().getStatements().addAll(setDefaultValueForArguments(primaryConstructor, context())); + + //NOTE: while we translate constructor parameters we also add property initializer statements + // for properties declared as constructor parameters + result.getParameters().addAll(translatePrimaryConstructorParameters()); + + mayBeAddCallToSuperMethod(result); + } + else { + result = new JsFunction(context().scope(), new JsBlock(), "fake constructor for " + classDescriptor.getName().asString()); + } + delegationTranslator.addInitCode(initializerStatements); new InitializerVisitor(initializerStatements).traverseContainer(classDeclaration, context()); List statements = result.getBody().getStatements(); - statements.addAll(setDefaultValueForArguments(primaryConstructor, context())); + for (JsStatement statement : initializerStatements) { if (statement instanceof JsBlock) { statements.addAll(((JsBlock) statement).getStatements()); @@ -90,15 +100,15 @@ public final class ClassInitializerTranslator extends AbstractTranslator { @NotNull public JsExpression generateEnumEntryInstanceCreation(@NotNull JetType enumClassType) { - JetDelegatorToSuperCall superCall = getSuperCall(); - List arguments; - if (superCall != null) { - arguments = translateArguments(superCall); - } else { - arguments = Collections.emptyList(); + ResolvedCall superCall = getSuperCall(); + + if (superCall == null) { + ClassDescriptor classDescriptor = getClassDescriptorForType(enumClassType); + JsNameRef reference = context().getQualifiedReference(classDescriptor); + return new JsNew(reference); } - JsNameRef reference = context().getQualifiedReference(getClassDescriptorForType(enumClassType)); - return new JsNew(reference, arguments); + + return CallTranslator.translate(context(), superCall); } private void mayBeAddCallToSuperMethod(JsFunction initializer) { @@ -107,11 +117,18 @@ public final class ClassInitializerTranslator extends AbstractTranslator { return; } if (hasAncestorClass(bindingContext(), classDeclaration)) { - JetDelegatorToSuperCall superCall = getSuperCall(); - if (superCall == null) { - return; + ResolvedCall superCall = getSuperCall(); + if (superCall == null) return; + + if (classDeclaration instanceof JetEnumEntry) { + JsExpression expression = CallTranslator.translate(context(), superCall, null); + JsExpression fixedInvocation = toInvocationWith(expression, JsLiteral.THIS); + initializerStatements.add(0, fixedInvocation.makeStmt()); + } + else { + List arguments = CallArgumentTranslator.translate(superCall, null, context()).getTranslateArguments(); + addCallToSuperMethod(arguments, initializer); } - addCallToSuperMethod(translateArguments(superCall), initializer); } } @@ -124,21 +141,16 @@ public final class ClassInitializerTranslator extends AbstractTranslator { initializerStatements.add(0, call.makeStmt()); } - @NotNull - private List translateArguments(@NotNull JetDelegatorToSuperCall superCall) { - ResolvedCall call = CallUtilPackage.getResolvedCallWithAssert(superCall, context().bindingContext()); - return CallArgumentTranslator.translate(call, null, context()).getTranslateArguments(); - } - @Nullable - private JetDelegatorToSuperCall getSuperCall() { - JetDelegatorToSuperCall result = null; + private ResolvedCall getSuperCall() { for (JetDelegationSpecifier specifier : classDeclaration.getDelegationSpecifiers()) { if (specifier instanceof JetDelegatorToSuperCall) { - result = (JetDelegatorToSuperCall) specifier; + JetDelegatorToSuperCall superCall = (JetDelegatorToSuperCall) specifier; + //noinspection unchecked + return (ResolvedCall) CallUtilPackage.getResolvedCallWithAssert(superCall, bindingContext()); } } - return result; + return null; } @NotNull diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/InitializerVisitor.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/InitializerVisitor.java index b21488c2e56..1470e599c1b 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/InitializerVisitor.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/initializer/InitializerVisitor.java @@ -78,4 +78,9 @@ public final class InitializerVisitor extends TranslatorVisitor { } return null; } + + @Override + public Void visitSecondaryConstructor(@NotNull JetSecondaryConstructor constructor, TranslationContext data) { + return null; + } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/BindingUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/BindingUtils.java index 80acae1d609..e54e943e65a 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/BindingUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/BindingUtils.java @@ -220,17 +220,4 @@ public final class BindingUtils { boolean isGet) { return BindingContextUtils.getNotNull(context, isGet ? INDEXED_LVALUE_GET : INDEXED_LVALUE_SET, arrayAccessExpression); } - - public static ConstructorDescriptor getConstructor(@NotNull BindingContext bindingContext, - @NotNull JetClassOrObject declaration) { - ConstructorDescriptor primaryConstructor = getClassDescriptor(bindingContext, declaration).getUnsubstitutedPrimaryConstructor(); - assert primaryConstructor != null : message(declaration, "Traits do not have initialize methods"); - return primaryConstructor; - } - - @Nullable - public static SimpleFunctionDescriptor getNullableDescriptorForFunction(@NotNull BindingContext bindingContext, - @NotNull JetNamedFunction function) { - return bindingContext.get(BindingContext.FUNCTION, function); - } } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsDescriptorUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsDescriptorUtils.java index 409867af32f..3862c2f8213 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsDescriptorUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/JsDescriptorUtils.java @@ -118,6 +118,7 @@ public final class JsDescriptorUtils { ", receiverParameter = " + receiverParameter); } + @NotNull public static ReceiverParameterDescriptor getReceiverParameterForDeclaration(DeclarationDescriptor declarationDescriptor) { if (declarationDescriptor instanceof ClassDescriptor) { return ((ClassDescriptor) declarationDescriptor).getThisAsReceiverParameter(); 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 4099be784ec..e97c682ce00 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 @@ -19,9 +19,13 @@ package org.jetbrains.kotlin.js.translate.utils; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; +import kotlin.KotlinPackage; +import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.backend.common.CodegenUtil; import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.descriptors.annotations.Annotations; +import org.jetbrains.kotlin.descriptors.impl.ConstructorDescriptorImpl; import org.jetbrains.kotlin.name.FqNameUnsafe; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.resolve.DescriptorUtils; @@ -31,12 +35,13 @@ import org.jetbrains.kotlin.resolve.scopes.JetScope; import java.util.*; import static org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsPackage.getJetTypeFqName; +import static org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsPackage.hasPrimaryConstructor; import static org.jetbrains.kotlin.resolve.DescriptorUtils.getFqName; public class ManglingUtils { private ManglingUtils() {} - public static final Comparator OVERLOADED_MEMBER_COMPARATOR = new OverloadedMemberComparator(); + public static final Comparator CALLABLE_COMPARATOR = new CallableComparator(); @NotNull public static String getMangledName(@NotNull PropertyDescriptor descriptor, @NotNull String suggestedName) { @@ -131,30 +136,66 @@ public class ManglingUtils { @NotNull private static String getStableMangledName(@NotNull CallableDescriptor descriptor) { - return getStableMangledName(descriptor.getName().asString(), getArgumentTypesAsString(descriptor)); + String suggestedName = getSuggestedName(descriptor); + return getStableMangledName(suggestedName, getArgumentTypesAsString(descriptor)); } @NotNull - private static String getSimpleMangledName(@NotNull final CallableMemberDescriptor descriptor) { - DeclarationDescriptor declaration = descriptor.getContainingDeclaration(); + private static String getSuggestedName(@NotNull CallableDescriptor descriptor) { + if (descriptor instanceof ConstructorDescriptor && !((ConstructorDescriptor) descriptor).isPrimary()) { + DeclarationDescriptor classDescriptor = descriptor.getContainingDeclaration(); + assert classDescriptor != null; + return classDescriptor.getName().asString(); + } + else { + return descriptor.getName().asString(); + } + } + + @NotNull + private static String getSimpleMangledName(@NotNull CallableMemberDescriptor descriptor) { + DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); JetScope jetScope = null; - if (declaration instanceof PackageFragmentDescriptor) { - jetScope = ((PackageFragmentDescriptor) declaration).getMemberScope(); + + String nameToCompare = descriptor.getName().asString(); + + if (containingDeclaration != null && descriptor instanceof ConstructorDescriptor) { + nameToCompare = containingDeclaration.getName().asString(); + containingDeclaration = containingDeclaration.getContainingDeclaration(); } - else if (declaration instanceof ClassDescriptor) { - jetScope = ((ClassDescriptor) declaration).getDefaultType().getMemberScope(); + + if (containingDeclaration instanceof PackageFragmentDescriptor) { + jetScope = ((PackageFragmentDescriptor) containingDeclaration).getMemberScope(); + } + else if (containingDeclaration instanceof ClassDescriptor) { + jetScope = ((ClassDescriptor) containingDeclaration).getDefaultType().getMemberScope(); } int counter = 0; if (jetScope != null) { + final String finalNameToCompare = nameToCompare; + Collection declarations = jetScope.getDescriptors(DescriptorKindFilter.CALLABLES, JetScope.ALL_NAME_FILTER); - List - overloadedFunctions = ContainerUtil.mapNotNull(declarations, new Function() { + List overloadedFunctions = + KotlinPackage.flatMap(declarations, new Function1>() { @Override - public CallableMemberDescriptor fun(DeclarationDescriptor declarationDescriptor) { - if (!(declarationDescriptor instanceof CallableMemberDescriptor)) return null; + public Iterable invoke(DeclarationDescriptor declarationDescriptor) { + if (declarationDescriptor instanceof ClassDescriptor && finalNameToCompare.equals(declarationDescriptor.getName().asString())) { + ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; + Collection constructors = classDescriptor.getConstructors(); + + if (!hasPrimaryConstructor(classDescriptor)) { + ConstructorDescriptorImpl fakePrimaryConstructor = + ConstructorDescriptorImpl.create(classDescriptor, Annotations.EMPTY, true, SourceElement.NO_SOURCE); + return KotlinPackage.plus(constructors, fakePrimaryConstructor); + } + + return constructors; + } + + if (!(declarationDescriptor instanceof CallableMemberDescriptor)) return Collections.emptyList(); CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) declarationDescriptor; @@ -163,24 +204,26 @@ public class ManglingUtils { // when name == null it's mean that it's not native. if (name == null) { // skip functions without arguments, because we don't use mangling for them - if (needsStableMangling(callableMemberDescriptor) && !callableMemberDescriptor.getValueParameters().isEmpty()) return null; + if (needsStableMangling(callableMemberDescriptor) && !callableMemberDescriptor.getValueParameters().isEmpty()) return Collections.emptyList(); // TODO add prefix for property: get_$name and set_$name name = callableMemberDescriptor.getName().asString(); } - return descriptor.getName().asString().equals(name) ? callableMemberDescriptor : null; + if (finalNameToCompare.equals(name)) return Collections.singletonList(callableMemberDescriptor); + + return Collections.emptyList(); } }); if (overloadedFunctions.size() > 1) { - Collections.sort(overloadedFunctions, OVERLOADED_MEMBER_COMPARATOR); + Collections.sort(overloadedFunctions, CALLABLE_COMPARATOR); counter = ContainerUtil.indexOfIdentity(overloadedFunctions, descriptor); assert counter >= 0; } } - String name = descriptor.getName().asString(); + String name = getSuggestedName(descriptor); return counter == 0 ? name : name + '_' + counter; } @@ -206,13 +249,21 @@ public class ManglingUtils { public static String getStableMangledNameForDescriptor(@NotNull ClassDescriptor descriptor, @NotNull String functionName) { Collection functions = descriptor.getDefaultType().getMemberScope().getFunctions(Name.identifier(functionName)); assert functions.size() == 1 : "Can't select a single function: " + functionName + " in " + descriptor; - return getSuggestedName(functions.iterator().next()); + return getSuggestedName((DeclarationDescriptor) functions.iterator().next()); } - private static class OverloadedMemberComparator implements Comparator { + private static class CallableComparator implements Comparator { @Override - public int compare(@NotNull CallableMemberDescriptor a, @NotNull CallableMemberDescriptor b) { - // native functions first + public int compare(@NotNull CallableDescriptor a, @NotNull CallableDescriptor b) { + // primary constructors + if (a instanceof ConstructorDescriptor && ((ConstructorDescriptor) a).isPrimary()) { + if (!(b instanceof ConstructorDescriptor) || !((ConstructorDescriptor) b).isPrimary()) return -1; + } + else if (b instanceof ConstructorDescriptor && ((ConstructorDescriptor) b).isPrimary()) { + return 1; + } + + // native functions if (isNativeOrOverrideNative(a)) { if (!isNativeOrOverrideNative(b)) return -1; } @@ -238,14 +289,16 @@ public class ManglingUtils { return aArguments.compareTo(bArguments); } - private static int arity(CallableMemberDescriptor descriptor) { + private static int arity(CallableDescriptor descriptor) { return descriptor.getValueParameters().size() + (descriptor.getExtensionReceiverParameter() == null ? 0 : 1); } - private static boolean isNativeOrOverrideNative(CallableMemberDescriptor descriptor) { + private static boolean isNativeOrOverrideNative(CallableDescriptor descriptor) { + if (!(descriptor instanceof CallableMemberDescriptor)) return false; + if (AnnotationsUtils.isNativeObject(descriptor)) return true; - Set declarations = DescriptorUtils.getAllOverriddenDeclarations(descriptor); + Set declarations = DescriptorUtils.getAllOverriddenDeclarations((CallableMemberDescriptor) descriptor); for (CallableMemberDescriptor memberDescriptor : declarations) { if (AnnotationsUtils.isNativeObject(memberDescriptor)) return true; } 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 7b73d3f8e9a..8d38676c837 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 @@ -146,7 +146,17 @@ public final class TranslationUtils { } backingFieldName = context.declarePropertyOrPropertyAccessorName(descriptor, backingFieldMangledName, false); } - return new JsNameRef(backingFieldName, JsLiteral.THIS); + + DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration(); + JsExpression receiver; + if (containingDescriptor instanceof PackageFragmentDescriptor) { + // used inside package initializer + receiver = JsLiteral.THIS; + } + else { + receiver = context.getDispatchReceiver(JsDescriptorUtils.getReceiverParameterForDeclaration(containingDescriptor)); + } + return new JsNameRef(backingFieldName, receiver); } @NotNull diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/astUtils.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/astUtils.kt index 2b06f5baf40..c4cdd53e577 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/astUtils.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/astUtils.kt @@ -17,7 +17,7 @@ package org.jetbrains.kotlin.js.translate.utils.jsAstUtils import com.google.dart.compiler.backend.js.ast.* -import org.jetbrains.kotlin.js.inline.util.IdentitySet +import org.jetbrains.kotlin.js.translate.context.Namer public fun JsFunction.addStatement(stmt: JsStatement) { getBody().getStatements().add(stmt) @@ -56,6 +56,25 @@ public fun JsNode.any(predicate: (JsNode) -> Boolean): Boolean { return visitor.matched } +fun JsExpression.toInvocationWith(thisExpr: JsExpression): JsExpression { + val qualifier: JsExpression + val arguments: MutableList + + when (this) { + is JsNew -> { + qualifier = Namer.getFunctionCallRef(getConstructorExpression()) + arguments = getArguments() + } + is JsInvocation -> { + qualifier = getQualifier() + arguments = with(getArguments()) { subList(1, size()) } + } + else -> throw IllegalStateException("Unexpected node type: " + javaClass) + } + + return JsInvocation(qualifier, listOf(thisExpr) + arguments) +} + public var JsNameRef.qualifier: JsExpression? get() = getQualifier() set(value) = setQualifier(value)