private static PsiType captureReturnType(PsiMethodCallExpression call,
                                           PsiMethod method,
                                           PsiType ret,
                                           JavaResolveResult result,
                                           LanguageLevel languageLevel, 
                                           PsiFile file) {
    PsiSubstitutor substitutor = result.getSubstitutor();
    substitutor.ensureValid();
    PsiType substitutedReturnType = substitutor.substitute(ret);
    if (substitutedReturnType == null) {
      return TypeConversionUtil.erasure(ret);
    }

    if (result instanceof MethodCandidateInfo && ((MethodCandidateInfo)result).isErased()) {
      // 18.5.2
      // if unchecked conversion was necessary, then this substitution provides the parameter types of the invocation type, 
      // while the return type and thrown types are given by the erasure of m's type (without applying theta').
      //due to https://bugs.openjdk.org/browse/JDK-8135087 erasure is called on substitutedReturnType and not on ret type itself as by spec
      return TypeConversionUtil.erasure(substitutedReturnType);
    }

    //15.12.2.6. Method Invocation Type
    // If unchecked conversion was necessary for the method to be applicable, 
    // the parameter types of the invocation type are the parameter types of the method's type,
    // and the return type and thrown types are given by the erasures of the return type and thrown types of the method's type.
    if ((!languageLevel.isAtLeast(LanguageLevel.JDK_1_8) || call.getTypeArguments().length > 0) && method.hasTypeParameters() ||
        !method.hasTypeParameters() && JavaVersionService.getInstance().isAtLeast(file, JavaSdkVersion.JDK_1_8)) {
      PsiType erased = TypeConversionUtil.erasure(substitutedReturnType);
      if (!substitutedReturnType.equals(erased) && result instanceof MethodCandidateInfo && ((MethodCandidateInfo)result).isApplicable()) {
        final PsiType[] args = call.getArgumentList().getExpressionTypes();
        final PsiParameter[] parameters = method.getParameterList().getParameters();
        final boolean varargs = ((MethodCandidateInfo)result).getApplicabilityLevel() == MethodCandidateInfo.ApplicabilityLevel.VARARGS;
        for (int i = 0; i < args.length; i++) {
          final PsiType parameterType = substitutor.substitute(PsiTypesUtil.getParameterType(parameters, i, varargs));
          final PsiType expressionType = args[i];
          if (expressionType != null && parameterType != null && JavaGenericsUtil.isRawToGeneric(parameterType, expressionType)) {
            return erased;
          }
        }
      }
    }

    if (PsiUtil.isRawSubstitutor(method, substitutor)) {
      final PsiType returnTypeErasure = TypeConversionUtil.erasure(ret);
      if (Comparing.equal(TypeConversionUtil.erasure(substitutedReturnType), returnTypeErasure)) {
        return returnTypeErasure;
      }
    }
    return PsiUtil.captureToplevelWildcards(substitutedReturnType, call);
  }
private static PsiType captureReturnType(PsiMethodCallExpression call,
                                           PsiMethod method,
                                           PsiType ret,
                                           JavaResolveResult result,
                                           LanguageLevel languageLevel, 
                                           PsiFile file)