docs: protected ClassNode inferReturnTypeGenerics(
              ClassNode receiver,
              MethodNode method,
              Expression arguments,
              GenericsType[] explicitTypeHints) {
          ClassNode returnType = method.getReturnType();
          if (method instanceof ExtensionMethodNode
                  && (isUsingGenericsOrIsArrayUsingGenerics(returnType))) {
              // check if the placeholder corresponds to the placeholder of the first parameter
              ExtensionMethodNode emn = (ExtensionMethodNode) method;
              MethodNode dgmMethod = emn.getExtensionMethodNode();
              ClassNode dc = emn.getDeclaringClass();
              ArgumentListExpression argList = new ArgumentListExpression();
              VariableExpression vexp = varX("$foo", receiver);
              vexp.setNodeMetaData(ExtensionMethodDeclaringClass.class, dc);
              argList.addExpression(vexp);
              if (arguments instanceof ArgumentListExpression) {
                  List<Expression> expressions = ((ArgumentListExpression) arguments).getExpressions();
                  for (Expression arg : expressions) {
                      argList.addExpression(arg);
                  }
              } else {
                  argList.addExpression(arguments);
              }
              return inferReturnTypeGenerics(receiver, dgmMethod, argList);
          }
          if (!isUsingGenericsOrIsArrayUsingGenerics(returnType)) return returnType;
          if (getGenericsWithoutArray(returnType) == null) return returnType;
          Map<GenericsTypeName, GenericsType> resolvedPlaceholders = resolvePlaceHoldersFromDeclaration(receiver, getDeclaringClass(method, arguments), method, method.isStatic());
          if (!receiver.isGenericsPlaceHolder()) {
              GenericsUtils.extractPlaceholders(receiver, resolvedPlaceholders);
          }
          resolvePlaceholdersFromExplicitTypeHints(method, explicitTypeHints, resolvedPlaceholders);
          if (resolvedPlaceholders.isEmpty()) {
              return boundUnboundedWildcards(returnType);
          }
          Map<GenericsTypeName, GenericsType> placeholdersFromContext = extractGenericsParameterMapOfThis(typeCheckingContext.getEnclosingMethod());
          applyGenericsConnections(placeholdersFromContext, resolvedPlaceholders);
  
          // then resolve receivers from method arguments
          Parameter[] parameters = method.getParameters();
          boolean isVargs = isVargs(parameters);
          ArgumentListExpression argList = InvocationWriter.makeArgumentList(arguments);
          List<Expression> expressions = argList.getExpressions();
          int paramLength = parameters.length;
          if (expressions.size() >= paramLength) {
              for (int i = 0; i < paramLength; i++) {
                  boolean lastArg = i == paramLength - 1;
                  ClassNode type = parameters[i].getType();
                  ClassNode actualType = getType(expressions.get(i));
                  while (!type.isUsingGenerics() && type.isArray() && actualType.isArray()) {
                      type = type.getComponentType();
                      actualType = actualType.getComponentType();
                  }
                  if (isUsingGenericsOrIsArrayUsingGenerics(type)) {
                      if (implementsInterfaceOrIsSubclassOf(actualType, CLOSURE_TYPE) &&
                              isSAMType(type)) {
                          // implicit closure coercion in action!
                          Map<GenericsTypeName, GenericsType> pholders = applyGenericsContextToParameterClass(resolvedPlaceholders, type);
                          actualType = convertClosureTypeToSAMType(expressions.get(i), actualType, type, pholders);
                      }
                      if (isVargs && lastArg && actualType.isArray()) {
                          actualType = actualType.getComponentType();
                      }
                      if (isVargs && lastArg && type.isArray()) {
                          type = type.getComponentType();
                      }
                      actualType = wrapTypeIfNecessary(actualType);
  
                      Map<GenericsTypeName, GenericsType> connections = new HashMap<GenericsTypeName, GenericsType>();
                      extractGenericsConnections(connections, actualType, type);
                      extractGenericsConnectionsForSuperClassAndInterfaces(resolvedPlaceholders, connections);
                      applyGenericsConnections(connections, resolvedPlaceholders);
                  }
              }
          }
  
          return applyGenericsContext(resolvedPlaceholders, returnType);
      }