use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class SimpleInference method inferPropAccess.
private JSType inferPropAccess(Node recv, String pname, NTIScope scope) {
if (recv.isGetProp() && recv.getLastChild().getString().equals("prototype")) {
return inferPrototypeProperty(recv.getFirstChild(), pname, scope);
}
QualifiedName propQname = new QualifiedName(pname);
JSType recvType = null;
if (recv.isQualifiedName()) {
QualifiedName recvQname = QualifiedName.fromNode(recv);
Declaration decl = scope.getDeclaration(recvQname, false);
if (decl != null) {
EnumType et = decl.getEnum();
if (et != null && et.enumLiteralHasKey(pname)) {
return et.getPropType();
}
Namespace ns = decl.getNamespace();
if (ns != null) {
return inferDeclaration(ns.getDeclaration(propQname));
}
recvType = decl.getTypeOfSimpleDecl();
}
}
if (recvType == null) {
recvType = inferExprRecur(recv, scope);
}
if (recvType == null) {
return null;
}
if (recvType.isScalar()) {
recvType = recvType.autobox();
}
FunctionType ft = recvType.getFunTypeIfSingletonObj();
if (ft != null && pname.equals("call")) {
return this.commonTypes.fromFunctionType(ft.transformByCallProperty());
} else if (ft != null && pname.equals("apply")) {
return this.commonTypes.fromFunctionType(ft.transformByApplyProperty());
}
if (recvType.mayHaveProp(propQname)) {
return recvType.getProp(propQname);
}
return null;
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class SimpleInference method inferInstantiatedCallee.
FunctionType inferInstantiatedCallee(Node call, FunctionType calleeType, boolean bailForUntypedArguments, NTIScope scope) {
Node callee = call.getFirstChild();
Preconditions.checkArgument(calleeType.isGeneric(), "Expected generic type for %s but found %s", callee, calleeType);
// The receiver type is useful for inference when calleeType has a @this annotation
// that includes a type variable.
JSType recvType = null;
if (callee.isGetProp() && callee.getFirstChild().isQualifiedName()) {
Node recv = callee.getFirstChild();
QualifiedName recvQname = QualifiedName.fromNode(recv);
Declaration decl = scope.getDeclaration(recvQname, false);
if (decl != null) {
recvType = decl.getTypeOfSimpleDecl();
}
}
ImmutableList.Builder<JSType> argTypes = ImmutableList.builder();
for (Node argNode = call.getSecondChild(); argNode != null; argNode = argNode.getNext()) {
JSType t = inferExprRecur(argNode, scope);
if (t == null) {
if (bailForUntypedArguments && !argNode.isFunction()) {
// Used for @const inference, where we want to be strict.
return null;
} else {
// Used when inferring a signature for unannotated callbacks passed to generic
// functions. Whatever type variable we can't infer will become unknown.
t = this.commonTypes.BOTTOM;
}
}
argTypes.add(t);
}
return calleeType.instantiateGenericsFromArgumentTypes(recvType, argTypes.build());
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class SimpleInference method inferGetelem.
private JSType inferGetelem(Node n, NTIScope scope) {
checkState(n.isGetElem());
Node recv = n.getFirstChild();
Node propNode = n.getLastChild();
// string literal as precisely as dot accesses.
if (propNode.isString()) {
JSType propType = inferPropAccess(recv, propNode.getString(), scope);
if (propType != null) {
return propType;
}
}
JSType recvType = inferExprRecur(recv, scope);
if (recvType != null) {
JSType indexType = recvType.getIndexType();
if (indexType != null) {
JSType propType = inferExprRecur(propNode, scope);
if (propType != null && propType.isSubtypeOf(indexType)) {
return recvType.getIndexedType();
}
}
}
return null;
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class SimpleInference method inferAndOr.
private JSType inferAndOr(Node n, NTIScope scope) {
checkState(n.isOr() || n.isAnd());
JSType lhs = inferExprRecur(n.getFirstChild(), scope);
if (lhs == null) {
return null;
}
JSType rhs = inferExprRecur(n.getSecondChild(), scope);
if (rhs == null) {
return null;
}
if (lhs.equals(rhs)) {
return lhs;
}
if (n.isAnd()) {
return JSType.join(lhs.specialize(this.commonTypes.FALSY), rhs);
}
return JSType.join(lhs.specialize(this.commonTypes.TRUTHY), rhs);
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method analyzeExprFwd.
/**
* @param requiredType The context requires this type; warn if the expression
* doesn't have this type.
* @param specializedType Used in boolean contexts to infer types of names.
*
* Invariant: specializedType is a subtype of requiredType.
*/
private EnvTypePair analyzeExprFwd(Node expr, TypeEnv inEnv, JSType requiredType, JSType specializedType) {
checkArgument(requiredType != null && !requiredType.isBottom());
EnvTypePair resultPair = null;
switch(expr.getToken()) {
case // can be created by a FOR with empty condition
EMPTY:
resultPair = new EnvTypePair(inEnv, UNKNOWN);
break;
case FUNCTION:
{
String fnName = symbolTable.getFunInternalName(expr);
JSType fnType = envGetType(inEnv, fnName);
Preconditions.checkState(fnType != null, "Could not find type for %s", fnName);
TypeEnv outEnv = collectTypesForEscapedVarsFwd(expr, inEnv);
resultPair = new EnvTypePair(outEnv, fnType);
break;
}
case FALSE:
case NULL:
case NUMBER:
case STRING:
case TRUE:
resultPair = new EnvTypePair(inEnv, scalarValueToType(expr.getToken()));
break;
case OBJECTLIT:
resultPair = analyzeObjLitFwd(expr, inEnv, requiredType, specializedType);
break;
case THIS:
{
resultPair = analyzeThisFwd(expr, inEnv, requiredType, specializedType);
break;
}
case SUPER:
{
resultPair = analyzeSuperFwd(expr, inEnv);
break;
}
case NAME:
resultPair = analyzeNameFwd(expr, inEnv, requiredType, specializedType);
break;
case AND:
case OR:
resultPair = analyzeLogicalOpFwd(expr, inEnv, requiredType, specializedType);
break;
case INC:
case DEC:
resultPair = analyzeIncDecFwd(expr, inEnv, requiredType);
break;
case BITNOT:
case NEG:
resultPair = analyzeUnaryNumFwd(expr, inEnv);
break;
case POS:
{
// We are more permissive with +, because it is used to coerce to number
resultPair = analyzeExprFwd(expr.getFirstChild(), inEnv);
resultPair.type = NUMBER;
break;
}
case TYPEOF:
{
resultPair = analyzeExprFwd(expr.getFirstChild(), inEnv);
resultPair.type = STRING;
break;
}
case INSTANCEOF:
resultPair = analyzeInstanceofFwd(expr, inEnv, specializedType);
break;
case ADD:
resultPair = analyzeAddFwd(expr, inEnv, requiredType);
break;
case BITOR:
case BITAND:
case BITXOR:
case DIV:
case EXPONENT:
case LSH:
case MOD:
case MUL:
case RSH:
case SUB:
case URSH:
resultPair = analyzeBinaryNumericOpFwd(expr, inEnv);
break;
case ASSIGN:
resultPair = analyzeAssignFwd(expr, inEnv, requiredType, specializedType);
break;
case ASSIGN_ADD:
resultPair = analyzeAssignAddFwd(expr, inEnv, requiredType);
break;
case ASSIGN_BITOR:
case ASSIGN_BITXOR:
case ASSIGN_BITAND:
case ASSIGN_LSH:
case ASSIGN_RSH:
case ASSIGN_URSH:
case ASSIGN_SUB:
case ASSIGN_MUL:
case ASSIGN_DIV:
case ASSIGN_MOD:
case ASSIGN_EXPONENT:
resultPair = analyzeAssignNumericOpFwd(expr, inEnv);
break;
case SHEQ:
case SHNE:
resultPair = analyzeStrictComparisonFwd(expr.getToken(), expr.getFirstChild(), expr.getLastChild(), inEnv, specializedType);
break;
case EQ:
case NE:
resultPair = analyzeNonStrictComparisonFwd(expr, inEnv, specializedType);
break;
case LT:
case GT:
case LE:
case GE:
resultPair = analyzeLtGtFwd(expr, inEnv);
break;
case GETPROP:
Preconditions.checkState(!NodeUtil.isAssignmentOp(expr.getParent()) || !NodeUtil.isLValue(expr));
if (expr.getBooleanProp(Node.ANALYZED_DURING_GTI)) {
if (expr.isQualifiedName() && !NodeUtil.isTypedefDecl(expr)) {
markAndGetTypeOfPreanalyzedNode(expr, inEnv, true);
}
expr.removeProp(Node.ANALYZED_DURING_GTI);
resultPair = new EnvTypePair(inEnv, requiredType);
} else {
resultPair = analyzePropAccessFwd(expr.getFirstChild(), expr.getLastChild().getString(), inEnv, requiredType, specializedType);
}
break;
case HOOK:
resultPair = analyzeHookFwd(expr, inEnv, requiredType, specializedType);
break;
case CALL:
case NEW:
case TAGGED_TEMPLATELIT:
resultPair = analyzeInvocationFwd(expr, inEnv, requiredType, specializedType);
break;
case COMMA:
resultPair = analyzeExprFwd(expr.getLastChild(), analyzeExprFwd(expr.getFirstChild(), inEnv).env, requiredType, specializedType);
break;
case NOT:
{
resultPair = analyzeExprFwd(expr.getFirstChild(), inEnv, UNKNOWN, specializedType.negate());
resultPair.type = resultPair.type.negate().toBoolean();
break;
}
case GETELEM:
resultPair = analyzeGetElemFwd(expr, inEnv, requiredType, specializedType);
break;
case VOID:
{
resultPair = analyzeExprFwd(expr.getFirstChild(), inEnv);
resultPair.type = UNDEFINED;
break;
}
case IN:
resultPair = analyzeInFwd(expr, inEnv, specializedType);
break;
case DELPROP:
{
// IRFactory checks that the operand is a name, getprop or getelem.
// analyzePropAccessFwd warns if we delete a constant property.
resultPair = analyzeExprFwd(expr.getFirstChild(), inEnv);
resultPair.type = BOOLEAN;
break;
}
case REGEXP:
resultPair = new EnvTypePair(inEnv, commonTypes.getRegexpType());
break;
case ARRAYLIT:
resultPair = analyzeArrayLitFwd(expr, inEnv);
break;
case CAST:
resultPair = analyzeCastFwd(expr, inEnv);
break;
case CASE:
// For a statement of the form: switch (exp1) { ... case exp2: ... }
// we analyze the case as if it were (exp1 === exp2).
// We analyze the body of the case when the test is true and the stm
// following the body when the test is false.
resultPair = analyzeStrictComparisonFwd(Token.SHEQ, expr.getParent().getFirstChild(), expr.getFirstChild(), inEnv, specializedType);
break;
case TEMPLATELIT:
resultPair = analyzeTemplateLitFwd(expr, inEnv);
break;
case TEMPLATELIT_SUB:
resultPair = analyzeExprFwd(expr.getFirstChild(), inEnv, requiredType);
break;
case STRING_KEY:
if (expr.hasChildren()) {
resultPair = analyzeExprFwd(expr.getFirstChild(), inEnv, requiredType, specializedType);
} else {
resultPair = analyzeNameFwd(expr, inEnv, requiredType, specializedType);
}
break;
case MEMBER_FUNCTION_DEF:
resultPair = analyzeExprFwd(expr.getFirstChild(), inEnv, requiredType, specializedType);
break;
case COMPUTED_PROP:
resultPair = analyzeExprFwd(expr.getFirstChild(), inEnv, requiredType, specializedType);
resultPair = analyzeExprFwd(expr.getSecondChild(), resultPair.env, requiredType, specializedType);
break;
case YIELD:
resultPair = analyzeYieldFwd(expr, inEnv);
break;
default:
throw new RuntimeException("Unhandled expression type: " + expr.getToken());
}
JSType resultType = resultPair.type;
mayWarnAboutUnknownType(expr, resultType);
if (resultType.isUnresolved()) {
resultPair.type = UNKNOWN;
}
maybeSetTypeI(expr, resultType);
if (this.currentScope.isFunction()) {
// In global scope, the env is too big and produces too much output
println("AnalyzeExprFWD: ", expr, " ::reqtype: ", requiredType, " ::spectype: ", specializedType, " ::resulttype: ", resultType);
}
return resultPair;
}
Aggregations