@Nullable
  @Override
  public PyType getReturnType(
      @NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) {
    final PyType type = getGenericReturnType(context, callSite);

    if (callSite == null) {
      return type;
    }
    final PyTypeChecker.AnalyzeCallResults results =
        PyTypeChecker.analyzeCallSite(callSite, context);

    if (PyTypeChecker.hasGenerics(type, context)) {
      if (results != null) {
        final Map<PyGenericType, PyType> substitutions =
            PyTypeChecker.unifyGenericCall(
                this, results.getReceiver(), results.getArguments(), context);
        if (substitutions != null) {
          return PyTypeChecker.substitute(type, substitutions, context);
        }
      }
      return null;
    }
    if (results != null && isDynamicallyEvaluated(results.getArguments().values(), context)) {
      return PyUnionType.createWeakType(type);
    } else {
      return type;
    }
  }
 @Nullable
 /** Suits when there is no call site(e.g. implicit __iter__ call in statement for) */
 public PyType getReturnTypeWithoutCallSite(
     @NotNull TypeEvalContext context, @Nullable PyExpression receiver) {
   final PyType type = getGenericReturnType(context, null);
   if (PyTypeChecker.hasGenerics(type, context)) {
     final Map<PyGenericType, PyType> substitutions =
         PyTypeChecker.unifyGenericCall(
             this, receiver, Maps.<PyExpression, PyNamedParameter>newHashMap(), context);
     if (substitutions != null) {
       return PyTypeChecker.substitute(type, substitutions, context);
     }
     return null;
   }
   return type;
 }
 @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;
 }