@Nullable
 public String extractDeprecationMessage() {
   PyStatementList statementList = getStatementList();
   if (statementList == null) {
     return null;
   }
   return extractDeprecationMessage(Arrays.asList(statementList.getStatements()));
 }
  @Nullable
  private Ref<? extends PyType> getYieldStatementType(@NotNull final TypeEvalContext context) {
    Ref<PyType> elementType = null;
    final PyBuiltinCache cache = PyBuiltinCache.getInstance(this);
    final PyStatementList statements = getStatementList();
    final Set<PyType> types = new LinkedHashSet<>();
    statements.accept(
        new PyRecursiveElementVisitor() {
          @Override
          public void visitPyYieldExpression(PyYieldExpression node) {
            final PyExpression expr = node.getExpression();
            final PyType type = expr != null ? context.getType(expr) : null;
            if (node.isDelegating() && type instanceof PyCollectionType) {
              final PyCollectionType collectionType = (PyCollectionType) type;
              // TODO: Select the parameter types that matches T in Iterable[T]
              final List<PyType> elementTypes = collectionType.getElementTypes(context);
              types.add(elementTypes.isEmpty() ? null : elementTypes.get(0));
            } else {
              types.add(type);
            }
          }

          @Override
          public void visitPyFunction(PyFunction node) {
            // Ignore nested functions
          }
        });
    final int n = types.size();
    if (n == 1) {
      elementType = Ref.create(types.iterator().next());
    } else if (n > 0) {
      elementType = Ref.create(PyUnionType.union(types));
    }
    if (elementType != null) {
      final PyClass generator = cache.getClass(PyNames.FAKE_GENERATOR);
      if (generator != null) {
        final List<PyType> parameters =
            Arrays.asList(elementType.get(), null, getReturnStatementType(context));
        return Ref.create(new PyCollectionTypeImpl(generator, false, parameters));
      }
    }
    if (!types.isEmpty()) {
      return Ref.create(null);
    }
    return null;
  }
 @NotNull
 @Override
 protected List<PyElement> getMembersCouldBeMoved(@NotNull final PyClass pyClass) {
   return Lists.<PyElement>newArrayList(filterNameless(Arrays.asList(pyClass.getMethods())));
 }
 @Override
 public boolean hasConflict(@NotNull final PyFunction member, @NotNull final PyClass aClass) {
   return NamePredicate.hasElementWithSameName(member, Arrays.asList(aClass.getMethods()));
 }
  @NotNull
  public static ParseResult parsePep484FunctionTypeComment(
      @NotNull PsiElement anchor, @NotNull String text) {
    final ForwardDeclaration<ParseResult, PyElementType> typeExpr = ForwardDeclaration.create();

    final Function<Pair<ParseResult, List<ParseResult>>, ParseResult> toParamTypeList =
        pair -> {
          if (pair != null) {
            final ParseResult first = pair.getFirst();
            final List<ParseResult> second = pair.getSecond();
            final List<PyType> itemTypes = new ArrayList<>();
            ParseResult result = first;
            itemTypes.add(result.getType());
            for (ParseResult r : second) {
              result = result.merge(r);
              itemTypes.add(r.getType());
            }
            return result.withType(ParameterListType.fromParameterTypes(itemTypes));
          }
          return EMPTY_RESULT.withType(new ParameterListType(Collections.emptyList()));
        };

    final FunctionalParser<ParseResult, PyElementType> ellipsis =
        op("...").map(token -> EMPTY_RESULT.withType(EllipsisType.INSTANCE)).named("ellipsis");

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

    final FunctionalParser<ParseResult, PyElementType> typeParamList =
        op("[")
            .skipThen(maybe(typeExpr.then(many(op(",").skipThen(typeExpr)))))
            .thenSkip(op("]"))
            .map(toParamTypeList)
            .named("type-param-list");

    final FunctionalParser<ParseResult, PyElementType> typeParam =
        typeExpr.or(typeParamList).or(ellipsis).named("type-param");

    final FunctionalParser<ParseResult, PyElementType> genericType =
        classType
            .thenSkip(op("["))
            .then(typeParam)
            .then(many(op(",").skipThen(typeParam)))
            .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 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;
                  final PsiElement resolved = first.getElement();
                  if (resolved != null) {
                    final PyType typingType = PyTypingTypeProvider.getType(resolved, elementTypes);
                    if (typingType != null) {
                      return result.withType(typingType);
                    }
                  }
                  return EMPTY_RESULT;
                })
            .named("generic-type");

    typeExpr.define(genericType.or(classType)).named("type-expr");

    final FunctionalParser<ParseResult, PyElementType> paramType =
        maybe(op("*"))
            .then(maybe(op("*")))
            .then(typeExpr)
            .map(
                pair -> {
                  final ParseResult paramResult = pair.getSecond();
                  final PyType type = paramResult.getType();
                  int starCount = 0;
                  if (pair.getFirst().getFirst() != null) {
                    starCount++;
                  }
                  if (pair.getFirst().getSecond() != null) {
                    starCount++;
                  }
                  if (starCount == 0) {
                    return paramResult;
                  } else if (starCount == 1) {
                    final PyClassType tupleType = PyTupleType.createHomogeneous(anchor, type);
                    if (tupleType != null) {
                      return paramResult.withType(tupleType);
                    }
                    return EMPTY_RESULT;
                  } else if (starCount == 2) {
                    final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(anchor);
                    final PyClassType dictType = builtinCache.getDictType();
                    if (dictType != null) {
                      final PyClass pyClass = dictType.getPyClass();
                      return paramResult.withType(
                          new PyCollectionTypeImpl(
                              pyClass, false, Arrays.asList(builtinCache.getStrType(), type)));
                    }
                    return EMPTY_RESULT;
                  }
                  return EMPTY_RESULT;
                })
            .named("param-type");

    final FunctionalParser<ParseResult, PyElementType> paramTypes =
        paramType.then(many(op(",").skipThen(paramType))).map(toParamTypeList).named("param-types");

    final FunctionalParser<ParseResult, PyElementType> funcType =
        op("(")
            .skipThen(maybe(paramTypes.or(ellipsis)))
            .thenSkip(op(")"))
            .thenSkip(op("->"))
            .then(typeExpr)
            .map(
                value -> {
                  final ParseResult paramsResult = value.getFirst();
                  final ParseResult returnResult = value.getSecond();
                  final List<PyCallableParameter> parameters;
                  ParseResult result = returnResult;
                  if (paramsResult != null) {
                    result = result.merge(paramsResult);
                    final ParameterListType paramTypesList =
                        as(paramsResult.getType(), ParameterListType.class);
                    if (paramTypesList != null) {
                      parameters = paramTypesList.getCallableParameters();
                    }
                    // ellipsis
                    else {
                      parameters = null;
                    }
                  } else {
                    parameters = Collections.emptyList();
                    result = returnResult;
                  }
                  return result.withType(
                      new PyCallableTypeImpl(parameters, returnResult.getType()));
                })
            .named("func-type");

    final FunctionalParser<ParseResult, PyElementType> typeFile =
        funcType.endOfInput().named("function-type-comment");

    try {
      return typeFile.parse(tokenize(text));
    } catch (ParserException e) {
      return EMPTY_RESULT;
    }
  }
  /** @param anchor should never be null or null will be returned */
  @NotNull
  public static ParseResult parse(@Nullable final PsiElement anchor, @NotNull String type) {
    PyPsiUtils.assertValid(anchor);
    if (anchor == null) {
      return EMPTY_RESULT;
    }

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

    final FunctionalParser<ParseResult, PyElementType> classType =
        token(IDENTIFIER)
            .then(many(op(".").skipThen(token(IDENTIFIER))))
            .map(new MakeSimpleType(anchor))
            .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 PyGenericType type1 = new PyGenericType(name, boundResult.getType());
                    final ParseResult result = new ParseResult(null, type1, range);
                    return result.merge(boundResult).withType(type1);
                  }
                  return new ParseResult(null, new PyGenericType(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;
                  final PsiElement resolved = first.getElement();
                  if (resolved != null) {
                    final PyType typingType = PyTypingTypeProvider.getType(resolved, elementTypes);
                    if (typingType != null) {
                      return result.withType(typingType);
                    }
                  }
                  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(new PyCallableParameterImpl(null, first.getType()));
                    for (ParseResult r : second) {
                      result = result.merge(r);
                      parameters.add(new PyCallableParameterImpl(null, 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;
    }
  }