Permalink
Browse files

proper compilation of enums

  • Loading branch information...
1 parent e582072 commit 594775968408f2f47735a74f200d57da222c72aa @alextkachman alextkachman committed Aug 13, 2012
Showing with 839 additions and 134 deletions.
  1. +6 −0 compiler/backend/src/org/jetbrains/jet/codegen/ConstructorFrameMap.java
  2. +6 −6 compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java
  3. +98 −10 compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java
  4. +15 −1 compiler/backend/src/org/jetbrains/jet/codegen/JetTypeMapper.java
  5. +48 −0 compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/EnumName.java
  6. +48 −0 compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/EnumOrdinal.java
  7. +51 −0 compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/EnumValueOf.java
  8. +49 −0 compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/EnumValues.java
  9. +29 −0 compiler/backend/src/org/jetbrains/jet/codegen/intrinsics/IntrinsicMethods.java
  10. +2 −0 compiler/backend/src/org/jetbrains/jet/codegen/signature/JvmMethodParameterKind.java
  11. +1 −1 compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java
  12. +1 −0 compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaTypeTransformer.java
  13. +3 −0 compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JdkNames.java
  14. +6 −0 compiler/frontend/src/jet/Enum.jet
  15. +258 −74 compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorResolver.java
  16. +50 −29 compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java
  17. +1 −1 compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/AbstractLazyMemberScope.java
  18. +23 −0 compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/LazyClassMemberScope.java
  19. +28 −1 compiler/frontend/src/org/jetbrains/jet/lang/types/lang/JetStandardLibrary.java
  20. +4 −1 compiler/frontend/src/org/jetbrains/jet/lang/types/lang/JetStandardLibraryNames.java
  21. +5 −0 compiler/testData/builtin-classes.txt
  22. +6 −0 compiler/testData/codegen/enum/name.kt
  23. +8 −0 compiler/testData/codegen/enum/ordinal.kt
  24. +6 −0 compiler/testData/codegen/enum/toString.kt
  25. +11 −0 compiler/testData/codegen/enum/valueof.kt
  26. +4 −2 compiler/testData/diagnostics/tests/DelegationNotTotrait.kt
  27. +11 −1 compiler/testData/lazyResolve/namespaceComparator/enum.txt
  28. +1 −1 compiler/testData/readJavaBinaryClass/ClassWithTypePRefSelf.kt
  29. +2 −2 compiler/testData/readJavaBinaryClass/ClassWithTypePRefSelf.txt
  30. +1 −1 compiler/testData/renderer/Enum.kt
  31. +2 −1 compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java
  32. +54 −1 compiler/tests/org/jetbrains/jet/codegen/EnumGenTest.java
  33. +1 −1 idea/testData/libraries/decompiled/Color.kt
@@ -17,6 +17,7 @@
package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.lang.descriptors.ClassKind;
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.asm4.Type;
@@ -42,6 +43,11 @@ public ConstructorFrameMap(CallableMethod callableMethod, @Nullable ConstructorD
List<Type> explicitArgTypes = callableMethod.getValueParameterTypes();
+ if(descriptor != null && descriptor.getContainingDeclaration().getKind() == ClassKind.ENUM_CLASS) {
+ enterTemp(); // name
+ enterTemp(); // ordinal
+ }
+
List<ValueParameterDescriptor> paramDescrs = descriptor != null
? descriptor.getValueParameters()
: Collections.<ValueParameterDescriptor>emptyList();
@@ -1035,7 +1035,11 @@ public StackValue visitSimpleNameExpression(JetSimpleNameExpression expression,
IntrinsicMethod intrinsic = null;
if (descriptor instanceof CallableMemberDescriptor) {
- intrinsic = state.getInjector().getIntrinsics().getIntrinsic((CallableMemberDescriptor) descriptor);
+ CallableMemberDescriptor memberDescriptor = (CallableMemberDescriptor) descriptor;
+ while(memberDescriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
+ memberDescriptor = memberDescriptor.getOverriddenDescriptors().iterator().next();
+ }
+ intrinsic = state.getInjector().getIntrinsics().getIntrinsic(memberDescriptor);
}
if (intrinsic != null) {
final Type expectedType = expressionType(expression);
@@ -1111,11 +1115,7 @@ public StackValue visitSimpleNameExpression(JetSimpleNameExpression expression,
if (descriptor instanceof ClassDescriptor) {
PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor);
if (declaration instanceof JetClass) {
- final JetClassObject classObject = ((JetClass) declaration).getClassObject();
- if (classObject == null) {
- throw new UnsupportedOperationException("trying to reference a class which doesn't have a class object");
- }
- final ClassDescriptor descriptor1 = bindingContext.get(BindingContext.CLASS, classObject.getObjectDeclaration());
+ final ClassDescriptor descriptor1 = ((ClassDescriptor)descriptor).getClassObjectDescriptor();
assert descriptor1 != null;
final Type type = typeMapper.mapType(descriptor1.getDefaultType(), MapTypeMode.VALUE);
return StackValue.field(type,
@@ -35,6 +35,7 @@
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
import org.jetbrains.jet.lang.types.JetType;
+import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.utils.BitSetUtils;
import org.jetbrains.asm4.AnnotationVisitor;
@@ -54,6 +55,7 @@
* @author alex.tkachman
*/
public class ImplementationBodyCodegen extends ClassBodyCodegen {
+ public static final String VALUES = "$VALUES";
private JetDelegationSpecifier superCall;
private String superClass;
@Nullable // null means java/lang/Object
@@ -78,6 +80,7 @@ protected void generateDeclaration() {
boolean isFinal = false;
boolean isStatic = false;
boolean isAnnotation = false;
+ boolean isEnum = false;
if (myClass instanceof JetClass) {
JetClass jetClass = (JetClass) myClass;
@@ -87,12 +90,16 @@ protected void generateDeclaration() {
isAbstract = true;
isInterface = true;
}
- if (jetClass.isAnnotation()) {
+ else if (jetClass.isAnnotation()) {
isAbstract = true;
isInterface = true;
isAnnotation = true;
signature.getInterfaces().add(JdkNames.JLA_ANNOTATION.getInternalName());
}
+ else if (jetClass.hasModifier(JetTokens.ENUM_KEYWORD)) {
+ isEnum = true;
+ }
+
if (!jetClass.hasModifier(JetTokens.OPEN_KEYWORD) && !isAbstract) {
isFinal = true;
}
@@ -121,6 +128,9 @@ else if (myClass.getParent() instanceof JetClassObject) {
if (isAnnotation) {
access |= ACC_ANNOTATION;
}
+ if (isEnum) {
+ access |= ACC_ENUM;
+ }
v.defineClass(myClass, V1_6,
access,
signature.getName(),
@@ -270,6 +280,13 @@ protected void getSuperClass() {
}
}
}
+
+ if(superClassType == null) {
+ if (myClass instanceof JetClass && ((JetClass) myClass).hasModifier(JetTokens.ENUM_KEYWORD)) {
+ superClassType = JetStandardLibrary.getInstance().getEnumType(descriptor.getDefaultType());
+ superClass = typeMapper.mapType(superClassType,MapTypeMode.VALUE).getInternalName();
+ }
+ }
}
@Override
@@ -293,6 +310,38 @@ protected void generateSyntheticParts() {
generateTraitMethods();
generateAccessors();
+
+ generateEnumMethods();
+ }
+
+ private void generateEnumMethods() {
+ if(myEnumConstants.size() > 0) {
+ {
+ Type type = typeMapper.mapType(JetStandardLibrary.getInstance().getArrayType(descriptor.getDefaultType()), MapTypeMode.IMPL);
+
+ MethodVisitor mv =
+ v.newMethod(myClass, ACC_PUBLIC | ACC_STATIC, "values", "()" + type.getDescriptor(), null, null);
+ mv.visitCode();
+ mv.visitFieldInsn(GETSTATIC, typeMapper.mapType(descriptor.getDefaultType(),MapTypeMode.VALUE).getInternalName(), VALUES, type.getDescriptor());
+ mv.visitMethodInsn(INVOKEVIRTUAL, type.getInternalName(), "clone", "()Ljava/lang/Object;");
+ mv.visitTypeInsn(CHECKCAST, type.getInternalName());
+ mv.visitInsn(ARETURN);
+ FunctionCodegen.endVisit(mv,"values()",myClass);
+ }
+ {
+ Type type = typeMapper.mapType(descriptor.getDefaultType(), MapTypeMode.IMPL);
+
+ MethodVisitor mv =
+ v.newMethod(myClass, ACC_PUBLIC | ACC_STATIC, "valueOf", "(Ljava/lang/String;)" + type.getDescriptor(), null, null);
+ mv.visitCode();
+ mv.visitLdcInsn(type);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Enum", "valueOf", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;");
+ mv.visitTypeInsn(CHECKCAST, type.getInternalName());
+ mv.visitInsn(ARETURN);
+ FunctionCodegen.endVisit(mv,"values()",myClass);
+ }
+ }
}
private void generateAccessors() {
@@ -593,6 +642,10 @@ else if (descriptor instanceof FunctionDescriptor) {
i++;
}
+ if(myClass instanceof JetClass && ((JetClass)myClass).hasModifier(JetTokens.ENUM_KEYWORD)) {
+ i += 2;
+ }
+
for (ValueParameterDescriptor valueParameter : constructorDescriptor.getValueParameters()) {
AnnotationCodegen.forParameter(i, mv, state.getInjector().getJetTypeMapper()).genAnnotations(valueParameter);
JetValueParameterAnnotationWriter jetValueParameterAnnotation = JetValueParameterAnnotationWriter.visitParameterAnnotation(mv, i);
@@ -641,7 +694,14 @@ else if (descriptor instanceof FunctionDescriptor) {
if (superCall == null) {
iv.load(0, Type.getType("L" + superClass + ";"));
- iv.invokespecial(superClass, "<init>", "()V");
+ if(descriptor.getKind() == ClassKind.ENUM_CLASS) {
+ iv.load(1, JetTypeMapper.JL_STRING_TYPE);
+ iv.load(2, Type.INT_TYPE);
+ iv.invokespecial(superClass, "<init>", "(Ljava/lang/String;I)V");
+ }
+ else {
+ iv.invokespecial(superClass, "<init>", "()V");
+ }
}
else if (superCall instanceof JetDelegatorToSuperClass) {
iv.load(0, Type.getType("L" + superClass + ";"));
@@ -865,6 +925,10 @@ private void generateDelegatorToConstructorCall(InstructionAdapter iv, Expressio
ClassDescriptor classDecl = constructorDescriptor.getContainingDeclaration();
iv.load(0, TYPE_OBJECT);
+ if(classDecl.getKind() == ClassKind.ENUM_CLASS) {
+ iv.load(1, JetTypeMapper.TYPE_OBJECT);
+ iv.load(2, Type.INT_TYPE);
+ }
if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) {
iv.load(frameMap.getOuterThisIndex(), typeMapper.mapType(((ClassDescriptor) descriptor.getContainingDeclaration()).getDefaultType(), MapTypeMode.IMPL));
@@ -895,7 +959,7 @@ protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclarati
else if (declaration instanceof JetEnumEntry && !((JetEnumEntry) declaration).hasPrimaryConstructor()) {
String name = declaration.getName();
final String desc = "L" + typeMapper.mapType(descriptor.getDefaultType(), MapTypeMode.IMPL).getInternalName() + ";";
- v.newField(declaration, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, name, desc, null, null);
+ v.newField(declaration, ACC_PUBLIC | ACC_ENUM | ACC_STATIC | ACC_FINAL, name, desc, null, null);
if (myEnumConstants.isEmpty()) {
staticInitializerChunks.add(new CodeChunk() {
@Override
@@ -913,19 +977,40 @@ public void generate(InstructionAdapter v) {
private final List<JetEnumEntry> myEnumConstants = new ArrayList<JetEnumEntry>();
- private void initializeEnumConstants(InstructionAdapter v) {
- ExpressionCodegen codegen = new ExpressionCodegen(v, new FrameMap(), Type.VOID_TYPE, context, state);
+ private void initializeEnumConstants(InstructionAdapter iv) {
+ ExpressionCodegen codegen = new ExpressionCodegen(iv, new FrameMap(), Type.VOID_TYPE, context, state);
+ int ordinal = -1;
+ JetType myType = descriptor.getDefaultType();
+ Type myAsmType = typeMapper.mapType(myType, MapTypeMode.IMPL);
+
+ assert myEnumConstants.size() > 0;
+ JetType arrayType = JetStandardLibrary.getInstance().getArrayType(myType);
+ Type arrayAsmType = typeMapper.mapType(arrayType, MapTypeMode.IMPL);
+ v.newField(myClass, ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, "$VALUES", arrayAsmType.getDescriptor(), null, null);
+
+ iv.iconst(myEnumConstants.size());
+ iv.newarray(myAsmType);
+ iv.dup();
+
for (JetEnumEntry enumConstant : myEnumConstants) {
+ ordinal++;
+
+ iv.dup();
+ iv.iconst(ordinal);
+
// TODO type and constructor parameters
- String implClass = typeMapper.mapType(descriptor.getDefaultType(), MapTypeMode.IMPL).getInternalName();
+ String implClass = typeMapper.mapType(myType, MapTypeMode.IMPL).getInternalName();
final List<JetDelegationSpecifier> delegationSpecifiers = enumConstant.getDelegationSpecifiers();
if (delegationSpecifiers.size() > 1) {
throw new UnsupportedOperationException("multiple delegation specifiers for enum constant not supported");
}
- v.anew(Type.getObjectType(implClass));
- v.dup();
+ iv.anew(Type.getObjectType(implClass));
+ iv.dup();
+
+ iv.aconst(enumConstant.getName());
+ iv.iconst(ordinal);
if (delegationSpecifiers.size() == 1) {
final JetDelegationSpecifier specifier = delegationSpecifiers.get(0);
@@ -940,10 +1025,13 @@ private void initializeEnumConstants(InstructionAdapter v) {
}
}
else {
- v.invokespecial(implClass, "<init>", "()V");
+ iv.invokespecial(implClass, "<init>", "(Ljava/lang/String;I)V");
}
- v.putstatic(implClass, enumConstant.getName(), "L" + implClass + ";");
+ iv.dup();
+ iv.putstatic(implClass, enumConstant.getName(), "L" + implClass + ";");
+ iv.astore(TYPE_OBJECT);
}
+ iv.putstatic(myAsmType.getClassName(), "$VALUES", arrayAsmType.getDescriptor());
}
public static void generateInitializers(@NotNull ExpressionCodegen codegen, @NotNull InstructionAdapter iv, @NotNull List<JetDeclaration> declarations,
@@ -38,6 +38,7 @@
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
+import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import org.jetbrains.jet.lang.types.lang.JetStandardLibraryNames;
import org.jetbrains.jet.lang.types.lang.PrimitiveType;
import org.jetbrains.jet.lang.types.ref.ClassName;
@@ -61,6 +62,7 @@
public static final Type JL_NUMBER_TYPE = Type.getObjectType("java/lang/Number");
public static final Type JL_STRING_BUILDER = Type.getObjectType("java/lang/StringBuilder");
public static final Type JL_STRING_TYPE = Type.getObjectType("java/lang/String");
+ public static final Type JL_ENUM_TYPE = Type.getObjectType("java/lang/Enum");
public static final Type JL_CHAR_SEQUENCE_TYPE = Type.getObjectType("java/lang/CharSequence");
private static final Type JL_COMPARABLE_TYPE = Type.getObjectType("java/lang/Comparable");
public static final Type JL_CLASS_TYPE = Type.getObjectType("java/lang/Class");
@@ -141,6 +143,7 @@ public void init() {
register(JetStandardLibraryNames.CHAR_SEQUENCE, JL_CHAR_SEQUENCE_TYPE, JL_CHAR_SEQUENCE_TYPE);
register(JetStandardLibraryNames.THROWABLE, TYPE_THROWABLE, TYPE_THROWABLE);
register(JetStandardLibraryNames.COMPARABLE, JL_COMPARABLE_TYPE, JL_COMPARABLE_TYPE);
+ register(JetStandardLibraryNames.ENUM, JL_ENUM_TYPE, JL_ENUM_TYPE);
for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
PrimitiveType primitiveType = jvmPrimitiveType.getPrimitiveType();
@@ -941,9 +944,19 @@ private JvmMethodSignature mapConstructorSignature(ConstructorDescriptor descrip
signatureWriter.writeParametersStart();
+ ClassDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (hasThis0) {
signatureWriter.writeParameterType(JvmMethodParameterKind.THIS0);
- mapType(closureAnnotator.getEclosingClassDescriptor(descriptor.getContainingDeclaration()).getDefaultType(), signatureWriter, MapTypeMode.VALUE);
+ mapType(closureAnnotator.getEclosingClassDescriptor(containingDeclaration).getDefaultType(), signatureWriter, MapTypeMode.VALUE);
+ signatureWriter.writeParameterTypeEnd();
+ }
+
+ if(containingDeclaration.getKind() == ClassKind.ENUM_CLASS) {
+ signatureWriter.writeParameterType(JvmMethodParameterKind.ENUM_NAME);
+ mapType(JetStandardLibrary.getInstance().getStringType(), signatureWriter, MapTypeMode.VALUE);
+ signatureWriter.writeParameterTypeEnd();
+ signatureWriter.writeParameterType(JvmMethodParameterKind.ENUM_ORDINAL);
+ mapType(JetStandardLibrary.getInstance().getIntType(), signatureWriter, MapTypeMode.VALUE);
signatureWriter.writeParameterTypeEnd();
}
@@ -1046,6 +1059,7 @@ private static boolean isForceReal(JvmClassName className) {
|| className.getFqName().getFqName().equals("java.lang.CharSequence")
|| className.getFqName().getFqName().equals("java.lang.Object")
|| className.getFqName().getFqName().equals("java.lang.Number")
+ || className.getFqName().getFqName().equals("java.lang.Enum")
|| className.getFqName().getFqName().equals("java.lang.Comparable");
}
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.jet.codegen.intrinsics;
+
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.asm4.Type;
+import org.jetbrains.asm4.commons.InstructionAdapter;
+import org.jetbrains.jet.codegen.ExpressionCodegen;
+import org.jetbrains.jet.codegen.GenerationState;
+import org.jetbrains.jet.codegen.JetTypeMapper;
+import org.jetbrains.jet.codegen.StackValue;
+import org.jetbrains.jet.lang.psi.JetExpression;
+
+import java.util.List;
+
+public class EnumName implements IntrinsicMethod {
+ @Override
+ public StackValue generate(
+ ExpressionCodegen codegen,
+ InstructionAdapter v,
+ @NotNull Type expectedType,
+ @Nullable PsiElement element,
+ @Nullable List<JetExpression> arguments,
+ StackValue receiver,
+ @NotNull GenerationState state
+ ) {
+ receiver.put(JetTypeMapper.TYPE_OBJECT, v);
+ v.invokevirtual("java/lang/Enum", "name", "()Ljava/lang/String;");
+ StackValue.onStack(JetTypeMapper.JL_STRING_TYPE).put(expectedType, v);
+ return StackValue.onStack(expectedType);
+ }
+}
Oops, something went wrong.

0 comments on commit 5947759

Please sign in to comment.