use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method getSummaryOfLocalFunDef.
private JSType getSummaryOfLocalFunDef(String name) {
NTIScope fnScope = this.currentScope.getScope(name);
JSType fnType = summaries.get(fnScope);
if (fnType != null) {
return fnType;
}
// Functions defined in externs have no summary, so use the declared type
fnType = this.currentScope.getDeclaredTypeOf(name);
if (fnType.getFunType() == null) {
// Can happen when a function defined in externs clashes with a variable
// defined by a catch block.
// TODO(dimvar): once we fix scoping for catch blocks, uncomment the
// precondition below.
checkState(fnType.isUnknown());
return this.commonTypes.qmarkFunction();
// Preconditions.checkState(fnType.getFunType() != null,
// "Needed function but found %s", fnType);
}
return changeTypeIfFunctionNamespace(fnScope, fnType);
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method analyzePropAccessFwd.
private EnvTypePair analyzePropAccessFwd(Node receiver, String pname, TypeEnv inEnv, JSType requiredType, JSType specializedType) {
QualifiedName propQname = new QualifiedName(pname);
Node propAccessNode = receiver.getParent();
EnvTypePair pair;
JSType reqObjType = pickReqObjType(propAccessNode);
JSType recvReqType;
JSType recvSpecType;
// First, analyze the receiver object.
if ((NodeUtil.isPropertyTest(compiler, propAccessNode) && !specializedType.isFalseOrFalsy()) || (NodeUtil.isPropertyAbsenceTest(propAccessNode) && !specializedType.isTrueOrTruthy()) || // else branch of "if (!x.prop)" is a property test.
specializedType.isTrueOrTruthy()) {
recvReqType = reqObjType;
pair = analyzeExprFwd(receiver, inEnv, recvReqType);
JSType subtypeWithProp = pair.type.findSubtypeWithProp(propQname);
if (subtypeWithProp.isBottom()) {
recvSpecType = reqObjType;
} else {
recvSpecType = subtypeWithProp;
}
if (specializedType.isTrueOrTruthy()) {
// This handles cases like: if (x.prop1 && x.prop1.prop2) { ... }
// In the THEN branch, the only thing we know about x.prop1 is that it
// has a truthy property, so x.prop1 should be a loose object to avoid
// spurious warnings.
recvSpecType = recvSpecType.withLoose().withProperty(propQname, specializedType);
} else {
recvSpecType = recvSpecType.withProperty(propQname, specializedType);
}
} else if (specializedType.isFalseOrFalsy()) {
recvReqType = recvSpecType = reqObjType;
} else {
recvReqType = reqObjType.withProperty(propQname, requiredType);
recvSpecType = reqObjType.withProperty(propQname, specializedType);
}
pair = analyzeExprFwd(receiver, inEnv, recvReqType, recvSpecType);
pair = mayWarnAboutNullableReferenceAndTighten(receiver, pair.type, recvSpecType, pair.env);
JSType recvType = pair.type.autobox();
if (recvType.isUnknown() || recvType.isTrueOrTruthy()) {
mayWarnAboutInexistentProp(propAccessNode, recvType, propQname);
return new EnvTypePair(pair.env, requiredType);
}
if (mayWarnAboutNonObject(receiver, recvType, specializedType)) {
return new EnvTypePair(pair.env, requiredType);
}
FunctionType ft = recvType.getFunTypeIfSingletonObj();
if (ft != null && (pname.equals("call") || pname.equals("apply"))) {
if (ft.isAbstract()) {
// We don't check if the parent of the property access is a call node.
// This catches calls that are a few nodes away, and also warns on .call/.apply
// accesses that do not result in calls (these should be very rare).
String funName = receiver.isQualifiedName() ? receiver.getQualifiedName() : "";
warnings.add(JSError.make(propAccessNode, ABSTRACT_SUPER_METHOD_NOT_CALLABLE, funName));
}
return new EnvTypePair(pair.env, pname.equals("call") ? commonTypes.fromFunctionType(ft.transformByCallProperty()) : commonTypes.fromFunctionType(ft.transformByApplyProperty()));
}
if (this.convention.isSuperClassReference(pname)) {
if (ft != null && ft.isUniqueConstructor()) {
JSType result = ft.getSuperPrototype();
pair.type = firstNonNull(result, UNDEFINED);
return pair;
}
}
if (propAccessNode.isGetProp() && mayWarnAboutDictPropAccess(receiver, recvType)) {
return new EnvTypePair(pair.env, requiredType);
}
if (recvType.isTop()) {
recvType = TOP_OBJECT;
}
if (propAccessNode.getParent().isDelProp() && recvType.hasConstantProp(propQname)) {
warnings.add(JSError.make(propAccessNode.getParent(), CONST_PROPERTY_DELETED, pname));
}
// Then, analyze the property access.
QualifiedName getterPname = new QualifiedName(commonTypes.createGetterPropName(pname));
if (recvType.hasProp(getterPname)) {
return new EnvTypePair(pair.env, recvType.getProp(getterPname));
}
JSType resultType = recvType.getProp(propQname);
if (resultType != null && resultType.isBottom()) {
warnings.add(JSError.make(propAccessNode, BOTTOM_PROP, pname, recvType.toString()));
return new EnvTypePair(pair.env, UNKNOWN);
}
if (!propAccessNode.getParent().isExprResult() && !specializedType.isTrueOrTruthy() && !specializedType.isFalseOrFalsy() && !recvType.mayBeDict() && !mayWarnAboutInexistentProp(propAccessNode, recvType, propQname) && recvType.hasProp(propQname) && !resultType.isSubtypeOf(requiredType) && tightenPropertyTypeAndDontWarn(receiver.isName() ? receiver.getString() : null, propAccessNode, recvType, recvType.getDeclaredProp(propQname), resultType, requiredType)) {
// Tighten the inferred type and don't warn.
// See analyzeNameFwd for explanation about types as lower/upper bounds.
resultType = resultType.specialize(requiredType);
LValueResultFwd lvr = analyzeLValueFwd(propAccessNode, inEnv, resultType);
TypeEnv updatedEnv = updateLvalueTypeInEnv(lvr.env, propAccessNode, lvr.ptr, resultType);
return new EnvTypePair(updatedEnv, resultType);
}
// We've already warned about missing props, and never want to return null.
if (resultType == null) {
resultType = UNKNOWN;
}
// Any potential type mismatch will be caught by the context
return new EnvTypePair(pair.env, resultType);
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method analyzeFunction.
private void analyzeFunction(NTIScope scope) {
println("=== Analyzing function: ", scope.getReadableName(), " ===");
currentScope = scope;
exitEnvs = new ArrayList<>();
Node scopeRoot = scope.getRoot();
if (NodeUtil.isUnannotatedCallback(scopeRoot)) {
computeFnDeclaredTypeForCallback(scope);
}
ControlFlowAnalysis cfa = new ControlFlowAnalysis(compiler, false, false);
cfa.process(null, scopeRoot);
this.cfg = cfa.getCfg();
println(this.cfg);
// The size is > 1 when multiple files are compiled
// Preconditions.checkState(cfg.getEntry().getOutEdges().size() == 1);
NTIWorkset workset = NTIWorkset.create(this.cfg);
this.typeEnvFromDeclaredTypes = getTypeEnvFromDeclaredTypes();
if (scope.isFunction() && scope.hasUndeclaredFormalsOrOuters()) {
// correctly waits for all incoming edges).
for (DiGraphEdge<Node, ControlFlowGraph.Branch> e : this.cfg.getEdges()) {
envs.put(e, this.typeEnvFromDeclaredTypes);
}
analyzeFunctionBwd(workset);
// TODO(dimvar): Revisit what we throw away after the bwd analysis
TypeEnv entryEnv = getEntryTypeEnv();
// Gives better results than starting them at unknown.
for (String varName : scope.getOuterVars()) {
JSType inferred = scope.getInferredTypeOf(varName);
if (inferred != null) {
entryEnv = envPutType(entryEnv, varName, inferred);
}
}
initEdgeEnvsFwd(entryEnv);
if (measureMem) {
updatePeakMem();
}
} else {
TypeEnv entryEnv = this.typeEnvFromDeclaredTypes;
initEdgeEnvsFwd(entryEnv);
}
this.typeEnvFromDeclaredTypes = null;
analyzeFunctionFwd(workset);
if (scope.isFunction()) {
createSummary(scope);
}
if (measureMem) {
updatePeakMem();
}
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method analyzeInstanceofFwd.
private EnvTypePair analyzeInstanceofFwd(Node expr, TypeEnv inEnv, JSType specializedType) {
Node obj = expr.getFirstChild();
Node ctor = expr.getLastChild();
EnvTypePair objPair;
EnvTypePair ctorPair;
// First, evaluate ignoring the specialized context
objPair = analyzeExprFwd(obj, inEnv);
JSType objType = objPair.type;
if (!objType.isTop() && !objType.isUnknown() && !objType.isTrueOrTruthy() && !objType.hasNonScalar() && !objType.hasTypeVariable()) {
warnInvalidOperand(obj, Token.INSTANCEOF, "an object or a union type that includes an object", objPair.type);
}
ctorPair = analyzeExprFwd(ctor, objPair.env, commonTypes.topFunction());
JSType ctorType = ctorPair.type;
FunctionType ctorFunType = ctorType.getFunType();
boolean mayBeConstructorFunction = ctorFunType != null && (ctorFunType.isLoose() || ctorFunType.isQmarkFunction() || ctorFunType.isSomeConstructorOrInterface());
if (!(ctorType.isUnknown() || mayBeConstructorFunction)) {
warnInvalidOperand(ctor, Token.INSTANCEOF, "a constructor function", ctorType);
}
if (ctorFunType == null || !ctorFunType.isUniqueConstructor() || (!specializedType.isTrueOrTruthy() && !specializedType.isFalseOrFalsy())) {
ctorPair.type = BOOLEAN;
return ctorPair;
}
// We are in a specialized context *and* we know the constructor type
JSType instanceType = ctorFunType.getInstanceTypeOfCtor();
JSType instanceSpecType;
if (specializedType.isTrueOrTruthy()) {
instanceSpecType = objType.specialize(instanceType);
} else if (objType.isTop()) {
instanceSpecType = objType;
} else {
instanceSpecType = objType.removeType(instanceType);
}
if (!instanceSpecType.isBottom()) {
objPair = analyzeExprFwd(obj, inEnv, UNKNOWN, instanceSpecType);
ctorPair = analyzeExprFwd(ctor, objPair.env, commonTypes.topFunction());
}
ctorPair.type = BOOLEAN;
return ctorPair;
}
use of com.google.javascript.jscomp.newtypes.JSType in project closure-compiler by google.
the class NewTypeInference method analyzeObjLitBwd.
private EnvTypePair analyzeObjLitBwd(Node objLit, TypeEnv outEnv, JSType requiredType) {
if (NodeUtil.isEnumDecl(objLit.getParent())) {
return analyzeEnumObjLitBwd(objLit, outEnv, requiredType);
}
TypeEnv env = outEnv;
JSType result = pickReqObjType(objLit);
for (Node prop = objLit.getLastChild(); prop != null; prop = prop.getPrevious()) {
if (prop.isGetterDef() || prop.isSetterDef()) {
env = analyzeExprBwd(prop.getFirstChild(), env).env;
} else if (prop.isComputedProp() && !prop.getFirstChild().isString()) {
env = analyzeExprBwd(prop, env).env;
} else {
QualifiedName pname = new QualifiedName(NodeUtil.getObjectLitKeyName(prop));
JSType jsdocType = (JSType) prop.getTypeI();
JSType reqPtype;
if (jsdocType != null) {
reqPtype = jsdocType;
} else if (requiredType.mayHaveProp(pname)) {
reqPtype = requiredType.getProp(pname);
} else {
reqPtype = UNKNOWN;
}
EnvTypePair pair = analyzeExprBwd(prop, env, reqPtype);
result = result.withProperty(pname, pair.type);
env = pair.env;
}
}
return new EnvTypePair(env, result);
}
Aggregations