}
private EnvTypePair analyzeCallNewBwd(
Node expr, TypeEnv outEnv, JSType requiredType) {
Node callee = expr.getFirstChild();
JSType calleeTypeGeneral =
analyzeExprBwd(callee, outEnv, JSType.topFunction()).type;
FunctionType funType = calleeTypeGeneral.getFunType();
if (funType == null) {
return analyzeCallNodeArgumentsBwd(expr, outEnv);
} else if (funType.isLoose()) {
return analyzeLooseCallNodeBwd(expr, outEnv, requiredType);
} else if (expr.isCall() && funType.isConstructor() ||
expr.isNew() && !funType.isConstructor()) {
return analyzeCallNodeArgumentsBwd(expr, outEnv);
} else if (funType.isTopFunction()) {
return analyzeCallNodeArgumentsBwd(expr, outEnv);
}
if (callee.isName() && !funType.isGeneric() && expr.isCall()) {
createDeferredCheckBwd(expr, requiredType);
}
int numArgs = expr.getChildCount() - 1;
if (numArgs < funType.getMinArity() || numArgs > funType.getMaxArity()) {
return analyzeCallNodeArgumentsBwd(expr, outEnv);
}
if (funType.isGeneric()) {
Map<String, JSType> typeMap =
calcTypeInstantiationBwd(expr, funType, outEnv);
funType = funType.instantiateGenerics(typeMap);
}
TypeEnv tmpEnv = outEnv;
// In bwd direction, analyze arguments in reverse
for (int i = expr.getChildCount() - 2; i >= 0; i--) {
JSType formalType = funType.getFormalType(i);
// The type of a formal can be BOTTOM as the result of a join.
// Don't use this as a requiredType.
if (formalType.isBottom()) {
formalType = JSType.UNKNOWN;
}
Node arg = expr.getChildAtIndex(i + 1);
tmpEnv = analyzeExprBwd(arg, tmpEnv, formalType).env;
// We don't need deferred checks for args in BWD