use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method analyzeCastFwd.
private EnvTypePair analyzeCastFwd(Node expr, TypeEnv inEnv) {
Node insideCast = expr.getFirstChild();
EnvTypePair pair = analyzeExprFwd(insideCast, inEnv);
JSType fromType = pair.type;
JSType toType = (JSType) expr.getTypeI();
if (!fromType.isInterfaceInstance() && !toType.isInterfaceInstance() && !JSType.haveCommonSubtype(fromType, toType) && !fromType.hasTypeVariable() && // Allow casts from an empty object literal to any type
(!insideCast.isObjectLit() || insideCast.hasChildren())) {
JSError error = JSError.make(expr, INVALID_CAST, fromType.toString(), toType.toString());
registerMismatchAndWarn(error, fromType, toType);
} else {
registerImplicitUses(expr, fromType, toType);
}
insideCast.putProp(Node.TYPE_BEFORE_CAST, fromType);
insideCast.setTypeI(toType);
pair.type = toType;
return pair;
}
use of com.google.javascript.jscomp.newtypes.JSType 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);
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method initEdgeEnvsFwd.
// Initialize the type environments on the CFG edges before the FWD analysis.
private void initEdgeEnvsFwd(TypeEnv entryEnv) {
envs.clear();
// For function scopes, add the formal parameters and the free variables
// from outer scopes to the environment.
Set<String> nonLocals = new LinkedHashSet<>();
if (this.currentScope.hasThis()) {
nonLocals.add(THIS_ID);
}
if (this.currentScope.isFunction()) {
if (this.currentScope.getName() != null) {
nonLocals.add(this.currentScope.getName());
}
nonLocals.addAll(this.currentScope.getOuterVars());
nonLocals.addAll(this.currentScope.getFormals());
entryEnv = envPutType(entryEnv, RETVAL_ID, UNDEFINED);
} else {
nonLocals.addAll(this.currentScope.getExterns());
}
for (String name : nonLocals) {
JSType declType = this.currentScope.getDeclaredTypeOf(name);
JSType initType = declType;
if (initType == null) {
initType = envGetType(entryEnv, name);
} else if (this.areTypeVariablesUnknown) {
initType = initType.substituteGenericsWithUnknown();
}
println("Adding non-local ", name, " with decltype: ", declType, " and inittype: ", initType);
entryEnv = envPutType(entryEnv, name, initType);
}
// to the environment.
for (String local : this.currentScope.getLocals()) {
if (!this.currentScope.isFunctionNamespace(local)) {
entryEnv = envPutType(entryEnv, local, UNDEFINED);
}
}
for (String fnName : this.currentScope.getLocalFunDefs()) {
entryEnv = envPutType(entryEnv, fnName, getSummaryOfLocalFunDef(fnName));
}
println("Keeping env: ", entryEnv);
setOutEnv(this.cfg.getEntry(), entryEnv);
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method analyzePropLValFwd.
private LValueResultFwd analyzePropLValFwd(Node obj, QualifiedName pname, LValueResultFwd recvLvalue, JSType requiredType, boolean insideQualifiedName) {
checkArgument(pname.isIdentifier());
TypeEnv inEnv = recvLvalue.env;
JSType recvType = recvLvalue.type;
if (!recvType.isUnion() && !recvType.isSingletonObj()) {
// The lvalue is a subtype of TOP_OBJECT, but does not contain an object
// yet, eg, it is ?, truthy, or bottom.
recvType = TOP_OBJECT.withLoose();
}
Node propAccessNode = obj.getParent();
if (propAccessNode.isGetProp() && propAccessNode.getParent().isAssign() && mayWarnAboutPropCreation(pname, propAccessNode, recvType)) {
return new LValueResultFwd(inEnv, requiredType, null, null);
}
if (!insideQualifiedName && mayWarnAboutConstProp(propAccessNode, recvType, pname)) {
return new LValueResultFwd(inEnv, requiredType, null, null);
}
if (!recvType.hasProp(pname)) {
// name, or for assignment ops that won't create a new property.
if (insideQualifiedName || !propAccessNode.getParent().isAssign()) {
mayWarnAboutInexistentProp(propAccessNode, recvType, pname);
if (!recvType.isLoose()) {
return new LValueResultFwd(inEnv, requiredType, null, null);
}
}
if (recvType.isLoose()) {
// For loose objects, create the inner property if it doesn't exist.
recvType = recvType.withProperty(pname, UNKNOWN);
inEnv = updateLvalueTypeInEnv(inEnv, obj, recvLvalue.ptr, recvType);
}
}
if (propAccessNode.isGetElem()) {
mayWarnAboutStructPropAccess(obj, recvType);
} else if (propAccessNode.isGetProp()) {
mayWarnAboutDictPropAccess(obj, recvType);
}
QualifiedName setterPname = new QualifiedName(commonTypes.createSetterPropName(pname.getLeftmostName()));
if (recvType.hasProp(setterPname)) {
FunctionType funType = recvType.getProp(setterPname).getFunType();
checkNotNull(funType, "recvType=%s, setterPname=%s", recvType, setterPname);
JSType formalType = funType.getFormalType(0);
checkState(!formalType.isBottom());
return new LValueResultFwd(inEnv, formalType, formalType, null);
}
QualifiedName ptr = recvLvalue.ptr == null ? null : QualifiedName.join(recvLvalue.ptr, pname);
return recvType.mayHaveProp(pname) ? new LValueResultFwd(inEnv, recvType.getProp(pname), recvType.getDeclaredProp(pname), ptr) : new LValueResultFwd(inEnv, UNKNOWN, null, ptr);
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method analyzeGetElemBwd.
private EnvTypePair analyzeGetElemBwd(Node expr, TypeEnv outEnv, JSType requiredType) {
Node receiver = expr.getFirstChild();
Node index = expr.getLastChild();
JSType reqObjType = pickReqObjType(expr);
EnvTypePair pair = analyzeExprBwd(receiver, outEnv, reqObjType);
JSType recvType = pair.type;
JSType indexType = recvType.getIndexType();
if (indexType != null) {
indexType = firstNonBottom(indexType, UNKNOWN);
pair = analyzeExprBwd(index, pair.env, indexType);
pair.type = getIndexedTypeOrUnknown(recvType);
return pair;
}
if (index.isString()) {
return analyzePropAccessBwd(receiver, index.getString(), outEnv, requiredType);
}
pair = analyzeExprBwd(index, outEnv);
pair = analyzeExprBwd(receiver, pair.env, reqObjType);
pair.type = requiredType;
return pair;
}
Aggregations