JS: update support of enum's values() and valueOf()
This commit is contained in:
@@ -28,6 +28,8 @@ import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
|
||||
import java.util.*;
|
||||
@@ -170,4 +172,18 @@ public class CodegenUtil {
|
||||
private static boolean rawTypeMatches(JetType type, ClassifierDescriptor classifier) {
|
||||
return type.getConstructor().getDeclarationDescriptor().getOriginal() == classifier.getOriginal();
|
||||
}
|
||||
|
||||
public static boolean isEnumValueOfMethod(@NotNull FunctionDescriptor functionDescriptor) {
|
||||
List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
|
||||
JetType nullableString = TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getStringType());
|
||||
return "valueOf".equals(functionDescriptor.getName().asString())
|
||||
&& methodTypeParameters.size() == 1
|
||||
&& JetTypeChecker.DEFAULT.isSubtypeOf(methodTypeParameters.get(0).getType(), nullableString);
|
||||
}
|
||||
|
||||
public static boolean isEnumValuesMethod(@NotNull FunctionDescriptor functionDescriptor) {
|
||||
List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
|
||||
return "values".equals(functionDescriptor.getName().asString())
|
||||
&& methodTypeParameters.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -928,7 +928,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
FunctionDescriptor valuesFunction = findEnumFunction("values", new Function1<FunctionDescriptor, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(FunctionDescriptor descriptor) {
|
||||
return isEnumValuesMethod(descriptor);
|
||||
return CodegenUtil.isEnumValuesMethod(descriptor);
|
||||
}
|
||||
});
|
||||
MethodVisitor mv = v.newMethod(OtherOrigin(myClass, valuesFunction), ACC_PUBLIC | ACC_STATIC, "values", "()" + type.getDescriptor(), null, null);
|
||||
@@ -946,7 +946,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
FunctionDescriptor valueOfFunction = findEnumFunction("valueOf", new Function1<FunctionDescriptor, Boolean>() {
|
||||
@Override
|
||||
public Boolean invoke(FunctionDescriptor descriptor) {
|
||||
return isEnumValueOfMethod(descriptor);
|
||||
return CodegenUtil.isEnumValueOfMethod(descriptor);
|
||||
}
|
||||
});
|
||||
MethodVisitor mv = v.newMethod(OtherOrigin(myClass, valueOfFunction),
|
||||
|
||||
@@ -44,8 +44,6 @@ import org.jetbrains.jet.lang.resolve.kotlin.incremental.IncrementalPackageFragm
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeUtils;
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
|
||||
import java.io.File;
|
||||
@@ -281,20 +279,6 @@ public class JvmCodegenUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isEnumValueOfMethod(@NotNull FunctionDescriptor functionDescriptor) {
|
||||
List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
|
||||
JetType nullableString = TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getStringType());
|
||||
return "valueOf".equals(functionDescriptor.getName().asString())
|
||||
&& methodTypeParameters.size() == 1
|
||||
&& JetTypeChecker.DEFAULT.isSubtypeOf(methodTypeParameters.get(0).getType(), nullableString);
|
||||
}
|
||||
|
||||
public static boolean isEnumValuesMethod(@NotNull FunctionDescriptor functionDescriptor) {
|
||||
List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
|
||||
return "values".equals(functionDescriptor.getName().asString())
|
||||
&& methodTypeParameters.isEmpty();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static CallableMemberDescriptor getDirectMember(@NotNull CallableMemberDescriptor descriptor) {
|
||||
return descriptor instanceof PropertyAccessorDescriptor
|
||||
|
||||
@@ -19,7 +19,7 @@ package org.jetbrains.jet.codegen.intrinsics;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.JvmCodegenUtil;
|
||||
import org.jetbrains.jet.backend.common.CodegenUtil;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
|
||||
@@ -203,11 +203,11 @@ public class IntrinsicMethods {
|
||||
DeclarationDescriptor container = descriptor.getContainingDeclaration();
|
||||
//noinspection ConstantConditions
|
||||
if (isClassObject(container) && isEnumClass(container.getContainingDeclaration())) {
|
||||
if (JvmCodegenUtil.isEnumValuesMethod(functionDescriptor)) {
|
||||
if (CodegenUtil.isEnumValuesMethod(functionDescriptor)) {
|
||||
return ENUM_VALUES;
|
||||
}
|
||||
|
||||
if (JvmCodegenUtil.isEnumValueOfMethod(functionDescriptor)) {
|
||||
if (CodegenUtil.isEnumValueOfMethod(functionDescriptor)) {
|
||||
return ENUM_VALUE_OF;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,13 +19,10 @@ package org.jetbrains.k2js.translate.context;
|
||||
import com.google.dart.compiler.backend.js.ast.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassKind;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.plugin.JetLanguage;
|
||||
|
||||
import static org.jetbrains.jet.lang.descriptors.ClassKind.TRAIT;
|
||||
|
||||
/**
|
||||
* Encapuslates different types of constants and naming conventions.
|
||||
*/
|
||||
@@ -40,9 +37,9 @@ public final class Namer {
|
||||
private static final String APPLY_FUNCTION = "apply";
|
||||
|
||||
private static final String CLASS_OBJECT_NAME = "createClass";
|
||||
private static final String ENUM_CLASS_OBJECT_NAME = "createEnumClass";
|
||||
private static final String TRAIT_OBJECT_NAME = "createTrait";
|
||||
private static final String OBJECT_OBJECT_NAME = "createObject";
|
||||
private static final String ENUM_ENTRIES_NAME = "createEnumEntries";
|
||||
private static final String CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME = "getCallableRefForMemberFunction";
|
||||
private static final String CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME = "getCallableRefForExtensionFunction";
|
||||
private static final String CALLABLE_REF_FOR_CONSTRUCTOR_NAME = "getCallableRefForConstructor";
|
||||
@@ -178,6 +175,8 @@ public final class Namer {
|
||||
@NotNull
|
||||
private final JsName className;
|
||||
@NotNull
|
||||
private final JsName enumClassName;
|
||||
@NotNull
|
||||
private final JsName traitName;
|
||||
@NotNull
|
||||
private final JsExpression definePackage;
|
||||
@@ -186,8 +185,6 @@ public final class Namer {
|
||||
@NotNull
|
||||
private final JsName objectName;
|
||||
@NotNull
|
||||
private final JsName enumEntriesName;
|
||||
@NotNull
|
||||
private final JsName callableRefForMemberFunctionName;
|
||||
@NotNull
|
||||
private final JsName callableRefForExtensionFunctionName;
|
||||
@@ -221,7 +218,7 @@ public final class Namer {
|
||||
callSetProperty = kotlin("callSetter");
|
||||
|
||||
className = kotlinScope.declareName(CLASS_OBJECT_NAME);
|
||||
enumEntriesName = kotlinScope.declareName(ENUM_ENTRIES_NAME);
|
||||
enumClassName = kotlinScope.declareName(ENUM_CLASS_OBJECT_NAME);
|
||||
objectName = kotlinScope.declareName(OBJECT_OBJECT_NAME);
|
||||
callableRefForMemberFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_MEMBER_FUNCTION_NAME);
|
||||
callableRefForExtensionFunctionName = kotlinScope.declareName(CALLABLE_REF_FOR_EXTENSION_FUNCTION_NAME);
|
||||
@@ -241,8 +238,8 @@ public final class Namer {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsExpression enumEntriesCreationMethodReference() {
|
||||
return kotlin(enumEntriesName);
|
||||
public JsExpression enumClassCreationMethodReference() {
|
||||
return kotlin(enumClassName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -321,7 +318,7 @@ public final class Namer {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
/*package*/ JsScope getKotlinScope() {
|
||||
/*package*/ JsScope getKotlinScope() {
|
||||
return kotlinScope;
|
||||
}
|
||||
|
||||
@@ -332,21 +329,24 @@ public final class Namer {
|
||||
|
||||
@NotNull
|
||||
public JsExpression classCreateInvocation(@NotNull ClassDescriptor descriptor) {
|
||||
ClassKind kind = descriptor.getKind();
|
||||
if (kind == TRAIT) {
|
||||
return traitCreationMethodReference();
|
||||
switch (descriptor.getKind()) {
|
||||
case TRAIT:
|
||||
return traitCreationMethodReference();
|
||||
case ENUM_CLASS:
|
||||
return enumClassCreationMethodReference();
|
||||
case ENUM_ENTRY:
|
||||
case OBJECT:
|
||||
case CLASS_OBJECT:
|
||||
return objectCreationMethodReference();
|
||||
case ANNOTATION_CLASS:
|
||||
throw new IllegalStateException("Can't create annotation class instance: " + descriptor);
|
||||
case CLASS:
|
||||
return DescriptorUtils.isAnonymousObject(descriptor)
|
||||
? objectCreationMethodReference()
|
||||
: classCreationMethodReference();
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unsupported class kind: " + descriptor);
|
||||
}
|
||||
|
||||
if (kind.isSingleton() || DescriptorUtils.isAnonymousObject(descriptor)) {
|
||||
return objectCreationMethodReference();
|
||||
}
|
||||
|
||||
return classCreationMethodReference();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JsInvocation enumEntriesObjectCreateInvocation() {
|
||||
return new JsInvocation(enumEntriesCreationMethodReference());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -37,7 +37,6 @@ import org.jetbrains.k2js.translate.utils.JsAstUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.jet.lang.descriptors.ClassKind.CLASS_OBJECT;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
||||
import static org.jetbrains.k2js.translate.utils.AnnotationsUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.*;
|
||||
@@ -502,12 +501,26 @@ public final class StaticContext {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
Rule<JsNameRef> staticMembersHaveContainerQualifier = new Rule<JsNameRef>() {
|
||||
@Override
|
||||
public JsNameRef apply(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof CallableDescriptor && !isNativeObject(descriptor)) {
|
||||
CallableDescriptor callableDescriptor = (CallableDescriptor) descriptor;
|
||||
if (DescriptorUtils.isStaticDeclaration(callableDescriptor)) {
|
||||
return getQualifiedReference(callableDescriptor.getContainingDeclaration());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
addRule(libraryObjectsHaveKotlinQualifier);
|
||||
addRule(constructorOrClassObjectHasTheSameQualifierAsTheClass);
|
||||
addRule(standardObjectsHaveKotlinQualifier);
|
||||
addRule(packageLevelDeclarationsHaveEnclosingPackagesNamesAsQualifier);
|
||||
addRule(nativeObjectsHaveNativePartOfFullQualifier);
|
||||
addRule(staticMembersHaveContainerQualifier);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,11 +42,9 @@ import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.topologicallySortSuperclassesAndRecordAllInstances;
|
||||
import static org.jetbrains.k2js.translate.initializer.InitializerUtils.createClassObjectInitializer;
|
||||
import static org.jetbrains.k2js.translate.reference.ReferenceTranslator.translateAsFQReference;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getClassDescriptor;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getPropertyDescriptorForConstructorParameter;
|
||||
import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.getContainingClass;
|
||||
import static org.jetbrains.k2js.translate.utils.JsDescriptorUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.PsiUtils.getPrimaryConstructorParameters;
|
||||
import static org.jetbrains.k2js.translate.utils.TranslationUtils.simpleReturnFunction;
|
||||
@@ -135,12 +133,17 @@ public final class ClassTranslator extends AbstractTranslator {
|
||||
DeclarationBodyVisitor bodyVisitor = new DeclarationBodyVisitor(properties, staticProperties);
|
||||
bodyVisitor.traverseContainer(classDeclaration, declarationContext);
|
||||
delegationTranslator.generateDelegated(properties);
|
||||
mayBeAddEnumEntry(bodyVisitor.getEnumEntryList(), staticProperties, declarationContext);
|
||||
|
||||
if (KotlinBuiltIns.getInstance().isData(descriptor)) {
|
||||
new JsDataClassGenerator(classDeclaration, declarationContext, properties).generate();
|
||||
}
|
||||
|
||||
if (isEnumClass(descriptor)) {
|
||||
JsObjectLiteral enumEntries = new JsObjectLiteral(bodyVisitor.getEnumEntryList(), true);
|
||||
JsFunction function = simpleReturnFunction(declarationContext.getScopeForDescriptor(descriptor), enumEntries);
|
||||
invocationArguments.add(function);
|
||||
}
|
||||
|
||||
boolean hasStaticProperties = !staticProperties.isEmpty();
|
||||
if (!properties.isEmpty() || hasStaticProperties) {
|
||||
if (properties.isEmpty()) {
|
||||
@@ -158,6 +161,7 @@ public final class ClassTranslator extends AbstractTranslator {
|
||||
invocationArguments.add(new JsDocComment(JsAstUtils.LENDS_JS_DOC_TAG, qualifiedReference));
|
||||
invocationArguments.add(new JsObjectLiteral(staticProperties, true));
|
||||
}
|
||||
|
||||
return invocationArguments;
|
||||
}
|
||||
|
||||
@@ -181,21 +185,6 @@ public final class ClassTranslator extends AbstractTranslator {
|
||||
return declarationContext;
|
||||
}
|
||||
|
||||
private void mayBeAddEnumEntry(@NotNull List<JsPropertyInitializer> enumEntryList,
|
||||
@NotNull List<JsPropertyInitializer> staticProperties,
|
||||
@NotNull TranslationContext declarationContext
|
||||
) {
|
||||
if (descriptor.getKind() == ClassKind.ENUM_CLASS) {
|
||||
JsInvocation invocation = context().namer().enumEntriesObjectCreateInvocation();
|
||||
invocation.getArguments().add(new JsObjectLiteral(enumEntryList, true));
|
||||
|
||||
JsFunction fun = simpleReturnFunction(declarationContext.getScopeForDescriptor(descriptor), invocation);
|
||||
staticProperties.add(createClassObjectInitializer(fun, declarationContext));
|
||||
} else {
|
||||
assert enumEntryList.isEmpty(): "Only enum class may have enum entry. Class kind is: " + descriptor.getKind();
|
||||
}
|
||||
}
|
||||
|
||||
private JsExpression getSuperclassReferences(@NotNull TranslationContext declarationContext) {
|
||||
List<JsExpression> superClassReferences = getSupertypesNameReferences();
|
||||
if (superClassReferences.isEmpty()) {
|
||||
|
||||
@@ -22,10 +22,10 @@ import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.backend.common.CodegenUtil;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
import org.jetbrains.jet.lang.resolve.OverrideResolver;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
@@ -41,7 +41,8 @@ import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getFqName;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isAnonymousObject;
|
||||
import static org.jetbrains.k2js.translate.context.Namer.getKotlinBackingFieldName;
|
||||
import static org.jetbrains.k2js.translate.utils.BindingUtils.getCallableDescriptorForOperationExpression;
|
||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.*;
|
||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.assignment;
|
||||
import static org.jetbrains.k2js.translate.utils.JsAstUtils.createDataDescriptor;
|
||||
|
||||
public final class TranslationUtils {
|
||||
public static final Comparator<FunctionDescriptor> OVERLOADED_FUNCTION_COMPARATOR = new OverloadedFunctionComparator();
|
||||
@@ -177,11 +178,16 @@ public final class TranslationUtils {
|
||||
else if (containingDeclaration instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
|
||||
|
||||
// Use stable mangling when it inside a overridable declaration for avoid clashing names when inheritance.
|
||||
// Use stable mangling when it's inside an overridable declaration to avoid clashing names on inheritance.
|
||||
if (classDescriptor.getModality().isOverridable()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// valueOf() is created in the library with a mangled name for every enum class
|
||||
if (CodegenUtil.isEnumValueOfMethod(descriptor)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't use stable mangling when it inside a non-public API declaration.
|
||||
if (!classDescriptor.getVisibility().isPublicAPI()) {
|
||||
return false;
|
||||
|
||||
@@ -231,34 +231,8 @@
|
||||
toString: function () {
|
||||
return this.name();
|
||||
}
|
||||
});
|
||||
(function () {
|
||||
function valueOf(name) {
|
||||
return this[name];
|
||||
}
|
||||
|
||||
function getValues() {
|
||||
return this.values$;
|
||||
}
|
||||
|
||||
Kotlin.createEnumEntries = function (enumEntryList) {
|
||||
var i = 0;
|
||||
var values = [];
|
||||
for (var entryName in enumEntryList) {
|
||||
if (enumEntryList.hasOwnProperty(entryName)) {
|
||||
var entryObject = enumEntryList[entryName];
|
||||
values[i] = entryObject;
|
||||
entryObject.ordinal$ = i;
|
||||
entryObject.name$ = entryName;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
enumEntryList.values$ = values;
|
||||
enumEntryList.valueOf_61zpoe$ = valueOf;
|
||||
enumEntryList.values = getValues;
|
||||
return enumEntryList;
|
||||
};
|
||||
})();
|
||||
);
|
||||
|
||||
Kotlin.PropertyMetadata = Kotlin.createClassNow(null,
|
||||
function (name) {
|
||||
|
||||
@@ -222,6 +222,41 @@ var Kotlin = {};
|
||||
return $o;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {(function():Array.<*>)|null} basesFun
|
||||
* @param {?=} constructor
|
||||
* @param {function():Object} enumEntries
|
||||
* @param {Object=} properties
|
||||
* @returns {*}
|
||||
*/
|
||||
Kotlin.createEnumClass = function (basesFun, constructor, enumEntries, properties) {
|
||||
return Kotlin.createClass(
|
||||
basesFun, constructor, properties, {
|
||||
object_initializer$: function () {
|
||||
var enumEntryList = enumEntries()
|
||||
var i = 0;
|
||||
var values = [];
|
||||
for (var entryName in enumEntryList) {
|
||||
if (enumEntryList.hasOwnProperty(entryName)) {
|
||||
var entryObject = enumEntryList[entryName];
|
||||
values[i] = entryObject;
|
||||
entryObject.ordinal$ = i;
|
||||
entryObject.name$ = entryName;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
enumEntryList.values$ = values;
|
||||
return enumEntryList;
|
||||
},
|
||||
values: function() {
|
||||
return this.object.values$;
|
||||
},
|
||||
valueOf_61zpoe$: function(name) {
|
||||
return this.object[name];
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {(function():Array.<*>)|null} basesFun
|
||||
* @param {Object=} properties
|
||||
|
||||
Reference in New Issue
Block a user