public static @NotNull <T extends PsiType> T originalize(@NotNull T type) {
    if (!type.isValid()) {
      return type;
    }

    T result = new PsiTypeMapper() {
      private final Set<PsiClassType> myVisited = new ReferenceOpenHashSet<>();

      @Override
      public PsiType visitClassType(@NotNull PsiClassType classType) {
        if (!myVisited.add(classType)) return classType;

        PsiClassType.ClassResolveResult classResolveResult = classType.resolveGenerics();
        PsiClass psiClass = classResolveResult.getElement();
        PsiSubstitutor substitutor = classResolveResult.getSubstitutor();
        if (psiClass == null) return classType;

        return new PsiImmediateClassType(CompletionUtil.getOriginalOrSelf(psiClass), originalizeSubstitutor(substitutor));
      }

      private @NotNull PsiSubstitutor originalizeSubstitutor(@NotNull PsiSubstitutor substitutor) {
        PsiSubstitutor originalSubstitutor = PsiSubstitutor.EMPTY;
        for (Map.Entry<PsiTypeParameter, PsiType> entry : substitutor.getSubstitutionMap().entrySet()) {
          PsiType value = entry.getValue();
          originalSubstitutor = originalSubstitutor.put(CompletionUtil.getOriginalOrSelf(entry.getKey()),
                                                        value == null ? null : mapType(value));
        }
        return originalSubstitutor;
      }

      @Override
      public PsiType visitType(@NotNull PsiType type) {
        return type;
      }
    }.mapType(type);
    if (result == null) {
      throw new AssertionError("Null result for type " + type + " of class " + type.getClass());
    }
    return result;
  }
public static @NotNull <T extends PsiType> T originalize(@NotNull T type)