docs: public static GenericsType[] applyGenericsContextToPlaceHolders(Map<String, ClassNode> genericsSpec, GenericsType[] oldPlaceHolders) {
          if (oldPlaceHolders == null || oldPlaceHolders.length == 0) return oldPlaceHolders;
          if (genericsSpec.isEmpty()) return oldPlaceHolders;
          GenericsType[] newTypes = new GenericsType[oldPlaceHolders.length];
          for (int i = 0; i < oldPlaceHolders.length; i++) {
              GenericsType old = oldPlaceHolders[i];
              if (!old.isPlaceholder())
                  throw new GroovyBugError("Given generics type " + old + " must be a placeholder!");
              ClassNode fromSpec = genericsSpec.get(old.getName());
              if (fromSpec != null) {
                  if (fromSpec.isGenericsPlaceHolder()) {
                      ClassNode[] upper = new ClassNode[]{fromSpec.redirect()};
                      newTypes[i] = new GenericsType(fromSpec, upper, null);
                  } else {
                      newTypes[i] = new GenericsType(fromSpec);
                  }
              } else {
                  ClassNode[] upper = old.getUpperBounds();
                  ClassNode[] newUpper = upper;
                  if (upper != null && upper.length > 0) {
                      ClassNode[] upperCorrected = new ClassNode[upper.length];
                      for (int j = 0; j < upper.length; j++) {
                          upperCorrected[i] = correctToGenericsSpecRecurse(genericsSpec, upper[j]);
                      }
                      upper = upperCorrected;
                  }
                  ClassNode lower = old.getLowerBound();
                  ClassNode newLower = correctToGenericsSpecRecurse(genericsSpec, lower);
                  if (lower == newLower && upper == newUpper) {
                      newTypes[i] = oldPlaceHolders[i];
                  } else {
                      ClassNode newPlaceHolder = ClassHelper.make(old.getName());
                      GenericsType gt = new GenericsType(newPlaceHolder, newUpper, newLower);
                      gt.setPlaceholder(true);
                      newTypes[i] = gt;
                  }
              }
          }
          return newTypes;
      }