case Token.FUNCTION:
// Function declaration, e.g. function Foo() {};
if (NodeUtil.isFunctionDeclaration(n)) {
if (!n.getJSType().isNoObjectType()) {
ConcreteFunctionType type = createConcreteFunction(n, scope);
scope.declareSlot(n.getFirstChild().getString(), n, type);
if (inExterns && type.getInstanceType() != null) {
// We must assume all extern types are instantiated since they
// can be created by the browser itself.
allInstantiatedTypes.add(type.getInstanceType());
}
}
}
break;
case Token.ASSIGN:
// Variable assignment, e.g. a = b;
Node lhs = n.getFirstChild();
if (inExterns) {
// Again, we have to trust the externs.
ConcreteScope scope;
if (lhs.getType() == Token.GETPROP) {
ConcreteType type = inferConcreteType(getTopScope(),
lhs.getFirstChild());
scope = (ConcreteScope) type.getScope();
} else {
scope = getTopScope();
}
if (scope == null) break;
ConcreteType type = inferConcreteType(getTopScope(), n);
if (type.isNone() || type.isAll()) {
break;
}
if (type.isFunction()) {
JSType lhsType = lhs.getJSType();
if (lhsType == null) {
break;
}
FunctionType funType =
lhsType.restrictByNotNullOrUndefined().toMaybeFunctionType();
if (funType == null) {
break;
}
ConcreteType retType = createType(funType.getReturnType());
retType = createUnionWithSubTypes(retType);
ConcreteType newret = type.toFunction().getReturnSlot()
.getType().unionWith(retType);
((ConcreteScope) type.getScope()).declareSlot(
ConcreteFunctionType.RETURN_SLOT_NAME, n, newret);
}
scope.declareSlot(lhs.getLastChild().getString(), n, type);
} else {
addActions(createAssignmentActions(lhs, n.getLastChild(), n));