/**
   * Notice that "call" and "bind" have the same argument signature, except that all the arguments
   * of "bind" (except the first) are optional.
   */
  private FunctionType getCallOrBindSignature(boolean isCall) {
    boolean isBind = !isCall;
    FunctionBuilder builder =
        new FunctionBuilder(registry)
            .withReturnType(isCall ? getReturnType() : getBindReturnType(-1))
            .withTemplateKeys(getTemplateTypeMap().getTemplateKeys());

    Node origParams = getParametersNode();
    if (origParams != null) {
      Node params = origParams.cloneTree();

      Node thisTypeNode = Node.newString(Token.NAME, "thisType");
      thisTypeNode.setJSType(registry.createOptionalNullableType(getTypeOfThis()));
      params.addChildToFront(thisTypeNode);

      if (isBind) {
        // The arguments of bind() are unique in that they are all
        // optional but not undefinable.
        for (Node current = thisTypeNode.getNext(); current != null; current = current.getNext()) {
          current.setOptionalArg(true);
        }
      } else if (isCall) {
        // The first argument of call() is optional iff all the arguments
        // are optional. It's sufficient to check the first argument.
        Node firstArg = thisTypeNode.getNext();
        if (firstArg == null || firstArg.isOptionalArg() || firstArg.isVarArgs()) {
          thisTypeNode.setOptionalArg(true);
        }
      }

      builder.withParamsNode(params);
    }

    return builder.build();
  }
 /**
  * Get the return value of calling "bind" on this function with the specified number of arguments.
  *
  * <p>If -1 is passed, then we will return a result that accepts any parameters.
  */
 public FunctionType getBindReturnType(int argsToBind) {
   FunctionBuilder builder =
       new FunctionBuilder(registry)
           .withReturnType(getReturnType())
           .withTemplateKeys(getTemplateTypeMap().getTemplateKeys());
   if (argsToBind >= 0) {
     Node origParams = getParametersNode();
     if (origParams != null) {
       Node params = origParams.cloneTree();
       for (int i = 1; i < argsToBind && params.getFirstChild() != null; i++) {
         if (params.getFirstChild().isVarArgs()) {
           break;
         }
         params.removeFirstChild();
       }
       builder.withParamsNode(params);
     }
   }
   return builder.build();
 }