private void fillInFormalParameterTypes(
     JSDocInfo jsdoc,
     Node funNode,
     ImmutableList<String> typeParameters,
     DeclaredTypeRegistry registry,
     FunctionTypeBuilder builder,
     boolean ignoreJsdoc /* for when the jsdoc is malformed */) {
   boolean ignoreFunNode = !funNode.isFunction();
   Node params = ignoreFunNode ? null : funNode.getSecondChild();
   ParamIterator iterator = new ParamIterator(params, jsdoc);
   while (iterator.hasNext()) {
     String pname = iterator.nextString();
     Node param = iterator.getNode();
     ParameterKind p = ParameterKind.REQUIRED;
     if (param != null && convention.isOptionalParameter(param)) {
       p = ParameterKind.OPTIONAL;
     } else if (param != null && convention.isVarArgsParameter(param)) {
       p = ParameterKind.REST;
     }
     ParameterType inlineParamType =
         (ignoreJsdoc || ignoreFunNode || param.getJSDocInfo() == null)
             ? null
             : parseParameter(param.getJSDocInfo().getType(), p, registry, typeParameters);
     ParameterType fnParamType = inlineParamType;
     JSTypeExpression jsdocExp = jsdoc == null ? null : jsdoc.getParameterType(pname);
     if (jsdocExp != null) {
       if (inlineParamType == null) {
         fnParamType = parseParameter(jsdocExp, p, registry, typeParameters);
       } else {
         warnings.add(JSError.make(param, TWO_JSDOCS, "formal parameter " + pname));
       }
     }
     JSType t = null;
     if (fnParamType != null) {
       p = fnParamType.kind;
       t = fnParamType.type;
     }
     switch (p) {
       case REQUIRED:
         builder.addReqFormal(t);
         break;
       case OPTIONAL:
         builder.addOptFormal(t);
         break;
       case REST:
         builder.addRestFormals(t != null ? t : JSType.UNKNOWN);
         break;
     }
   }
 }
 private void fillInFunTypeBuilder(
     Node jsdocNode,
     RawNominalType ownerType,
     DeclaredTypeRegistry registry,
     ImmutableList<String> typeParameters,
     FunctionTypeBuilder builder)
     throws UnknownTypeException {
   Node child = jsdocNode.getFirstChild();
   if (child.getType() == Token.THIS) {
     if (ownerType == null) {
       builder.addReceiverType(getThisOrNewType(child.getFirstChild(), registry, typeParameters));
     }
     child = child.getNext();
   } else if (child.getType() == Token.NEW) {
     Node newTypeNode = child.getFirstChild();
     JSType t = getThisOrNewType(newTypeNode, registry, typeParameters);
     if (!t.isSubtypeOf(JSType.TOP_OBJECT) && (!t.hasTypeVariable() || t.hasScalar())) {
       warnings.add(JSError.make(newTypeNode, NEW_EXPECTS_OBJECT_OR_TYPEVAR, t.toString()));
     }
     builder.addNominalType(t);
     child = child.getNext();
   }
   if (child.getType() == Token.PARAM_LIST) {
     for (Node arg = child.getFirstChild(); arg != null; arg = arg.getNext()) {
       try {
         switch (arg.getType()) {
           case Token.EQUALS:
             builder.addOptFormal(
                 getTypeFromCommentHelper(arg.getFirstChild(), registry, typeParameters));
             break;
           case Token.ELLIPSIS:
             Node restNode = arg.getFirstChild();
             builder.addRestFormals(
                 restNode == null
                     ? JSType.UNKNOWN
                     : getTypeFromCommentHelper(restNode, registry, typeParameters));
             break;
           default:
             builder.addReqFormal(getTypeFromCommentHelper(arg, registry, typeParameters));
             break;
         }
       } catch (FunctionTypeBuilder.WrongParameterOrderException e) {
         warnings.add(JSError.make(jsdocNode, WRONG_PARAMETER_ORDER));
         builder.addPlaceholderFormal();
       }
     }
     child = child.getNext();
   }
   builder.addRetType(getTypeFromCommentHelper(child, registry, typeParameters));
 }
 public FunctionType toFunctionType() {
   FunctionTypeBuilder builder = new FunctionTypeBuilder();
   for (JSType formal : requiredFormals) {
     builder.addReqFormal(formal == null ? JSType.UNKNOWN : formal);
   }
   for (JSType formal : optionalFormals) {
     builder.addOptFormal(formal == null ? JSType.UNKNOWN : formal);
   }
   builder.addRestFormals(restFormals);
   builder.addRetType(returnType == null ? JSType.UNKNOWN : returnType);
   builder.addNominalType(nominalType);
   builder.addReceiverType(receiverType);
   builder.addTypeParameters(typeParameters);
   return builder.buildFunction();
 }
 public DeclaredFunctionType withTypeInfoFromSuper(DeclaredFunctionType superType) {
   FunctionTypeBuilder builder = new FunctionTypeBuilder();
   int i = 0;
   for (JSType formal : requiredFormals) {
     builder.addReqFormal(formal != null ? formal : superType.getFormalType(i));
     i++;
   }
   for (JSType formal : optionalFormals) {
     builder.addOptFormal(formal != null ? formal : superType.getFormalType(i));
     i++;
   }
   if (restFormals != null) {
     builder.addRestFormals(restFormals);
   } else if (superType.hasRestFormals()) {
     builder.addRestFormals(superType.restFormals);
   }
   builder.addRetType(returnType != null ? returnType : superType.returnType);
   builder.addNominalType(nominalType);
   builder.addReceiverType(receiverType);
   builder.addTypeParameters(typeParameters);
   return builder.buildDeclaration();
 }
  private static DeclaredFunctionType meet(DeclaredFunctionType f1, DeclaredFunctionType f2) {
    if (f1.equals(f2)) {
      return f1;
    }

    FunctionTypeBuilder builder = new FunctionTypeBuilder();
    int minRequiredArity = Math.min(f1.requiredFormals.size(), f2.requiredFormals.size());
    for (int i = 0; i < minRequiredArity; i++) {
      builder.addReqFormal(nullAcceptingJoin(f1.getFormalType(i), f2.getFormalType(i)));
    }
    int maxTotalArity =
        Math.max(
            f1.requiredFormals.size() + f1.optionalFormals.size(),
            f2.requiredFormals.size() + f2.optionalFormals.size());
    for (int i = minRequiredArity; i < maxTotalArity; i++) {
      builder.addOptFormal(nullAcceptingJoin(f1.getFormalType(i), f2.getFormalType(i)));
    }
    if (f1.restFormals != null || f2.restFormals != null) {
      builder.addRestFormals(nullAcceptingJoin(f1.restFormals, f2.restFormals));
    }
    builder.addRetType(nullAcceptingMeet(f1.returnType, f2.returnType));
    return builder.buildDeclaration();
  }