@Contract("null, _ -> null")
  public static PsiType erasure(@Nullable PsiType type, @NotNull PsiSubstitutor beforeSubstitutor) {
    if (type == null) return null;
    return type.accept(new PsiTypeVisitor<PsiType>() {
      @NotNull
      @Override
      public PsiType visitType(@NotNull PsiType type) {
        return type;
      }

      @Override
      public PsiType visitClassType(@NotNull PsiClassType classType) {
        final PsiClass aClass = classType.resolve();
        if (aClass instanceof PsiTypeParameter && !isFreshVariable((PsiTypeParameter)aClass)) {
          return typeParameterErasure((PsiTypeParameter)aClass, beforeSubstitutor);
        }
        return classType.rawType();
      }

      @Override
      public PsiType visitWildcardType(@NotNull PsiWildcardType wildcardType) {
        return wildcardType;
      }

      @Nullable
      @Override
      public PsiType visitCapturedWildcardType(@NotNull PsiCapturedWildcardType capturedWildcardType) {
        return capturedWildcardType.getUpperBound().accept(this);
      }

      @Override
      public PsiType visitPrimitiveType(@NotNull PsiPrimitiveType primitiveType) {
        return primitiveType;
      }

      @Override
      public PsiType visitArrayType(@NotNull PsiArrayType arrayType) {
        final PsiType componentType = arrayType.getComponentType();
        final PsiType newComponentType = componentType.accept(this);
        if (newComponentType == componentType) return arrayType;
        return newComponentType != null ? newComponentType.createArrayType() : null;
      }

      @Override
      public PsiType visitDisjunctionType(@NotNull PsiDisjunctionType disjunctionType) {
        final PsiClassType lub = PsiTypesUtil.getLowestUpperBoundClassType(disjunctionType);
        return lub != null ? erasure(lub, beforeSubstitutor) : disjunctionType;
      }
    });
  }
@Contract("null, _ -> null")
  public static PsiType erasure(@Nullable PsiType type, @NotNull PsiSubstitutor beforeSubstitutor)