@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 getReturnType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) {
   for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
     final PyType returnType = typeProvider.getReturnType(this, context);
     if (returnType != null) {
       returnType.assertValid(typeProvider.toString());
       return returnType;
     }
   }
   if (context.maySwitchToAST(this)
       && LanguageLevel.forElement(this).isAtLeast(LanguageLevel.PYTHON30)) {
     PyAnnotation anno = getAnnotation();
     if (anno != null) {
       PyClass pyClass = anno.resolveToClass();
       if (pyClass != null) {
         return new PyClassTypeImpl(pyClass, false);
       }
     }
   }
   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
 private PyType getGenericReturnType(
     @NotNull TypeEvalContext typeEvalContext, @Nullable PyQualifiedExpression callSite) {
   if (typeEvalContext.maySwitchToAST(this)
       && LanguageLevel.forElement(this).isAtLeast(LanguageLevel.PYTHON30)) {
     PyAnnotation anno = getAnnotation();
     if (anno != null) {
       PyClass pyClass = anno.resolveToClass();
       if (pyClass != null) {
         return new PyClassTypeImpl(pyClass, false);
       }
     }
   }
   for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
     final PyType returnType = typeProvider.getReturnType(this, callSite, typeEvalContext);
     if (returnType != null) {
       returnType.assertValid(typeProvider.toString());
       return returnType;
     }
   }
   final PyType docStringType = getReturnTypeFromDocString();
   if (docStringType != null) {
     docStringType.assertValid("from docstring");
     return docStringType;
   }
   if (typeEvalContext.allowReturnTypes(this)) {
     final PyType yieldType = getYieldStatementType(typeEvalContext);
     if (yieldType != null) {
       return yieldType;
     }
     return getReturnStatementType(typeEvalContext);
   }
   return null;
 }
 @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;
 }
 @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 PyFunctionType type = new PyFunctionType(this);
   if (getDecoratorList() != null) {
     return PyUnionType.createWeakType(type);
   }
   return type;
 }
  @Nullable
  @Override
  public PyType getCallType(
      @NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) {
    for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
      final Ref<PyType> typeRef = typeProvider.getCallType(this, callSite, context);
      if (typeRef != null) {
        return derefType(typeRef, typeProvider);
      }
    }

    final PyExpression receiver = PyTypeChecker.getReceiver(callSite, this);
    final Map<PyExpression, PyNamedParameter> mapping =
        PyCallExpressionHelper.mapArguments(callSite, this, context);
    return getCallType(receiver, mapping, context);
  }
 @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 boolean hasCustomDecorators =
       PyUtil.hasCustomDecorators(this)
           && !PyUtil.isDecoratedAsAbstract(this)
           && getProperty() == null;
   final PyFunctionType type = new PyFunctionType(this);
   if (hasCustomDecorators) {
     return PyUnionType.createWeakType(type);
   }
   return type;
 }
 @Nullable
 private static PyType derefType(
     @NotNull Ref<PyType> typeRef, @NotNull PyTypeProvider typeProvider) {
   final PyType type = typeRef.get();
   if (type != null) {
     type.assertValid(typeProvider.toString());
   }
   return type;
 }
  @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
 @Override
 public PyType getCallType(
     @NotNull TypeEvalContext context, @NotNull PyQualifiedExpression callSite) {
   PyType type = null;
   for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
     type = typeProvider.getCallType(this, callSite, context);
     if (type != null) {
       type.assertValid(typeProvider.toString());
       break;
     }
   }
   if (type == null) {
     type = context.getReturnType(this);
   }
   final PyTypeChecker.AnalyzeCallResults results =
       PyTypeChecker.analyzeCallSite(callSite, context);
   if (results != null) {
     return analyzeCallType(type, results.getReceiver(), results.getArguments(), context);
   }
   return type;
 }
 @Nullable
 @Override
 public PyType getCallType(
     @NotNull TypeEvalContext context, @NotNull PyCallSiteExpression callSite) {
   for (PyTypeProvider typeProvider : Extensions.getExtensions(PyTypeProvider.EP_NAME)) {
     final PyType type = typeProvider.getCallType(this, callSite, context);
     if (type != null) {
       type.assertValid(typeProvider.toString());
       return type;
     }
   }
   final PyExpression receiver = PyTypeChecker.getReceiver(callSite, this);
   final List<PyExpression> arguments = PyTypeChecker.getArguments(callSite, this);
   final List<PyParameter> parameters = PyUtil.getParameters(this, context);
   final PyResolveContext resolveContext =
       PyResolveContext.noImplicits().withTypeEvalContext(context);
   final List<PyParameter> explicitParameters =
       PyTypeChecker.filterExplicitParameters(parameters, this, callSite, resolveContext);
   final Map<PyExpression, PyNamedParameter> mapping =
       PyCallExpressionHelper.mapArguments(arguments, explicitParameters);
   return getCallType(receiver, mapping, context);
 }