@NotNull
  public static ParseResult parse(@NotNull PsiElement anchor, @NotNull String type, @NotNull TypeEvalContext context) {
    PyPsiUtils.assertValid(anchor);

    final ForwardDeclaration<ParseResult, PyElementType> typeExpr = ForwardDeclaration.create();

    final FunctionalParser<ParseResult, PyElementType> classType =
      token(IDENTIFIER).then(many(op(".").skipThen(token(IDENTIFIER))))
        .map(new MakeSimpleType(anchor, context))
        .cached()
        .named("class-type");

    final FunctionalParser<ParseResult, PyElementType> tupleType =
      op("(").skipThen(typeExpr).then(many(op(",").skipThen(typeExpr))).thenSkip(op(")"))
        .map(value -> {
          ParseResult result = value.getFirst();
          final List<ParseResult> rest = value.getSecond();
          if (rest.isEmpty()) {
            return result;
          }
          final List<PyType> types = new ArrayList<>();
          types.add(result.getType());
          for (ParseResult r : rest) {
            result = result.merge(r);
            types.add(r.getType());
          }
          return result.withType(PyTupleType.create(anchor, types));
        })
        .named("tuple-type");

    final FunctionalParser<ParseResult, PyElementType> typeParameter =
      token(PARAMETER).then(maybe(op("<=").skipThen(typeExpr)))
        .map(value -> {
          final Token<PyElementType> token = value.getFirst();
          final String name = token.getText().toString();
          final TextRange range = token.getRange();
          final ParseResult boundResult = value.getSecond();
          if (boundResult != null) {
            final PyTypeVarType type1 = new PyTypeVarTypeImpl(name, boundResult.getType());
            final ParseResult result = new ParseResult(type1, range);
            return result.merge(boundResult).withType(type1);
          }
          return new ParseResult(new PyTypeVarTypeImpl(name, null), range);
        })
        .named("type-parameter");

    final FunctionalParser<ParseResult, PyElementType> simpleExpr =
      classType
        .or(tupleType)
        .or(typeParameter)
        .named("simple-expr");

    final FunctionalParser<ParseResult, PyElementType> paramExpr =
      classType.thenSkip(op("[")).then(typeExpr).then(many(op(",").skipThen(typeExpr))).thenSkip(op("]"))
        .map(value -> {
          final Pair<ParseResult, ParseResult> firstPair = value.getFirst();
          final ParseResult first = firstPair.getFirst();
          final ParseResult second = firstPair.getSecond();
          final List<ParseResult> third = value.getSecond();
          final PyType firstType = first.getType();
          final List<PyType> typesInBrackets = new ArrayList<>();
          typesInBrackets.add(second.getType());
          ParseResult result = first;
          result = result.merge(second);
          for (ParseResult r : third) {
            typesInBrackets.add(r.getType());
            result = result.merge(r);
          }
          final List<PyType> elementTypes = third.isEmpty() ? Collections.singletonList(second.getType()) : typesInBrackets;
          if (firstType instanceof PyClassType) {
            final PyType type1 = new PyCollectionTypeImpl(((PyClassType)firstType).getPyClass(), false, elementTypes);
            return result.withType(type1);
          }
          return EMPTY_RESULT;
        })
        .or(classType.thenSkip(op("of")).then(simpleExpr)
              .map(value -> {
                final ParseResult firstResult = value.getFirst();
                final ParseResult secondResult = value.getSecond();
                final ParseResult result = firstResult.merge(secondResult);
                final PyType firstType = firstResult.getType();
                final PyType secondType = secondResult.getType();
                if (firstType != null) {
                  if (firstType instanceof PyClassType && secondType != null) {
                    return result.withType(new PyCollectionTypeImpl(((PyClassType)firstType).getPyClass(), false,
                                                                    Collections.singletonList(secondType)));
                  }
                  return result.withType(firstType);
                }
                return EMPTY_RESULT;
              }))
        .or(classType.thenSkip(op("from")).then(simpleExpr).thenSkip(op("to")).then(simpleExpr)
              .map(value -> {
                final Pair<ParseResult, ParseResult> firstPair = value.getFirst();
                final ParseResult first = firstPair.getFirst();
                final ParseResult second = firstPair.getSecond();
                final ParseResult third = value.getSecond();
                final PyType firstType = first.getType();
                if (firstType instanceof PyClassType) {
                  final List<PyType> elementTypes = Arrays.asList(second.getType(), third.getType());
                  final PyCollectionTypeImpl type1 = new PyCollectionTypeImpl(((PyClassType)firstType).getPyClass(), false,
                                                                              elementTypes);
                  return first.merge(second).merge(third).withType(type1);
                }
                return EMPTY_RESULT;
              }))
        .named("param-expr");

    final FunctionalParser<ParseResult, PyElementType> callableExpr =
      op("(").skipThen(maybe(typeExpr.then(many(op(",").skipThen(typeExpr))))).thenSkip(op(")")).thenSkip(op("->")).then(typeExpr)
        .map(
          value -> {
            final List<PyCallableParameter> parameters = new ArrayList<>();
            final ParseResult returnResult = value.getSecond();
            ParseResult result;
            final Pair<ParseResult, List<ParseResult>> firstPair = value.getFirst();
            if (firstPair != null) {
              final ParseResult first = firstPair.getFirst();
              final List<ParseResult> second = firstPair.getSecond();
              result = first;
              parameters.add(PyCallableParameterImpl.nonPsi(first.getType()));
              for (ParseResult r : second) {
                result = result.merge(r);
                parameters.add(PyCallableParameterImpl.nonPsi(r.getType()));
              }
              result = result.merge(returnResult);
            }
            else {
              result = returnResult;
            }
            return result.withType(new PyCallableTypeImpl(parameters, returnResult.getType()));
          })
        .named("callable-expr");

    final FunctionalParser<ParseResult, PyElementType> singleExpr =
      paramExpr
        .or(callableExpr)
        .or(simpleExpr)
        .named("single-expr");

    final FunctionalParser<ParseResult, PyElementType> unionExpr =
      singleExpr.then(many(op("or").or(op("|")).skipThen(singleExpr)))
        .map(value -> {
          final ParseResult first = value.getFirst();
          final List<ParseResult> rest = value.getSecond();
          if (rest.isEmpty()) {
            return first;
          }
          final List<PyType> types = new ArrayList<>();
          types.add(first.getType());
          ParseResult result = first;
          for (ParseResult r : rest) {
            types.add(r.getType());
            result = result.merge(r);
          }
          return result.withType(PyUnionType.union(types));
        })
        .named("union-expr");

    typeExpr
      .define(unionExpr)
      .named("type-expr");

    final FunctionalParser<ParseResult, PyElementType> typeFile =
      typeExpr
        .endOfInput()
        .named("type-file");

    try {
      return typeFile.parse(tokenize(type));
    }
    catch (ParserException e) {
      return EMPTY_RESULT;
    }
  }
@NotNull
  public static ParseResult parse(@NotNull PsiElement anchor, @NotNull String type, @NotNull TypeEvalContext context)