use of com.google.javascript.jscomp.newtypes.TypeEnv in project closure-compiler by google.
the class NewTypeInference method analyzeFunctionBindFwd.
private EnvTypePair analyzeFunctionBindFwd(Node call, TypeEnv inEnv) {
checkArgument(call.isCall());
Bind bindComponents = this.convention.describeFunctionBind(call, true, false);
Node boundFunNode = bindComponents.target;
EnvTypePair pair = analyzeExprFwd(boundFunNode, inEnv);
TypeEnv env = pair.env;
FunctionType boundFunType = pair.type.getFunTypeIfSingletonObj();
if (!pair.type.isSubtypeOf(commonTypes.topFunction())) {
warnings.add(JSError.make(boundFunNode, GOOG_BIND_EXPECTS_FUNCTION, pair.type.toString()));
}
// For some function types, we don't know enough to handle .bind specially.
if (boundFunType == null || boundFunType.isTopFunction() || boundFunType.isQmarkFunction() || boundFunType.isLoose()) {
return analyzeInvocationArgsFwdWhenError(call, env);
}
if (boundFunType.isSomeConstructorOrInterface()) {
warnings.add(JSError.make(call, CANNOT_BIND_CTOR));
return new EnvTypePair(env, UNKNOWN);
}
// Check if the receiver argument is there
int callChildCount = call.getChildCount();
if ((NodeUtil.isGoogBind(call.getFirstChild()) && callChildCount <= 2) || (!NodeUtil.isGoogPartial(call.getFirstChild()) && callChildCount == 1)) {
warnings.add(JSError.make(call, WRONG_ARGUMENT_COUNT, getReadableCalleeName(call.getFirstChild()), "0", "1", ""));
}
// Check that there are not too many of the other arguments
int maxArity = boundFunType.hasRestFormals() ? Integer.MAX_VALUE : boundFunType.getMaxArity();
int numArgs = bindComponents.getBoundParameterCount();
if (numArgs > maxArity) {
warnings.add(JSError.make(call, WRONG_ARGUMENT_COUNT, getReadableCalleeName(call.getFirstChild()), Integer.toString(numArgs), "0", " and at most " + maxArity));
return analyzeInvocationArgsFwdWhenError(call, inEnv);
}
// If the bound function is polymorphic, we only support the case where we
// can completely calculate the type instantiation at the .bind call site.
// We don't support splitting the instantiation between call sites.
//
Node receiver = bindComponents.thisValue;
if (boundFunType.isGeneric()) {
Map<String, JSType> typeMap = calcTypeInstantiationFwd(call, receiver, bindComponents.parameters, boundFunType, env);
boundFunType = boundFunType.instantiateGenerics(typeMap);
}
FunctionTypeBuilder builder = new FunctionTypeBuilder(this.commonTypes);
if (receiver != null) {
// receiver is null for goog.partial
JSType reqThisType = boundFunType.getThisType();
if (reqThisType == null || boundFunType.isSomeConstructorOrInterface()) {
reqThisType = JSType.join(NULL, TOP_OBJECT);
}
pair = analyzeExprFwd(receiver, env, reqThisType);
env = pair.env;
if (!pair.type.isSubtypeOf(reqThisType)) {
warnings.add(JSError.make(call, INVALID_THIS_TYPE_IN_BIND, errorMsgWithTypeDiff(reqThisType, pair.type)));
} else {
instantiateGoogBind(call.getFirstChild(), pair.type);
}
}
Iterable<Node> parametersIterable = bindComponents.parameters == null ? ImmutableList.<Node>of() : bindComponents.parameters.siblings();
// We are passing an arraylist but don't do deferred checks for bind.
env = analyzeInvocationArgumentsFwd(call, parametersIterable, boundFunType, new ArrayList<JSType>(), env);
// For any formal not bound here, add it to the resulting function type.
for (int j = numArgs; j < boundFunType.getMaxArityWithoutRestFormals(); j++) {
JSType formalType = boundFunType.getFormalType(j);
if (boundFunType.isRequiredArg(j)) {
builder.addReqFormal(formalType);
} else {
builder.addOptFormal(formalType);
}
}
if (boundFunType.hasRestFormals()) {
builder.addRestFormals(boundFunType.getRestFormalsType());
}
return new EnvTypePair(env, commonTypes.fromFunctionType(builder.addRetType(boundFunType.getReturnType()).buildFunction()));
}
use of com.google.javascript.jscomp.newtypes.TypeEnv in project closure-compiler by google.
the class NewTypeInference method getInEnv.
private TypeEnv getInEnv(DiGraphNode<Node, ControlFlowGraph.Branch> dn) {
List<DiGraphEdge<Node, ControlFlowGraph.Branch>> inEdges = dn.getInEdges();
// True for code considered dead in the CFG
if (inEdges.isEmpty()) {
return getEntryTypeEnv();
}
if (inEdges.size() == 1) {
return envs.get(inEdges.get(0));
}
Set<TypeEnv> envSet = new LinkedHashSet<>();
for (DiGraphEdge<Node, ControlFlowGraph.Branch> de : inEdges) {
TypeEnv env = envs.get(de);
if (env != null) {
envSet.add(env);
}
}
if (envSet.isEmpty()) {
return null;
}
return TypeEnv.join(envSet);
}
use of com.google.javascript.jscomp.newtypes.TypeEnv in project closure-compiler by google.
the class NewTypeInference method analyzeObjLitFwd.
private EnvTypePair analyzeObjLitFwd(Node objLit, TypeEnv inEnv, JSType requiredType, JSType specializedType) {
if (NodeUtil.isEnumDecl(objLit.getParent())) {
return analyzeEnumObjLitFwd(objLit, inEnv, requiredType);
}
JSDocInfo jsdoc = objLit.getJSDocInfo();
boolean isStruct = jsdoc != null && jsdoc.makesStructs();
boolean isDict = jsdoc != null && jsdoc.makesDicts();
TypeEnv env = inEnv;
JSType result = pickReqObjType(objLit);
for (Node prop : objLit.children()) {
if (isStruct && prop.isQuotedString()) {
warnings.add(JSError.make(prop, ILLEGAL_OBJLIT_KEY, "struct"));
} else if (isDict && !prop.isQuotedString()) {
warnings.add(JSError.make(prop, ILLEGAL_OBJLIT_KEY, "dict"));
}
// an accidental clash.
if (prop.isGetterDef() || prop.isSetterDef()) {
String pname = NodeUtil.getObjectLitKeyName(prop);
EnvTypePair pair = analyzeExprFwd(prop.getFirstChild(), env);
FunctionType funType = pair.type.getFunType();
checkNotNull(funType);
String specialPropName;
JSType propType;
if (prop.isGetterDef()) {
specialPropName = commonTypes.createGetterPropName(pname);
propType = funType.getReturnType();
} else {
specialPropName = commonTypes.createSetterPropName(pname);
propType = pair.type;
}
result = result.withProperty(new QualifiedName(specialPropName), propType);
env = pair.env;
} else {
Node pnameNode = NodeUtil.getObjectLitKeyNode(prop);
if (pnameNode == null) {
// pnameNode is null when prop is a computed prop does not have a String node key.
// Just type-check the prop, then move on to the next property.
env = analyzeExprFwd(prop, env).env;
continue;
}
QualifiedName qname = new QualifiedName(pnameNode.getString());
JSType jsdocType = (JSType) prop.getTypeI();
JSType reqPtype;
JSType specPtype;
if (jsdocType != null) {
reqPtype = specPtype = jsdocType;
} else if (requiredType.mayHaveProp(qname)) {
reqPtype = specPtype = requiredType.getProp(qname);
if (specializedType.mayHaveProp(qname)) {
specPtype = specializedType.getProp(qname);
}
} else {
reqPtype = specPtype = UNKNOWN;
}
EnvTypePair pair = analyzeExprFwd(prop, env, reqPtype, specPtype);
if (jsdocType != null) {
// First declare it; then set the maybe more precise inferred type
result = result.withDeclaredProperty(qname, jsdocType, false);
if (!pair.type.isSubtypeOf(jsdocType)) {
warnings.add(JSError.make(prop, INVALID_OBJLIT_PROPERTY_TYPE, errorMsgWithTypeDiff(jsdocType, pair.type)));
pair.type = jsdocType;
}
}
result = result.withProperty(qname, pair.type);
env = pair.env;
}
}
result = mayAdjustObjLitType(objLit, jsdoc, inEnv, result);
return new EnvTypePair(env, result);
}
use of com.google.javascript.jscomp.newtypes.TypeEnv in project closure-compiler by google.
the class NewTypeInference method analyzeLooseCallNodeFwd.
private EnvTypePair analyzeLooseCallNodeFwd(Node callNode, TypeEnv inEnv, JSType requiredType) {
checkArgument(callNode.isCall() || callNode.isNew());
Node callee = callNode.getFirstChild();
FunctionTypeBuilder builder = new FunctionTypeBuilder(this.commonTypes);
TypeEnv tmpEnv = inEnv;
for (Node arg = callee.getNext(); arg != null; arg = arg.getNext()) {
EnvTypePair pair = analyzeExprFwd(arg, tmpEnv);
tmpEnv = pair.env;
builder.addReqFormal(pair.type);
}
JSType looseRetType = requiredType.isUnknown() ? BOTTOM : requiredType;
JSType looseFunctionType = commonTypes.fromFunctionType(builder.addRetType(looseRetType).addLoose().buildFunction());
// Unsound if the arguments and callee have interacting side effects
EnvTypePair calleePair = analyzeExprFwd(callee, tmpEnv, commonTypes.topFunction(), looseFunctionType);
FunctionType calleeType = calleePair.type.getFunType();
JSType result = calleeType.getReturnType();
return new EnvTypePair(calleePair.env, isImpreciseType(result) ? requiredType : result);
}
use of com.google.javascript.jscomp.newtypes.TypeEnv in project closure-compiler by google.
the class NewTypeInference method analyzeForOfFwd.
private TypeEnv analyzeForOfFwd(Node n, TypeEnv inEnv) {
Node rhs = n.getSecondChild();
EnvTypePair rhsPair = analyzeExprFwd(rhs, inEnv, pickReqObjType(n));
rhsPair = mayWarnAboutNullableReferenceAndTighten(n, rhsPair.type, null, inEnv);
JSType rhsObjType = rhsPair.type;
JSType boxedType = rhsObjType.autobox();
JSType lhsExpectedType;
JSType iterable = this.commonTypes.getIterableInstance(UNKNOWN);
if (boxedType.isSubtypeOf(iterable)) {
lhsExpectedType = boxedType.getInstantiatedTypeArgument(iterable);
} else {
warnings.add(JSError.make(rhs, FOROF_EXPECTS_ITERABLE, rhsObjType.toString()));
lhsExpectedType = UNKNOWN;
}
Node lhsNode = n.getFirstChild();
LValueResultFwd lhsLval = analyzeLValueFwd(lhsNode, inEnv, lhsExpectedType);
TypeEnv outEnv;
if (lhsLval.declType == null || lhsExpectedType.isSubtypeOf(lhsLval.declType)) {
outEnv = updateLvalueTypeInEnv(lhsLval.env, lhsNode, lhsLval.ptr, lhsExpectedType);
} else {
registerMismatchAndWarn(JSError.make(n, MISTYPED_FOROF_ELEMENT_TYPE, errorMsgWithTypeDiff(lhsLval.declType, lhsExpectedType)), lhsExpectedType, lhsLval.declType);
outEnv = updateLvalueTypeInEnv(lhsLval.env, lhsNode, lhsLval.ptr, lhsLval.declType);
}
return outEnv;
}
Aggregations