private void createTypeConstructors(@NotNull TopDownAnalysisContext c) {
    for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry :
        c.getClasses().entrySet()) {
      JetClassOrObject classOrObject = entry.getKey();
      MutableClassDescriptor descriptor = (MutableClassDescriptor) entry.getValue();
      if (classOrObject instanceof JetClass) {
        descriptorResolver.resolveMutableClassDescriptor(
            (JetClass) classOrObject, descriptor, trace);
      } else if (classOrObject instanceof JetObjectDeclaration) {
        descriptor.setModality(Modality.FINAL);
        descriptor.setVisibility(
            resolveVisibilityFromModifiers(classOrObject, getDefaultClassVisibility(descriptor)));
        descriptor.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList());
      }

      descriptor.createTypeConstructor();

      ClassKind kind = descriptor.getKind();
      if (kind == ClassKind.ENUM_ENTRY
          || kind == ClassKind.OBJECT
          || kind == ClassKind.ENUM_CLASS) {
        MutableClassDescriptorLite classObject = descriptor.getClassObjectDescriptor();
        assert classObject != null
            : "Enum entries and named objects should have class objects: "
                + classOrObject.getText();

        JetType supertype;
        if (kind == ClassKind.ENUM_CLASS) {
          supertype = KotlinBuiltIns.getInstance().getAnyType();
        } else {
          // 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()
          supertype = descriptor.getDefaultType();
        }
        classObject.setSupertypes(Collections.singleton(supertype));
        classObject.createTypeConstructor();
      }
    }
  }
  private void resolveTypesInClassHeaders(@NotNull TopDownAnalysisContext c) {
    for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry :
        c.getClasses().entrySet()) {
      JetClassOrObject classOrObject = entry.getKey();
      if (classOrObject instanceof JetClass) {
        ClassDescriptorWithResolutionScopes descriptor = entry.getValue();
        //noinspection unchecked
        descriptorResolver.resolveGenericBounds(
            (JetClass) classOrObject,
            descriptor,
            descriptor.getScopeForClassHeaderResolution(),
            (List) descriptor.getTypeConstructor().getParameters(),
            trace);
      }
    }

    for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry :
        c.getClasses().entrySet()) {
      descriptorResolver.resolveSupertypesForMutableClassDescriptor(
          entry.getKey(), (MutableClassDescriptor) entry.getValue(), trace);
    }
  }