diff --git a/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/DescriptorSerializer.java b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/DescriptorSerializer.java index 26423e6e752..c83e753c7dc 100644 --- a/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/DescriptorSerializer.java +++ b/compiler/frontend/serialization/src/org/jetbrains/jet/descriptors/serialization/DescriptorSerializer.java @@ -137,8 +137,8 @@ public class DescriptorSerializer { } if (classDescriptor.getKind() == ClassKind.ENUM_CLASS) { - for (ClassDescriptor descriptor : getEnumEntriesScope(classDescriptor).getObjectDescriptors()) { - if (descriptor.getKind() == ClassKind.ENUM_ENTRY) { + for (DeclarationDescriptor descriptor : getEnumEntriesScope(classDescriptor).getAllDescriptors()) { + if (isEnumEntry(descriptor)) { builder.addEnumEntry(nameTable.getSimpleNameIndex(descriptor.getName())); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/WhenChecker.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/WhenChecker.java index 48e16baa82a..359e57b6177 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/WhenChecker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/WhenChecker.java @@ -21,16 +21,14 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.VariableDescriptorForObject; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; -import java.util.Collection; - import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getEnumEntriesScope; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumEntry; public final class WhenChecker { private WhenChecker() { @@ -54,13 +52,12 @@ public final class WhenChecker { if (!(declarationDescriptor instanceof ClassDescriptor)) return false; ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; if (classDescriptor.getKind() != ClassKind.ENUM_CLASS || classDescriptor.getModality().isOverridable()) return false; - Collection objectDescriptors = getEnumEntriesScope(classDescriptor).getObjectDescriptors(); boolean isExhaust = true; boolean notEmpty = false; - for (ClassDescriptor descriptor : objectDescriptors) { - if (descriptor.getKind() == ClassKind.ENUM_ENTRY) { + for (DeclarationDescriptor descriptor : getEnumEntriesScope(classDescriptor).getAllDescriptors()) { + if (isEnumEntry(descriptor)) { notEmpty = true; - if (!containsEnumEntryCase(expression, descriptor, trace)) { + if (!containsEnumEntryCase(expression, (ClassDescriptor) descriptor, trace)) { isExhaust = false; } } @@ -100,12 +97,7 @@ public final class WhenChecker { if (reference == null) return false; DeclarationDescriptor target = trace.get(BindingContext.REFERENCE_TARGET, reference); - if (!(target instanceof VariableDescriptorForObject)) { - return false; - } - - ClassDescriptor classDescriptor = ((VariableDescriptorForObject) target).getObjectClass(); - return classDescriptor == enumEntry; + return target == enumEntry; } @Nullable diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java index 6e313b11ad2..b951750c5f3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationResolver.java @@ -230,17 +230,6 @@ public class DeclarationResolver { context.registerDeclaringScope(setter, scopeForPropertyAccessors); } } - - @Override - public void visitEnumEntry(@NotNull JetEnumEntry enumEntry) { - // FIX: Bad cast - MutableClassDescriptorLite classObjectDescriptor = - ((MutableClassDescriptorLite)namespaceLike.getOwnerForChildren()).getClassObjectDescriptor(); - assert classObjectDescriptor != null; - PropertyDescriptor propertyDescriptor = descriptorResolver.resolveObjectDeclarationAsPropertyDescriptor( - scopeForFunctions, classObjectDescriptor, enumEntry, context.getClasses().get(enumEntry), trace); - classObjectDescriptor.getBuilder().addPropertyDescriptor(propertyDescriptor); - } }); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java index 3dabd556208..8a6044d156d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeHierarchyResolver.java @@ -181,22 +181,26 @@ public class TypeHierarchyResolver { MutableClassDescriptor descriptor = entry.getValue(); if (classOrObject instanceof JetClass) { descriptorResolver.resolveMutableClassDescriptor((JetClass) classOrObject, descriptor, trace); - descriptor.createTypeConstructor(); } else if (classOrObject instanceof JetObjectDeclaration) { - initializeObject((JetObjectDeclaration) classOrObject, descriptor); + descriptor.setModality(Modality.FINAL); + descriptor.setVisibility(resolveVisibilityFromModifiers(classOrObject, getDefaultClassVisibility(descriptor))); + descriptor.setTypeParameterDescriptors(Collections.emptyList()); } - } - } - private static void initializeObject(@NotNull JetObjectDeclaration declaration, @NotNull MutableClassDescriptor descriptor) { - descriptor.setModality(Modality.FINAL); - descriptor.setVisibility(resolveVisibilityFromModifiers(declaration, getDefaultClassVisibility(descriptor))); - descriptor.setTypeParameterDescriptors(Collections.emptyList()); - descriptor.createTypeConstructor(); - MutableClassDescriptorLite classObject = descriptor.getClassObjectDescriptor(); - if (classObject != null) { - classObject.addSupertype(descriptor.getDefaultType()); + descriptor.createTypeConstructor(); + + if (classOrObject instanceof JetEnumEntry || + classOrObject instanceof JetObjectDeclaration && classOrObject.getNameIdentifier() != null) { + MutableClassDescriptorLite classObject = descriptor.getClassObjectDescriptor(); + assert classObject != null : "Enum entries and named objects should have class objects: " + classOrObject.getText(); + + // This is a clever hack: each enum entry and object declaration (i.e. singleton) has a synthetic class object. + // We make this class object inherit from the singleton here, thus allowing to use the singleton's class object where + // the instance of the singleton is applicable. Effectively all members of the singleton would be present in its class + // object as fake overrides, so you can access them via standard class object notation: ObjectName.memberName() + classObject.addSupertype(descriptor.getDefaultType()); + } } } @@ -490,11 +494,10 @@ public class TypeHierarchyResolver { @Override public void visitEnumEntry(@NotNull JetEnumEntry enumEntry) { // TODO: Bad casting - MutableClassDescriptorLite ownerClassDescriptor = (MutableClassDescriptorLite) owner.getOwnerForChildren(); - MutableClassDescriptorLite classObjectDescriptor = ownerClassDescriptor.getClassObjectDescriptor(); - - assert classObjectDescriptor != null : enumEntry.getParent().getText(); - createClassDescriptorForEnumEntry(enumEntry, classObjectDescriptor); + MutableClassDescriptorLite enumClass = (MutableClassDescriptorLite) owner.getOwnerForChildren(); + MutableClassDescriptorLite enumClassObject = enumClass.getClassObjectDescriptor(); + assert enumClassObject != null : enumEntry.getParent().getText(); + createClassDescriptorForEnumEntry(enumEntry, enumClassObject); } @Override @@ -572,11 +575,22 @@ public class TypeHierarchyResolver { @NotNull private MutableClassDescriptor createClassDescriptorForObject( - @NotNull JetObjectDeclaration declaration, + @NotNull JetClassOrObject declaration, @NotNull Name name, @NotNull ClassKind kind ) { - MutableClassDescriptor descriptor = new MutableClassDescriptor(owner.getOwnerForChildren(), outerScope, kind, false, name); + return createClassDescriptorForSingleton(owner.getOwnerForChildren(), outerScope, declaration, name, kind); + } + + @NotNull + private MutableClassDescriptor createClassDescriptorForSingleton( + @NotNull DeclarationDescriptor containingDeclaration, + @NotNull JetScope scope, + @NotNull JetClassOrObject declaration, + @NotNull Name name, + @NotNull ClassKind kind + ) { + MutableClassDescriptor descriptor = new MutableClassDescriptor(containingDeclaration, scope, kind, false, name); prepareForDeferredCall(descriptor.getScopeForMemberResolution(), descriptor, declaration); @@ -585,30 +599,29 @@ public class TypeHierarchyResolver { return descriptor; } + @NotNull private MutableClassDescriptor createClassDescriptorForEnumEntry( @NotNull JetEnumEntry declaration, - @NotNull MutableClassDescriptorLite classObjectDescriptor + @NotNull MutableClassDescriptorLite enumClassObject ) { - NamespaceLikeBuilder owner = classObjectDescriptor.getBuilder(); - MutableClassDescriptor mutableClassObjectDescriptor = (MutableClassDescriptor) classObjectDescriptor; + JetScope scope = ((MutableClassDescriptor) enumClassObject).getScopeForMemberResolution(); - MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor( - owner.getOwnerForChildren(), mutableClassObjectDescriptor.getScopeForMemberResolution(), ClassKind.ENUM_ENTRY, - false, JetPsiUtil.safeName(declaration.getName())); - context.getClasses().put(declaration, mutableClassDescriptor); + MutableClassDescriptor descriptor = + createClassDescriptorForSingleton(enumClassObject, scope, declaration, JetPsiUtil.safeName(declaration.getName()), + ClassKind.ENUM_ENTRY); - prepareForDeferredCall(mutableClassDescriptor.getScopeForMemberResolution(), mutableClassDescriptor, declaration); + context.getClasses().put(declaration, descriptor); + enumClassObject.getBuilder().addClassifierDescriptor(descriptor); - // ??? - is enum entry object? - createPrimaryConstructorForObject(declaration, mutableClassDescriptor); - owner.addObjectDescriptor(mutableClassDescriptor); - trace.record(BindingContext.CLASS, declaration, mutableClassDescriptor); - return mutableClassDescriptor; + descriptor.getBuilder().setClassObjectDescriptor(createSyntheticClassObject(descriptor)); + + return descriptor; } + @NotNull private ConstructorDescriptorImpl createPrimaryConstructorForObject( @Nullable PsiElement object, - MutableClassDescriptor mutableClassDescriptor + @NotNull MutableClassDescriptor mutableClassDescriptor ) { ConstructorDescriptorImpl constructorDescriptor = DescriptorResolver .createAndRecordPrimaryConstructorForObject(object, mutableClassDescriptor, trace); diff --git a/compiler/testData/loadKotlinCustom/enum/enumVisibilitySource.txt b/compiler/testData/loadKotlinCustom/enum/enumVisibilitySource.txt index e141b6994a7..af416fbc911 100644 --- a/compiler/testData/loadKotlinCustom/enum/enumVisibilitySource.txt +++ b/compiler/testData/loadKotlinCustom/enum/enumVisibilitySource.txt @@ -7,14 +7,19 @@ internal final enum class In : jet.Enum { public class object { /*primary*/ private constructor () - public final val A: test.In public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.In public final /*synthesized*/ fun values(): jet.Array - private enum entry A : test.In { + public enum entry A : test.In { /*primary*/ private constructor A() public final override /*1*/ /*fake_override*/ fun name(): jet.String public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.In.A { + /*primary*/ private constructor () + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } } } } @@ -26,14 +31,19 @@ private final enum class Pr : jet.Enum { public class object { /*primary*/ private constructor () - public final val A: test.Pr public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.Pr public final /*synthesized*/ fun values(): jet.Array - private enum entry A : test.Pr { + public enum entry A : test.Pr { /*primary*/ private constructor A() public final override /*1*/ /*fake_override*/ fun name(): jet.String public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.Pr.A { + /*primary*/ private constructor () + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } } } } @@ -45,14 +55,19 @@ public final enum class Pu : jet.Enum { public class object { /*primary*/ private constructor () - public final val A: test.Pu public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.Pu public final /*synthesized*/ fun values(): jet.Array - private enum entry A : test.Pu { + public enum entry A : test.Pu { /*primary*/ private constructor A() public final override /*1*/ /*fake_override*/ fun name(): jet.String public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.Pu.A { + /*primary*/ private constructor () + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } } } } diff --git a/compiler/testData/loadKotlinCustom/enum/innerEnumExistingClassObjectSource.txt b/compiler/testData/loadKotlinCustom/enum/innerEnumExistingClassObjectSource.txt index 09bf5247f4f..456bbe938f8 100644 --- a/compiler/testData/loadKotlinCustom/enum/innerEnumExistingClassObjectSource.txt +++ b/compiler/testData/loadKotlinCustom/enum/innerEnumExistingClassObjectSource.txt @@ -14,14 +14,19 @@ internal final class A { public class object { /*primary*/ private constructor () - public final val ENTRY: test.A.E public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.A.E public final /*synthesized*/ fun values(): jet.Array - private enum entry ENTRY : test.A.E { + public enum entry ENTRY : test.A.E { /*primary*/ private constructor ENTRY() public final override /*1*/ /*fake_override*/ fun name(): jet.String public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.A.E.ENTRY { + /*primary*/ private constructor () + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } } } } diff --git a/compiler/testData/loadKotlinCustom/enum/innerEnumSource.txt b/compiler/testData/loadKotlinCustom/enum/innerEnumSource.txt index cde9a960dd8..d0c3916866f 100644 --- a/compiler/testData/loadKotlinCustom/enum/innerEnumSource.txt +++ b/compiler/testData/loadKotlinCustom/enum/innerEnumSource.txt @@ -10,14 +10,19 @@ internal final class A { public class object { /*primary*/ private constructor () - public final val ENTRY: test.A.E public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.A.E public final /*synthesized*/ fun values(): jet.Array - private enum entry ENTRY : test.A.E { + public enum entry ENTRY : test.A.E { /*primary*/ private constructor ENTRY() public final override /*1*/ /*fake_override*/ fun name(): jet.String public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.A.E.ENTRY { + /*primary*/ private constructor () + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } } } } diff --git a/compiler/testData/loadKotlinCustom/enum/simpleEnumSource.txt b/compiler/testData/loadKotlinCustom/enum/simpleEnumSource.txt index 1171177e9e8..e85d2240e14 100644 --- a/compiler/testData/loadKotlinCustom/enum/simpleEnumSource.txt +++ b/compiler/testData/loadKotlinCustom/enum/simpleEnumSource.txt @@ -7,14 +7,19 @@ internal final enum class MyEnum : jet.Enum { public class object { /*primary*/ private constructor () - public final val ENTRY: test.MyEnum public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.MyEnum public final /*synthesized*/ fun values(): jet.Array - private enum entry ENTRY : test.MyEnum { + public enum entry ENTRY : test.MyEnum { /*primary*/ private constructor ENTRY() public final override /*1*/ /*fake_override*/ fun name(): jet.String public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + + public class object : test.MyEnum.ENTRY { + /*primary*/ private constructor () + public final override /*1*/ /*fake_override*/ fun name(): jet.String + public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int + } } } } diff --git a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/AbstractClassDescriptor.java b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/AbstractClassDescriptor.java index df9e4ee37d3..eb1dd61723b 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/AbstractClassDescriptor.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/impl/AbstractClassDescriptor.java @@ -31,6 +31,8 @@ import org.jetbrains.jet.storage.StorageManager; import java.util.List; import java.util.Map; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClass; + public abstract class AbstractClassDescriptor implements ClassDescriptor { private final Name name; protected final NotNullLazyValue defaultType; @@ -81,6 +83,12 @@ public abstract class AbstractClassDescriptor implements ClassDescriptor { return getDefaultType(); } + if (getKind() == ClassKind.ENUM_ENTRY) { + DeclarationDescriptor enumClass = getContainingDeclaration(); + assert isEnumClass(enumClass) : "Enum entry should be declared in enum class: " + this; + return ((ClassDescriptor) enumClass).getDefaultType(); + } + ClassDescriptor classObject = getClassObjectDescriptor(); return classObject == null ? null : classObject.getDefaultType(); }