private static Map<String, PsiType> getCompatibleTypeNames(
      @NotNull PsiType type, @Nullable PsiType min, PsiManager manager, GlobalSearchScope scope) {
    if (type instanceof PsiDisjunctionType) type = ((PsiDisjunctionType) type).getLeastUpperBound();

    // if initial type is not assignable to min type we don't take into consideration min type.
    if (min != null && !TypesUtil.isAssignable(min, type, manager, scope)) {
      min = null;
    }

    Map<String, PsiType> map = new LinkedHashMap<String, PsiType>();
    final PsiPrimitiveType unboxed = PsiPrimitiveType.getUnboxedType(type);
    if (unboxed != null) type = unboxed;
    final Set<PsiType> set = new LinkedHashSet<PsiType>();
    set.add(type);
    while (!set.isEmpty()) {
      PsiType cur = set.iterator().next();
      set.remove(cur);
      if (!map.containsValue(cur)
          && (min == null || TypesUtil.isAssignable(min, cur, manager, scope))) {
        if (isPartiallySubstituted(cur)) {
          LOG.assertTrue(cur instanceof PsiClassType);
          PsiClassType rawType = ((PsiClassType) cur).rawType();
          map.put(rawType.getPresentableText(), rawType);
        } else {
          map.put(cur.getPresentableText(), cur);
        }
        for (PsiType superType : cur.getSuperTypes()) {
          if (!map.containsValue(superType)) {
            set.add(superType);
          }
        }
      }
    }
    return map;
  }