@Nullable
 private PyType getReturnType(@NotNull TypeEvalContext context) {
   for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
     final Ref<PyType> returnTypeRef = typeProvider.getReturnType(this, context);
     if (returnTypeRef != null) {
       final PyType returnType = returnTypeRef.get();
       if (returnType != null) {
         returnType.assertValid(typeProvider.toString());
       }
       return returnType;
     }
   }
   final PyType docStringType = getReturnTypeFromDocString();
   if (docStringType != null) {
     docStringType.assertValid("from docstring");
     return docStringType;
   }
   if (context.allowReturnTypes(this)) {
     final Ref<? extends PyType> yieldTypeRef = getYieldStatementType(context);
     if (yieldTypeRef != null) {
       return yieldTypeRef.get();
     }
     return getReturnStatementType(context);
   }
   return null;
 }
 @Nullable
 @Override
 public PyType getCallType(
     @Nullable PyExpression receiver,
     @NotNull Map<PyExpression, PyNamedParameter> parameters,
     @NotNull TypeEvalContext context) {
   return analyzeCallType(context.getReturnType(this), receiver, parameters, context);
 }
 private static boolean isDynamicallyEvaluated(
     @NotNull Collection<PyNamedParameter> parameters, @NotNull TypeEvalContext context) {
   for (PyNamedParameter parameter : parameters) {
     final PyType type = context.getType(parameter);
     if (type instanceof PyDynamicallyEvaluatedType) {
       return true;
     }
   }
   return false;
 }
 @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);
     }
   }
 }
  @Nullable
  private PyType getReturnType(@NotNull TypeEvalContext context) {
    for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
      final Ref<PyType> returnTypeRef = typeProvider.getReturnType(this, context);
      if (returnTypeRef != null) {
        return derefType(returnTypeRef, typeProvider);
      }
    }

    if (context.allowReturnTypes(this)) {
      final Ref<? extends PyType> yieldTypeRef = getYieldStatementType(context);
      if (yieldTypeRef != null) {
        return yieldTypeRef.get();
      }
      return getReturnStatementType(context);
    }

    return null;
  }
 @Nullable
 private PyType replaceSelf(
     @Nullable PyType returnType,
     @Nullable PyExpression receiver,
     @NotNull TypeEvalContext context) {
   if (receiver != null) {
     // TODO: Currently we substitute only simple subclass types, but we could handle union and
     // collection types as well
     if (returnType instanceof PyClassType) {
       final PyClassType returnClassType = (PyClassType) returnType;
       if (returnClassType.getPyClass() == getContainingClass()) {
         final PyType receiverType = context.getType(receiver);
         if (receiverType instanceof PyClassType
             && PyTypeChecker.match(returnType, receiverType, context)) {
           return returnClassType.isDefinition()
               ? receiverType
               : ((PyClassType) receiverType).toInstance();
         }
       }
     }
   }
   return returnType;
 }