case Token.ARRAYLIT: {
if (!n.hasChildren()) {
return null;
}
Node child = n.getFirstChild();
JSType arrayType = simpleInferExprType(child);
if (arrayType == null) {
return null;
}
while (null != (child = child.getNext())) {
if (!arrayType.equals(simpleInferExprType(child))) {
return null;
}
}
return getArrayType(arrayType);
}
case Token.TRUE:
return JSType.TRUE_TYPE;
case Token.FALSE:
return JSType.FALSE_TYPE;
case Token.NAME: {
String varName = n.getString();
if (varName.equals("undefined")) {
return JSType.UNDEFINED;
} else if (currentScope.isNamespaceLiteral(varName)) {
// Namespaces (literals, enums, constructors) get populated during
// ProcessScope, so it's NOT safe to convert them to jstypes until
// after ProcessScope is done. So, we don't try to do sth clever
// here to find the type of a namespace property.
// However, in the GETPROP case, we special-case for enum
// properties, because enums get resolved right after
// CollectNamedTypes, so we know the enumerated type.
// (But we still don't know the types of enum properties outside
// the object-literal declaration.)
return null;
}
return currentScope.getDeclaredTypeOf(varName);
}
case Token.OBJECTLIT: {
JSType objLitType = JSType.TOP_OBJECT;
for (Node prop : n.children()) {
JSType propType = simpleInferExprType(prop.getFirstChild());
if (propType == null) {
return null;
}
objLitType = objLitType.withProperty(
new QualifiedName(NodeUtil.getObjectLitKeyName(prop)),
propType);
}
return objLitType;
}
case Token.GETPROP:
Node recv = n.getFirstChild();
JSType recvType = simpleInferExprType(recv);
if (recvType == null) {
EnumType et = currentScope.getEnum(recv.getQualifiedName());
if (et == null) {
return null;
}
if (et.enumLiteralHasKey(n.getLastChild().getString())) {
return et.getEnumeratedType();
}
return null;
}
QualifiedName qname = new QualifiedName(n.getLastChild().getString());
if (!recvType.mayHaveProp(qname)) {
return null;
}
return recvType.getProp(qname);
case Token.COMMA:
case Token.ASSIGN:
return simpleInferExprType(n.getLastChild());
case Token.CALL:
case Token.NEW:
JSType ratorType = simpleInferExprType(n.getFirstChild());
if (ratorType == null) {
return null;
}
FunctionType funType = ratorType.getFunType();
if (funType == null) {
return null;
}
if (funType.isGeneric()) {
ImmutableList.Builder<JSType> argTypes = ImmutableList.builder();
for (Node argNode = n.getFirstChild().getNext();
argNode != null;
argNode = argNode.getNext()) {
JSType t = simpleInferExprType(argNode);
if (t == null) {
return null;
}
argTypes.add(t);
}