Resolve enum entries similar to objects in TypeHierarchyResolver

This commit is contained in:
Alexander Udalov
2013-10-30 21:57:24 +04:00
parent c04f63e157
commit dd6cfcdc78
9 changed files with 103 additions and 71 deletions
@@ -137,8 +137,8 @@ public class DescriptorSerializer {
} }
if (classDescriptor.getKind() == ClassKind.ENUM_CLASS) { if (classDescriptor.getKind() == ClassKind.ENUM_CLASS) {
for (ClassDescriptor descriptor : getEnumEntriesScope(classDescriptor).getObjectDescriptors()) { for (DeclarationDescriptor descriptor : getEnumEntriesScope(classDescriptor).getAllDescriptors()) {
if (descriptor.getKind() == ClassKind.ENUM_ENTRY) { if (isEnumEntry(descriptor)) {
builder.addEnumEntry(nameTable.getSimpleNameIndex(descriptor.getName())); builder.addEnumEntry(nameTable.getSimpleNameIndex(descriptor.getName()));
} }
} }
@@ -21,16 +21,14 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassKind; import org.jetbrains.jet.lang.descriptors.ClassKind;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; 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.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 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.getEnumEntriesScope;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumEntry;
public final class WhenChecker { public final class WhenChecker {
private WhenChecker() { private WhenChecker() {
@@ -54,13 +52,12 @@ public final class WhenChecker {
if (!(declarationDescriptor instanceof ClassDescriptor)) return false; if (!(declarationDescriptor instanceof ClassDescriptor)) return false;
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
if (classDescriptor.getKind() != ClassKind.ENUM_CLASS || classDescriptor.getModality().isOverridable()) return false; if (classDescriptor.getKind() != ClassKind.ENUM_CLASS || classDescriptor.getModality().isOverridable()) return false;
Collection<ClassDescriptor> objectDescriptors = getEnumEntriesScope(classDescriptor).getObjectDescriptors();
boolean isExhaust = true; boolean isExhaust = true;
boolean notEmpty = false; boolean notEmpty = false;
for (ClassDescriptor descriptor : objectDescriptors) { for (DeclarationDescriptor descriptor : getEnumEntriesScope(classDescriptor).getAllDescriptors()) {
if (descriptor.getKind() == ClassKind.ENUM_ENTRY) { if (isEnumEntry(descriptor)) {
notEmpty = true; notEmpty = true;
if (!containsEnumEntryCase(expression, descriptor, trace)) { if (!containsEnumEntryCase(expression, (ClassDescriptor) descriptor, trace)) {
isExhaust = false; isExhaust = false;
} }
} }
@@ -100,12 +97,7 @@ public final class WhenChecker {
if (reference == null) return false; if (reference == null) return false;
DeclarationDescriptor target = trace.get(BindingContext.REFERENCE_TARGET, reference); DeclarationDescriptor target = trace.get(BindingContext.REFERENCE_TARGET, reference);
if (!(target instanceof VariableDescriptorForObject)) { return target == enumEntry;
return false;
}
ClassDescriptor classDescriptor = ((VariableDescriptorForObject) target).getObjectClass();
return classDescriptor == enumEntry;
} }
@Nullable @Nullable
@@ -230,17 +230,6 @@ public class DeclarationResolver {
context.registerDeclaringScope(setter, scopeForPropertyAccessors); 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);
}
}); });
} }
} }
@@ -181,22 +181,26 @@ public class TypeHierarchyResolver {
MutableClassDescriptor descriptor = entry.getValue(); MutableClassDescriptor descriptor = entry.getValue();
if (classOrObject instanceof JetClass) { if (classOrObject instanceof JetClass) {
descriptorResolver.resolveMutableClassDescriptor((JetClass) classOrObject, descriptor, trace); descriptorResolver.resolveMutableClassDescriptor((JetClass) classOrObject, descriptor, trace);
descriptor.createTypeConstructor();
} }
else if (classOrObject instanceof JetObjectDeclaration) { else if (classOrObject instanceof JetObjectDeclaration) {
initializeObject((JetObjectDeclaration) classOrObject, descriptor); descriptor.setModality(Modality.FINAL);
descriptor.setVisibility(resolveVisibilityFromModifiers(classOrObject, getDefaultClassVisibility(descriptor)));
descriptor.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList());
} }
}
}
private static void initializeObject(@NotNull JetObjectDeclaration declaration, @NotNull MutableClassDescriptor descriptor) { descriptor.createTypeConstructor();
descriptor.setModality(Modality.FINAL);
descriptor.setVisibility(resolveVisibilityFromModifiers(declaration, getDefaultClassVisibility(descriptor))); if (classOrObject instanceof JetEnumEntry ||
descriptor.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList()); classOrObject instanceof JetObjectDeclaration && classOrObject.getNameIdentifier() != null) {
descriptor.createTypeConstructor(); MutableClassDescriptorLite classObject = descriptor.getClassObjectDescriptor();
MutableClassDescriptorLite classObject = descriptor.getClassObjectDescriptor(); assert classObject != null : "Enum entries and named objects should have class objects: " + classOrObject.getText();
if (classObject != null) {
classObject.addSupertype(descriptor.getDefaultType()); // 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 @Override
public void visitEnumEntry(@NotNull JetEnumEntry enumEntry) { public void visitEnumEntry(@NotNull JetEnumEntry enumEntry) {
// TODO: Bad casting // TODO: Bad casting
MutableClassDescriptorLite ownerClassDescriptor = (MutableClassDescriptorLite) owner.getOwnerForChildren(); MutableClassDescriptorLite enumClass = (MutableClassDescriptorLite) owner.getOwnerForChildren();
MutableClassDescriptorLite classObjectDescriptor = ownerClassDescriptor.getClassObjectDescriptor(); MutableClassDescriptorLite enumClassObject = enumClass.getClassObjectDescriptor();
assert enumClassObject != null : enumEntry.getParent().getText();
assert classObjectDescriptor != null : enumEntry.getParent().getText(); createClassDescriptorForEnumEntry(enumEntry, enumClassObject);
createClassDescriptorForEnumEntry(enumEntry, classObjectDescriptor);
} }
@Override @Override
@@ -572,11 +575,22 @@ public class TypeHierarchyResolver {
@NotNull @NotNull
private MutableClassDescriptor createClassDescriptorForObject( private MutableClassDescriptor createClassDescriptorForObject(
@NotNull JetObjectDeclaration declaration, @NotNull JetClassOrObject declaration,
@NotNull Name name, @NotNull Name name,
@NotNull ClassKind kind @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); prepareForDeferredCall(descriptor.getScopeForMemberResolution(), descriptor, declaration);
@@ -585,30 +599,29 @@ public class TypeHierarchyResolver {
return descriptor; return descriptor;
} }
@NotNull
private MutableClassDescriptor createClassDescriptorForEnumEntry( private MutableClassDescriptor createClassDescriptorForEnumEntry(
@NotNull JetEnumEntry declaration, @NotNull JetEnumEntry declaration,
@NotNull MutableClassDescriptorLite classObjectDescriptor @NotNull MutableClassDescriptorLite enumClassObject
) { ) {
NamespaceLikeBuilder owner = classObjectDescriptor.getBuilder(); JetScope scope = ((MutableClassDescriptor) enumClassObject).getScopeForMemberResolution();
MutableClassDescriptor mutableClassObjectDescriptor = (MutableClassDescriptor) classObjectDescriptor;
MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor( MutableClassDescriptor descriptor =
owner.getOwnerForChildren(), mutableClassObjectDescriptor.getScopeForMemberResolution(), ClassKind.ENUM_ENTRY, createClassDescriptorForSingleton(enumClassObject, scope, declaration, JetPsiUtil.safeName(declaration.getName()),
false, JetPsiUtil.safeName(declaration.getName())); ClassKind.ENUM_ENTRY);
context.getClasses().put(declaration, mutableClassDescriptor);
prepareForDeferredCall(mutableClassDescriptor.getScopeForMemberResolution(), mutableClassDescriptor, declaration); context.getClasses().put(declaration, descriptor);
enumClassObject.getBuilder().addClassifierDescriptor(descriptor);
// ??? - is enum entry object? descriptor.getBuilder().setClassObjectDescriptor(createSyntheticClassObject(descriptor));
createPrimaryConstructorForObject(declaration, mutableClassDescriptor);
owner.addObjectDescriptor(mutableClassDescriptor); return descriptor;
trace.record(BindingContext.CLASS, declaration, mutableClassDescriptor);
return mutableClassDescriptor;
} }
@NotNull
private ConstructorDescriptorImpl createPrimaryConstructorForObject( private ConstructorDescriptorImpl createPrimaryConstructorForObject(
@Nullable PsiElement object, @Nullable PsiElement object,
MutableClassDescriptor mutableClassDescriptor @NotNull MutableClassDescriptor mutableClassDescriptor
) { ) {
ConstructorDescriptorImpl constructorDescriptor = DescriptorResolver ConstructorDescriptorImpl constructorDescriptor = DescriptorResolver
.createAndRecordPrimaryConstructorForObject(object, mutableClassDescriptor, trace); .createAndRecordPrimaryConstructorForObject(object, mutableClassDescriptor, trace);
@@ -7,14 +7,19 @@ internal final enum class In : jet.Enum<test.In> {
public class object <class-object-for-In> { public class object <class-object-for-In> {
/*primary*/ private constructor <class-object-for-In>() /*primary*/ private constructor <class-object-for-In>()
public final val A: test.In
public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.In public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.In
public final /*synthesized*/ fun values(): jet.Array<test.In> public final /*synthesized*/ fun values(): jet.Array<test.In>
private enum entry A : test.In { public enum entry A : test.In {
/*primary*/ private constructor A() /*primary*/ private constructor A()
public final override /*1*/ /*fake_override*/ fun name(): jet.String public final override /*1*/ /*fake_override*/ fun name(): jet.String
public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int
public class object <class-object-for-A> : test.In.A {
/*primary*/ private constructor <class-object-for-A>()
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<test.Pr> {
public class object <class-object-for-Pr> { public class object <class-object-for-Pr> {
/*primary*/ private constructor <class-object-for-Pr>() /*primary*/ private constructor <class-object-for-Pr>()
public final val A: test.Pr
public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.Pr public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.Pr
public final /*synthesized*/ fun values(): jet.Array<test.Pr> public final /*synthesized*/ fun values(): jet.Array<test.Pr>
private enum entry A : test.Pr { public enum entry A : test.Pr {
/*primary*/ private constructor A() /*primary*/ private constructor A()
public final override /*1*/ /*fake_override*/ fun name(): jet.String public final override /*1*/ /*fake_override*/ fun name(): jet.String
public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int
public class object <class-object-for-A> : test.Pr.A {
/*primary*/ private constructor <class-object-for-A>()
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<test.Pu> {
public class object <class-object-for-Pu> { public class object <class-object-for-Pu> {
/*primary*/ private constructor <class-object-for-Pu>() /*primary*/ private constructor <class-object-for-Pu>()
public final val A: test.Pu
public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.Pu public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.Pu
public final /*synthesized*/ fun values(): jet.Array<test.Pu> public final /*synthesized*/ fun values(): jet.Array<test.Pu>
private enum entry A : test.Pu { public enum entry A : test.Pu {
/*primary*/ private constructor A() /*primary*/ private constructor A()
public final override /*1*/ /*fake_override*/ fun name(): jet.String public final override /*1*/ /*fake_override*/ fun name(): jet.String
public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int
public class object <class-object-for-A> : test.Pu.A {
/*primary*/ private constructor <class-object-for-A>()
public final override /*1*/ /*fake_override*/ fun name(): jet.String
public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int
}
} }
} }
} }
@@ -14,14 +14,19 @@ internal final class A {
public class object <class-object-for-E> { public class object <class-object-for-E> {
/*primary*/ private constructor <class-object-for-E>() /*primary*/ private constructor <class-object-for-E>()
public final val ENTRY: test.A.E
public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.A.E public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.A.E
public final /*synthesized*/ fun values(): jet.Array<test.A.E> public final /*synthesized*/ fun values(): jet.Array<test.A.E>
private enum entry ENTRY : test.A.E { public enum entry ENTRY : test.A.E {
/*primary*/ private constructor ENTRY() /*primary*/ private constructor ENTRY()
public final override /*1*/ /*fake_override*/ fun name(): jet.String public final override /*1*/ /*fake_override*/ fun name(): jet.String
public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int
public class object <class-object-for-ENTRY> : test.A.E.ENTRY {
/*primary*/ private constructor <class-object-for-ENTRY>()
public final override /*1*/ /*fake_override*/ fun name(): jet.String
public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int
}
} }
} }
} }
@@ -10,14 +10,19 @@ internal final class A {
public class object <class-object-for-E> { public class object <class-object-for-E> {
/*primary*/ private constructor <class-object-for-E>() /*primary*/ private constructor <class-object-for-E>()
public final val ENTRY: test.A.E
public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.A.E public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.A.E
public final /*synthesized*/ fun values(): jet.Array<test.A.E> public final /*synthesized*/ fun values(): jet.Array<test.A.E>
private enum entry ENTRY : test.A.E { public enum entry ENTRY : test.A.E {
/*primary*/ private constructor ENTRY() /*primary*/ private constructor ENTRY()
public final override /*1*/ /*fake_override*/ fun name(): jet.String public final override /*1*/ /*fake_override*/ fun name(): jet.String
public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int
public class object <class-object-for-ENTRY> : test.A.E.ENTRY {
/*primary*/ private constructor <class-object-for-ENTRY>()
public final override /*1*/ /*fake_override*/ fun name(): jet.String
public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int
}
} }
} }
} }
@@ -7,14 +7,19 @@ internal final enum class MyEnum : jet.Enum<test.MyEnum> {
public class object <class-object-for-MyEnum> { public class object <class-object-for-MyEnum> {
/*primary*/ private constructor <class-object-for-MyEnum>() /*primary*/ private constructor <class-object-for-MyEnum>()
public final val ENTRY: test.MyEnum
public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.MyEnum public final /*synthesized*/ fun valueOf(/*0*/ value: jet.String): test.MyEnum
public final /*synthesized*/ fun values(): jet.Array<test.MyEnum> public final /*synthesized*/ fun values(): jet.Array<test.MyEnum>
private enum entry ENTRY : test.MyEnum { public enum entry ENTRY : test.MyEnum {
/*primary*/ private constructor ENTRY() /*primary*/ private constructor ENTRY()
public final override /*1*/ /*fake_override*/ fun name(): jet.String public final override /*1*/ /*fake_override*/ fun name(): jet.String
public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int
public class object <class-object-for-ENTRY> : test.MyEnum.ENTRY {
/*primary*/ private constructor <class-object-for-ENTRY>()
public final override /*1*/ /*fake_override*/ fun name(): jet.String
public final override /*1*/ /*fake_override*/ fun ordinal(): jet.Int
}
} }
} }
} }
@@ -31,6 +31,8 @@ import org.jetbrains.jet.storage.StorageManager;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClass;
public abstract class AbstractClassDescriptor implements ClassDescriptor { public abstract class AbstractClassDescriptor implements ClassDescriptor {
private final Name name; private final Name name;
protected final NotNullLazyValue<JetType> defaultType; protected final NotNullLazyValue<JetType> defaultType;
@@ -81,6 +83,12 @@ public abstract class AbstractClassDescriptor implements ClassDescriptor {
return getDefaultType(); 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(); ClassDescriptor classObject = getClassObjectDescriptor();
return classObject == null ? null : classObject.getDefaultType(); return classObject == null ? null : classObject.getDefaultType();
} }