JS backend: add the support secondary constructors
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
public fun ClassDescriptor.hasPrimaryConstructor(): Boolean = getUnsubstitutedPrimaryConstructor() != null
|
||||
|
||||
+6
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<JsName> constructorOrCompanionObjectHasTheSameNameAsTheClass = new Rule<JsName>() {
|
||||
@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());
|
||||
}
|
||||
|
||||
+7
-2
@@ -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);
|
||||
|
||||
+63
-8
@@ -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<JsStatement> =
|
||||
with(arrayListOf<JsStatement>()) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -126,4 +126,9 @@ public class DeclarationBodyVisitor extends TranslatorVisitor<Void> {
|
||||
// parsed it in initializer visitor => no additional actions are needed
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitSecondaryConstructor(@NotNull JetSecondaryConstructor constructor, TranslationContext data) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -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<JsNode> {
|
||||
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);
|
||||
}
|
||||
|
||||
+1
-2
@@ -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());
|
||||
|
||||
+51
-39
@@ -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<JsStatement> 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<JsExpression> arguments;
|
||||
if (superCall != null) {
|
||||
arguments = translateArguments(superCall);
|
||||
} else {
|
||||
arguments = Collections.emptyList();
|
||||
ResolvedCall<FunctionDescriptor> 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<FunctionDescriptor> 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<JsExpression> 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<JsExpression> 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<FunctionDescriptor> getSuperCall() {
|
||||
for (JetDelegationSpecifier specifier : classDeclaration.getDelegationSpecifiers()) {
|
||||
if (specifier instanceof JetDelegatorToSuperCall) {
|
||||
result = (JetDelegatorToSuperCall) specifier;
|
||||
JetDelegatorToSuperCall superCall = (JetDelegatorToSuperCall) specifier;
|
||||
//noinspection unchecked
|
||||
return (ResolvedCall<FunctionDescriptor>) CallUtilPackage.getResolvedCallWithAssert(superCall, bindingContext());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+5
@@ -78,4 +78,9 @@ public final class InitializerVisitor extends TranslatorVisitor<Void> {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitSecondaryConstructor(@NotNull JetSecondaryConstructor constructor, TranslationContext data) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<CallableMemberDescriptor> OVERLOADED_MEMBER_COMPARATOR = new OverloadedMemberComparator();
|
||||
public static final Comparator<CallableDescriptor> 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<DeclarationDescriptor> declarations = jetScope.getDescriptors(DescriptorKindFilter.CALLABLES, JetScope.ALL_NAME_FILTER);
|
||||
List<CallableMemberDescriptor>
|
||||
overloadedFunctions = ContainerUtil.mapNotNull(declarations, new Function<DeclarationDescriptor, CallableMemberDescriptor>() {
|
||||
List<CallableDescriptor> overloadedFunctions =
|
||||
KotlinPackage.flatMap(declarations, new Function1<DeclarationDescriptor, Iterable<? extends CallableDescriptor>>() {
|
||||
@Override
|
||||
public CallableMemberDescriptor fun(DeclarationDescriptor declarationDescriptor) {
|
||||
if (!(declarationDescriptor instanceof CallableMemberDescriptor)) return null;
|
||||
public Iterable<? extends CallableDescriptor> invoke(DeclarationDescriptor declarationDescriptor) {
|
||||
if (declarationDescriptor instanceof ClassDescriptor && finalNameToCompare.equals(declarationDescriptor.getName().asString())) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
|
||||
Collection<ConstructorDescriptor> 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<FunctionDescriptor> 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<CallableMemberDescriptor> {
|
||||
private static class CallableComparator implements Comparator<CallableDescriptor> {
|
||||
@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<CallableMemberDescriptor> declarations = DescriptorUtils.getAllOverriddenDeclarations(descriptor);
|
||||
Set<CallableMemberDescriptor> declarations = DescriptorUtils.getAllOverriddenDeclarations((CallableMemberDescriptor) descriptor);
|
||||
for (CallableMemberDescriptor memberDescriptor : declarations) {
|
||||
if (AnnotationsUtils.isNativeObject(memberDescriptor)) return true;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<JsExpression>
|
||||
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user