@NotNull
  private JetType modifyTypeAccordingToSuperMethods(
      @NotNull JetType autoType,
      @NotNull List<TypeAndVariance> typesFromSuper,
      @NotNull TypeUsage howThisTypeIsUsed) {
    if (ErrorUtils.isErrorType(autoType)) {
      return autoType;
    }

    boolean resultNullable = typeMustBeNullable(autoType, typesFromSuper, howThisTypeIsUsed);
    ClassifierDescriptor resultClassifier = modifyTypeClassifier(autoType, typesFromSuper);
    List<TypeProjection> resultArguments =
        getTypeArgsOfType(autoType, resultClassifier, typesFromSuper);
    JetScope resultScope;
    if (resultClassifier instanceof ClassDescriptor) {
      resultScope = ((ClassDescriptor) resultClassifier).getMemberScope(resultArguments);
    } else {
      resultScope = autoType.getMemberScope();
    }

    JetTypeImpl type =
        new JetTypeImpl(
            autoType.getAnnotations(),
            resultClassifier.getTypeConstructor(),
            resultNullable,
            resultArguments,
            resultScope);

    PropagationHeuristics.checkArrayInReturnType(this, type, typesFromSuper);
    return type;
  }
  @NotNull
  private ClassifierDescriptor modifyTypeClassifier(
      @NotNull JetType autoType, @NotNull List<TypeAndVariance> typesFromSuper) {
    ClassifierDescriptor classifier = autoType.getConstructor().getDeclarationDescriptor();
    if (!(classifier instanceof ClassDescriptor)) {
      assert classifier != null : "no declaration descriptor for type " + autoType;

      if (classifier instanceof TypeParameterDescriptor
          && autoTypeParameterToModified.containsKey(classifier)) {
        return autoTypeParameterToModified.get(classifier);
      }
      return classifier;
    }
    ClassDescriptor klass = (ClassDescriptor) classifier;

    CollectionClassMapping collectionMapping = CollectionClassMapping.getInstance();

    boolean someSupersMutable = false;
    boolean someSupersCovariantReadOnly = false;
    boolean someSupersNotCovariantReadOnly = false;
    for (TypeAndVariance typeFromSuper : typesFromSuper) {
      ClassifierDescriptor classifierFromSuper =
          typeFromSuper.type.getConstructor().getDeclarationDescriptor();
      if (classifierFromSuper instanceof ClassDescriptor) {
        ClassDescriptor classFromSuper = (ClassDescriptor) classifierFromSuper;

        if (collectionMapping.isMutableCollection(classFromSuper)) {
          someSupersMutable = true;
        } else if (collectionMapping.isReadOnlyCollection(classFromSuper)) {
          if (typeFromSuper.varianceOfPosition == Variance.OUT_VARIANCE) {
            someSupersCovariantReadOnly = true;
          } else {
            someSupersNotCovariantReadOnly = true;
          }
        }
      }
    }

    if (someSupersMutable && someSupersNotCovariantReadOnly) {
      reportError("Incompatible types in superclasses: " + typesFromSuper);
      return classifier;
    } else if (someSupersMutable) {
      if (collectionMapping.isReadOnlyCollection(klass)) {
        return collectionMapping.convertReadOnlyToMutable(klass);
      }
    } else if (someSupersNotCovariantReadOnly || someSupersCovariantReadOnly) {
      if (collectionMapping.isMutableCollection(klass)) {
        return collectionMapping.convertMutableToReadOnly(klass);
      }
    }

    ClassifierDescriptor fixed =
        PropagationHeuristics.tryToFixOverridingTWithRawType(this, typesFromSuper);
    return fixed != null ? fixed : classifier;
  }