use of com.google.javascript.jscomp.CodingConvention.AssertionFunctionSpec in project closure-compiler by google.
the class TypeInference method tightenTypesAfterAssertions.
private FlowScope tightenTypesAfterAssertions(FlowScope scope, Node callNode) {
Node left = callNode.getFirstChild();
Node firstParam = left.getNext();
AssertionFunctionSpec assertionFunctionSpec = assertionFunctionsMap.get(left.getQualifiedName());
if (assertionFunctionSpec == null || firstParam == null) {
return scope;
}
Node assertedNode = assertionFunctionSpec.getAssertedParam(firstParam);
if (assertedNode == null) {
return scope;
}
JSType assertedType = assertionFunctionSpec.getAssertedOldType(callNode, registry);
String assertedNodeName = assertedNode.getQualifiedName();
JSType narrowed;
// Handle assertions that enforce expressions evaluate to true.
if (assertedType == null) {
// Handle arbitrary expressions within the assert.
scope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome(assertedNode, scope, true);
// Build the result of the assertExpression
narrowed = getJSType(assertedNode).restrictByNotNullOrUndefined();
} else {
// Handle assertions that enforce expressions are of a certain type.
JSType type = getJSType(assertedNode);
if (assertedType.isUnknownType() || type.isUnknownType()) {
narrowed = assertedType;
} else {
narrowed = type.getGreatestSubtype(assertedType);
}
if (assertedNodeName != null && type.differsFrom(narrowed)) {
scope = narrowScope(scope, assertedNode, narrowed);
}
}
callNode.setJSType(narrowed);
return scope;
}
use of com.google.javascript.jscomp.CodingConvention.AssertionFunctionSpec in project closure-compiler by google.
the class NewTypeInference method analyzeInvocationFwd.
private EnvTypePair analyzeInvocationFwd(Node expr, TypeEnv inEnv, JSType requiredType, JSType specializedType) {
if (isPropertyTestCall(expr)) {
return analyzePropertyTestCallFwd(expr, inEnv, specializedType);
}
if (expr.isCall() && this.convention.getObjectLiteralCast(expr) != null) {
return analyzeObjLitCastFwd(this.convention.getObjectLiteralCast(expr), expr, inEnv);
}
Node callee = expr.getFirstChild();
if (isFunctionBind(callee, inEnv, true)) {
return analyzeFunctionBindFwd(expr, inEnv);
}
AssertionFunctionSpec assertionFunctionSpec = assertionFunctionsMap.get(callee.getQualifiedName());
if (assertionFunctionSpec != null) {
return analyzeAssertionCall(expr, inEnv, assertionFunctionSpec);
}
EnvTypePair calleePair = analyzeExprFwd(callee, inEnv, commonTypes.topFunction());
TypeEnv envAfterCallee = calleePair.env;
calleePair = mayWarnAboutNullableReferenceAndTighten(callee, calleePair.type, null, envAfterCallee);
JSType calleeType = calleePair.type;
if (calleeType.isBottom() || !calleeType.isSubtypeOf(commonTypes.topFunction())) {
warnings.add(JSError.make(expr, NOT_CALLABLE, calleeType.toString()));
}
FunctionType funType = calleeType.getFunTypeIfSingletonObj();
if (funType == null || funType.isTopFunction() || funType.isQmarkFunction()) {
return analyzeInvocationArgsFwdWhenError(expr, envAfterCallee);
} else if (funType.isLoose()) {
return analyzeLooseCallNodeFwd(expr, envAfterCallee, requiredType);
} else if (!isConstructorCall(expr) && funType.isSomeConstructorOrInterface() && (funType.getReturnType().isUnknown() || funType.getReturnType().isUndefined())) {
warnings.add(JSError.make(expr, CONSTRUCTOR_NOT_CALLABLE, funType.toString()));
return analyzeInvocationArgsFwdWhenError(expr, envAfterCallee);
} else if (expr.isNew()) {
if (!funType.isSomeConstructorOrInterface() || funType.isInterfaceDefinition()) {
// or as an arbitrarily nested property), don't warn.
if (callee.isQualifiedName()) {
String qnameRoot = QualifiedName.fromNode(callee).getLeftmostName();
if (!this.currentScope.isFormalParamInAnyAncestorScope(qnameRoot)) {
warnings.add(JSError.make(expr, NOT_A_CONSTRUCTOR, funType.toString()));
}
}
return analyzeInvocationArgsFwdWhenError(expr, envAfterCallee);
} else if (funType.isConstructorOfAbstractClass()) {
warnings.add(JSError.make(expr, CANNOT_INSTANTIATE_ABSTRACT_CLASS, funType.toString()));
return analyzeInvocationArgsFwdWhenError(expr, envAfterCallee);
}
} else if (expr.isTaggedTemplateLit()) {
funType = checkTaggedFunctionFirstParam(expr.getLastChild(), expr.getFirstChild(), funType);
}
if (!isInvocationArgCountCorrectAndWarn(funType, expr, callee)) {
return analyzeInvocationArgsFwdWhenError(expr, envAfterCallee);
}
// save for later
FunctionType originalFunType = funType;
if (funType.isGeneric()) {
Node receiver = callee.isGetProp() ? callee.getFirstChild() : null;
Node firstArg = expr.getSecondChild();
ImmutableMap<String, JSType> typeMap = calcTypeInstantiationFwd(expr, receiver, firstArg, funType, envAfterCallee);
funType = instantiateCalleeMaybeWithTTL(funType, typeMap);
callee.setTypeI(this.commonTypes.fromFunctionType(funType));
println("Instantiated function type: ", funType);
}
// argTypes collects types of actuals for deferred checks.
List<JSType> argTypes = new ArrayList<>();
Node invocationNode = expr.isTaggedTemplateLit() ? expr.getLastChild() : expr;
Iterable<Node> argIterable = NodeUtil.getInvocationArgsAsIterable(expr);
TypeEnv tmpEnv = analyzeInvocationArgumentsFwd(invocationNode, argIterable, funType, argTypes, envAfterCallee);
if (callee.isName()) {
String calleeName = callee.getString();
if (this.currentScope.isKnownFunction(calleeName) && !this.currentScope.isExternalFunction(calleeName)) {
// exactly using their summaries, and don't need deferred checks
if (this.currentScope.isLocalFunDef(calleeName)) {
tmpEnv = collectTypesForEscapedVarsFwd(callee, tmpEnv);
} else if (!originalFunType.isGeneric()) {
JSType expectedRetType = requiredType;
println("Updating deferred check with ret: ", expectedRetType, " and args: ", argTypes);
DeferredCheck dc;
if (funType.isSomeConstructorOrInterface()) {
dc = new DeferredCheck(expr, null, this.currentScope, this.currentScope.getScope(calleeName));
deferredChecks.put(expr, dc);
} else {
dc = deferredChecks.get(expr);
if (dc != null) {
dc.updateReturn(expectedRetType);
} else {
// The backward analysis of a function is skipped when all
// variables, including outer vars, are declared.
// So, we check that dc is null iff bwd was skipped.
Preconditions.checkState(!this.currentScope.hasUndeclaredFormalsOrOuters(), "No deferred check created in backward direction for %s", expr);
}
}
if (dc != null) {
dc.updateArgTypes(argTypes);
}
}
}
}
JSType retType = expr.isNew() ? funType.getThisType() : funType.getReturnType();
if (retType.isSubtypeOf(requiredType)) {
retType = retType.specialize(specializedType);
}
return new EnvTypePair(tmpEnv, retType);
}
Aggregations