// Every trailing undeclared formal whose inferred type is ?
// or contains undefined can be marked as optional.
List<String> formals = fn.getFormals();
for (int i = reqArity - 1; i >= 0; i--) {
JSType formalType = fn.getDeclaredType().getFormalType(i);
if (formalType != null) {
break;
}
String formalName = formals.get(i);
formalType = getTypeAfterFwd(formalName, entryEnv, exitEnv);
if (formalType.isUnknown() || JSType.UNDEFINED.isSubtypeOf(formalType)) {
reqArity--;
} else {
break;
}
}
// Collect types of formals in the builder
int formalIndex = 0;
for (String formal : formals) {
JSType formalType = fn.getDeclaredTypeOf(formal);
if (formalType == null) {
formalType = getTypeAfterFwd(formal, entryEnv, exitEnv);
}
if (formalIndex < reqArity) {
builder.addReqFormal(formalType);
} else if (formalIndex < optArity) {
builder.addOptFormal(formalType);
}
formalIndex++;
}
if (declType.hasRestFormals()) {
builder.addRestFormals(declType.getFormalType(formalIndex));
}
for (String outer : fn.getOuterVars()) {
println("Free var ", outer, " going in summary");
builder.addOuterVarPrecondition(
outer, getTypeAfterFwd(outer, entryEnv, exitEnv));
}
builder.addNominalType(declType.getNominalType());
builder.addReceiverType(declType.getReceiverType());
JSType declRetType = declType.getReturnType();
JSType actualRetType = envGetType(exitEnv, RETVAL_ID);
if (declRetType == null) {
builder.addRetType(actualRetType);
} else {
builder.addRetType(declRetType);
if (!isAllowedToNotReturn(fn) &&
!JSType.UNDEFINED.isSubtypeOf(declRetType) &&
hasPathWithNoReturn(cfg)) {
warnings.add(JSError.make(fn.getRoot(),
CheckMissingReturn.MISSING_RETURN_STATEMENT,
declRetType.toString()));
}
}
JSType summary = builder.buildType();
println("Function summary for ", fn.getReadableName());
println("\t", summary);
summaries.put(fn, summary);
}