use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method analyzeNameFwd.
private EnvTypePair analyzeNameFwd(Node expr, TypeEnv inEnv, JSType requiredType, JSType specializedType) {
String varName = expr.getString();
if (varName.equals("undefined")) {
return new EnvTypePair(inEnv, UNDEFINED);
}
JSType inferredType = envGetType(inEnv, varName);
if (inferredType == null) {
println("Found global variable ", varName);
// For now, we don't warn for global variables
return new EnvTypePair(inEnv, UNKNOWN);
}
println(varName, "'s inferredType: ", inferredType, " requiredType: ", requiredType, " specializedType: ", specializedType);
if (!inferredType.isSubtypeOf(requiredType)) {
// The inferred type of a variable is always an upper bound, but
// sometimes it's also a lower bound, eg, if x was the lhs of an =
// where we know the type of the rhs.
// We don't track whether the inferred type is a lower bound, so we
// conservatively assume that it always is.
// This is why we warn when !inferredType.isSubtypeOf(requiredType).
// In some rare cases, the inferred type is only an upper bound,
// and we would falsely warn.
// (These usually include the polymorphic operators += and <.)
// We have a heuristic check to avoid the spurious warnings,
// but we also miss some true warnings.
JSType declType = this.currentScope.getDeclaredTypeOf(varName);
if (tightenNameTypeAndDontWarn(varName, expr, declType, inferredType, requiredType)) {
inferredType = inferredType.specialize(requiredType);
} else {
// the mismatch
return new EnvTypePair(inEnv, inferredType);
}
}
// If preciseType is bottom, there is a condition that can't be true,
// but that's not necessarily a type error.
JSType preciseType = inferredType.specialize(specializedType);
if (preciseType.isBottom()) {
preciseType = pickFallbackTypeAfterBottom(varName, inferredType, specializedType);
}
println(varName, "'s preciseType: ", preciseType);
if ((this.currentScope.isUndeclaredFormal(varName) || this.currentScope.isUndeclaredOuterVar(varName)) && preciseType.hasNonScalar()) {
// In the bwd direction, we may infer a loose type and then join w/
// top and forget it. That's why we also loosen types going fwd.
preciseType = preciseType.withLoose();
}
return EnvTypePair.addBinding(inEnv, varName, preciseType);
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method analyzeAssignFwd.
private EnvTypePair analyzeAssignFwd(Node expr, TypeEnv inEnv, JSType requiredType, JSType specializedType) {
if (expr.getBooleanProp(Node.ANALYZED_DURING_GTI)) {
expr.removeProp(Node.ANALYZED_DURING_GTI);
Node rhs = expr.getLastChild();
if (!rhs.isQualifiedName()) {
analyzeExprFwdIgnoreResult(rhs, inEnv);
}
// definitions, not just ones defining typedefs.
if (!NodeUtil.isAliasedConstDefinition(expr.getFirstChild())) {
markAndGetTypeOfPreanalyzedNode(expr.getFirstChild(), inEnv, true);
markAndGetTypeOfPreanalyzedNode(rhs, inEnv, true);
}
return new EnvTypePair(inEnv, requiredType);
}
mayWarnAboutConst(expr);
Node lhs = expr.getFirstChild();
Node rhs = expr.getLastChild();
if (lhs.getBooleanProp(Node.ANALYZED_DURING_GTI)) {
lhs.removeProp(Node.ANALYZED_DURING_GTI);
JSType declType = markAndGetTypeOfPreanalyzedNode(lhs, inEnv, true);
if (rhs.matchesQualifiedName(ABSTRACT_METHOD_NAME) || (GlobalTypeInfoCollector.isCtorDefinedByCall(lhs) && !isFunctionBind(rhs.getFirstChild(), inEnv, true))) {
return new EnvTypePair(inEnv, requiredType);
}
EnvTypePair rhsPair = analyzeExprFwd(rhs, inEnv, declType);
if (rhsPair.type.isSubtypeOf(declType)) {
registerImplicitUses(expr, rhsPair.type, declType);
} else if (!NodeUtil.isPrototypeAssignment(lhs)) {
registerMismatchAndWarn(JSError.make(expr, MISTYPED_ASSIGN_RHS, errorMsgWithTypeDiff(declType, rhsPair.type)), rhsPair.type, declType);
}
return rhsPair;
}
LValueResultFwd lvalue = analyzeLValueFwd(lhs, inEnv, requiredType);
JSType declType = lvalue.declType;
EnvTypePair rhsPair = analyzeExprFwd(rhs, lvalue.env, requiredType, specializedType);
if (declType == null) {
if (!isGlobalVariable(lhs, inEnv)) {
rhsPair.env = updateLvalueTypeInEnv(rhsPair.env, lhs, lvalue.ptr, rhsPair.type);
}
} else if (rhsPair.type.isSubtypeOf(declType)) {
registerImplicitUses(expr, rhsPair.type, declType);
rhsPair.env = updateLvalueTypeInEnv(rhsPair.env, lhs, lvalue.ptr, rhsPair.type);
} else {
registerMismatchAndWarn(JSError.make(expr, MISTYPED_ASSIGN_RHS, errorMsgWithTypeDiff(declType, rhsPair.type)), rhsPair.type, declType);
}
return rhsPair;
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method analyzeInvocationBwd.
private EnvTypePair analyzeInvocationBwd(Node expr, TypeEnv outEnv, JSType requiredType) {
checkArgument(expr.isNew() || expr.isCall() || expr.isTaggedTemplateLit());
Node callee = expr.getFirstChild();
EnvTypePair pair = analyzeExprBwd(callee, outEnv, commonTypes.topFunction());
TypeEnv envAfterCallee = pair.env;
FunctionType funType = pair.type.getFunType();
if (funType == null) {
return analyzeInvocationArgumentsBwd(expr, expr.getFirstChild(), envAfterCallee);
} else if (funType.isLoose()) {
return analyzeLooseCallNodeBwd(expr, envAfterCallee, requiredType);
} else if ((expr.isCall() && funType.isSomeConstructorOrInterface()) || (expr.isNew() && !funType.isSomeConstructorOrInterface())) {
return analyzeInvocationArgumentsBwd(expr, expr.getFirstChild(), envAfterCallee);
} else if (funType.isTopFunction()) {
return analyzeInvocationArgumentsBwd(expr, expr.getFirstChild(), envAfterCallee);
}
if (callee.isName() && !funType.isGeneric() && (expr.isCall() || expr.isTaggedTemplateLit())) {
createDeferredCheckBwd(expr, requiredType);
}
int numArgs = NodeUtil.getInvocationArgsCount(expr);
if (numArgs < funType.getMinArity() || numArgs > funType.getMaxArity()) {
if (expr.isTaggedTemplateLit()) {
return analyzeInvocationArgumentsBwd(expr.getLastChild(), null, envAfterCallee);
} else {
return analyzeInvocationArgumentsBwd(expr, expr.getFirstChild(), envAfterCallee);
}
}
if (funType.isGeneric()) {
Map<String, JSType> typeMap = calcTypeInstantiationBwd(expr, funType, envAfterCallee);
funType = funType.instantiateGenerics(typeMap);
}
TypeEnv tmpEnv = envAfterCallee;
// In bwd direction, analyze arguments in reverse
Node target = expr.isTaggedTemplateLit() ? null : expr.getFirstChild();
Node start = expr.isTaggedTemplateLit() ? expr.getLastChild().getLastChild() : expr.getLastChild();
int i = numArgs;
for (Node arg = start; arg != target; arg = arg.getPrevious()) {
if (expr.isTaggedTemplateLit() && !arg.isTemplateLitSub()) {
// with the formal types of the tag function, i needs to stay unchanged here.
continue;
}
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.
formalType = firstNonBottom(formalType, UNKNOWN);
tmpEnv = analyzeExprBwd(arg, tmpEnv, formalType).env;
// We don't need deferred checks for args in BWD
}
JSType retType = expr.isNew() ? funType.getThisType() : funType.getReturnType();
return new EnvTypePair(tmpEnv, retType);
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method analyzeAddFwd.
private EnvTypePair analyzeAddFwd(Node expr, TypeEnv inEnv, JSType requiredType) {
Node lhs = expr.getFirstChild();
Node rhs = expr.getLastChild();
JSType operandType = requiredType.isNumber() ? NUMBER : UNKNOWN;
EnvTypePair lhsPair = analyzeExprFwd(lhs, inEnv, operandType);
EnvTypePair rhsPair = analyzeExprFwd(rhs, lhsPair.env, operandType);
JSType lhsType = lhsPair.type;
JSType rhsType = rhsPair.type;
if (lhsType.isString() || rhsType.isString()) {
// Return early and don't warn, since '' + expr is used for type coercions
rhsPair.type = STRING;
return rhsPair;
}
if (!commonTypes.isNumStrScalarOrObj(lhsType)) {
warnInvalidOperand(lhs, expr.getToken(), NUMBER_OR_STRING, lhsType);
}
if (!commonTypes.isNumStrScalarOrObj(rhsType)) {
warnInvalidOperand(rhs, expr.getToken(), NUMBER_OR_STRING, rhsType);
}
return new EnvTypePair(rhsPair.env, JSType.plus(lhsType, rhsType));
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method mayWarnAboutNullableReferenceAndTighten.
private EnvTypePair mayWarnAboutNullableReferenceAndTighten(Node obj, JSType recvType, JSType maybeSpecType, TypeEnv inEnv) {
if (!recvType.isUnknown() && !recvType.isTop() && (NULL.isSubtypeOf(recvType) || UNDEFINED.isSubtypeOf(recvType))) {
JSType minusNull = recvType.removeType(NULL_OR_UNDEFINED);
if (!minusNull.isBottom()) {
if (this.reportNullDeref) {
warnings.add(JSError.make(obj, NULLABLE_DEREFERENCE, recvType.toString()));
}
TypeEnv outEnv = inEnv;
if (obj.isQualifiedName()) {
QualifiedName qname = QualifiedName.fromNode(obj);
if (maybeSpecType != null && maybeSpecType.isSubtypeOf(minusNull)) {
minusNull = maybeSpecType;
}
outEnv = updateLvalueTypeInEnv(inEnv, obj, qname, minusNull);
}
return new EnvTypePair(outEnv, minusNull);
}
}
return new EnvTypePair(inEnv, recvType);
}
Aggregations