@Override
 public void visitPyReturnStatement(PyReturnStatement node) {
   if (PsiTreeUtil.getParentOfType(node, ScopeOwner.class, true) == myFunction) {
     final PyExpression expr = node.getExpression();
     PyType returnType;
     returnType = expr == null ? PyNoneType.INSTANCE : myContext.getType(expr);
     if (!myHasReturns) {
       myResult = returnType;
       myHasReturns = true;
     } else {
       myResult = PyUnionType.union(myResult, returnType);
     }
   }
 }
 @Override
 public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) {
   for (PyTypeProvider provider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
     final PyType type = provider.getCallableType(this, context);
     if (type != null) {
       return type;
     }
   }
   final PyFunctionTypeImpl type = new PyFunctionTypeImpl(this);
   if (PyKnownDecoratorUtil.hasUnknownDecorator(this, context) && getProperty() == null) {
     return PyUnionType.createWeakType(type);
   }
   return type;
 }
  @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;
  }
 @Nullable
 private PyType analyzeCallType(
     @Nullable PyType type,
     @Nullable PyExpression receiver,
     @NotNull Map<PyExpression, PyNamedParameter> parameters,
     @NotNull TypeEvalContext context) {
   if (PyTypeChecker.hasGenerics(type, context)) {
     final Map<PyGenericType, PyType> substitutions =
         PyTypeChecker.unifyGenericCall(receiver, parameters, context);
     if (substitutions != null) {
       type = PyTypeChecker.substitute(type, substitutions, context);
     } else {
       type = null;
     }
   }
   if (receiver != null) {
     type = replaceSelf(type, receiver, context);
   }
   if (type != null && isDynamicallyEvaluated(parameters.values(), context)) {
     type = PyUnionType.createWeakType(type);
   }
   return type;
 }