docs: public static List<MethodNode> chooseBestMethod(final ClassNode receiver, Collection<MethodNode> methods, ClassNode... args) {
          if (methods.isEmpty()) return Collections.emptyList();
          if (isUsingUncheckedGenerics(receiver)) {
              ClassNode raw = makeRawType(receiver);
              return chooseBestMethod(raw, methods, args);
          }
          List<MethodNode> bestChoices = new LinkedList<MethodNode>();
          int bestDist = Integer.MAX_VALUE;
          Collection<MethodNode> choicesLeft = removeCovariantsAndInterfaceEquivalents(methods);
          for (MethodNode candidateNode : choicesLeft) {
              ClassNode declaringClassForDistance = candidateNode.getDeclaringClass();
              ClassNode actualReceiverForDistance = receiver != null ? receiver : candidateNode.getDeclaringClass();
              MethodNode safeNode = candidateNode;
              ClassNode[] safeArgs = args;
              boolean isExtensionMethodNode = candidateNode instanceof ExtensionMethodNode;
              if (isExtensionMethodNode) {
                  safeArgs = new ClassNode[args.length + 1];
                  System.arraycopy(args, 0, safeArgs, 1, args.length);
                  safeArgs[0] = receiver;
                  safeNode = ((ExtensionMethodNode) candidateNode).getExtensionMethodNode();
              }
  
              // todo : corner case
              /*
                  class B extends A {}
  
                  Animal foo(A o) {...}
                  Person foo(B i){...}
  
                  B  a = new B()
                  Person p = foo(b)
               */
  
              Map<GenericsType, GenericsType> declaringAndActualGenericsTypeMap = GenericsUtils.makeDeclaringAndActualGenericsTypeMap(declaringClassForDistance, actualReceiverForDistance);
              Parameter[] params = makeRawTypes(safeNode.getParameters(), declaringAndActualGenericsTypeMap);
              int dist = measureParametersAndArgumentsDistance(params, safeArgs);
              if (dist >= 0) {
                  dist += getClassDistance(declaringClassForDistance, actualReceiverForDistance);
                  dist += getExtensionDistance(isExtensionMethodNode);
                  if (dist < bestDist) {
                      bestChoices.clear();
                      bestChoices.add(candidateNode);
                      bestDist = dist;
                  } else if (dist == bestDist) {
                      bestChoices.add(candidateNode);
                  }
              }
          }
          if (bestChoices.size() > 1) {
              // GROOVY-6849: prefer extension methods in case of ambiguity
              List<MethodNode> onlyExtensionMethods = new LinkedList<MethodNode>();
              for (MethodNode choice : bestChoices) {
                  if (choice instanceof ExtensionMethodNode) {
                      onlyExtensionMethods.add(choice);
                  }
              }
              if (onlyExtensionMethods.size() == 1) {
                  return onlyExtensionMethods;
              }
          }
          return bestChoices;
      }