use of com.google.javascript.jscomp.newtypes.FunctionType 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.FunctionType 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.FunctionType in project closure-compiler by google.
the class NewTypeInference method computeFnDeclaredTypeForCallback.
/**
* Given a scope whose root is an unannotated callback, finds a declared type for the callback
* using the types in the callback's context.
* Similar to GlobalTypeInfoCollector#computeFnDeclaredTypeFromCallee, but not similar enough
* to use the same code for both.
*/
private void computeFnDeclaredTypeForCallback(NTIScope scope) {
Node callback = scope.getRoot();
checkState(NodeUtil.isUnannotatedCallback(callback));
Node call = callback.getParent();
JSType calleeType = (JSType) call.getFirstChild().getTypeI();
if (calleeType == null) {
return;
}
FunctionType calleeFunType = calleeType.getFunType();
if (calleeFunType == null) {
return;
}
int argIndex = call.getIndexOfChild(callback) - 1;
JSType formalType = calleeFunType.getFormalType(argIndex);
if (formalType == null) {
return;
}
FunctionType ft = formalType.getFunType();
if (ft == null || ft.isLoose()) {
return;
}
DeclaredFunctionType callbackDft = scope.getDeclaredFunctionType();
JSType scopeType = this.commonTypes.fromFunctionType(callbackDft.toFunctionType());
if (ft.isUniqueConstructor() || ft.isInterfaceDefinition()) {
warnAboutInvalidArgument(call, callback, argIndex, formalType, scopeType);
return;
}
DeclaredFunctionType declaredDft = checkNotNull(ft.toDeclaredFunctionType());
// the arity of the callback.
if (ft.acceptsAnyArguments() || callbackDft.getRequiredArity() <= declaredDft.getMaxArity()) {
scope.setDeclaredType(declaredDft);
} else {
warnAboutInvalidArgument(call, callback, argIndex, formalType, scopeType);
}
}
use of com.google.javascript.jscomp.newtypes.FunctionType in project closure-compiler by google.
the class NewTypeInference method analyzeSuperFwd.
private EnvTypePair analyzeSuperFwd(Node expr, TypeEnv inEnv) {
checkArgument(expr.isSuper());
if (this.currentScope.hasThis()) {
NominalType thisClass = checkNotNull(envGetType(inEnv, THIS_ID).getNominalTypeIfSingletonObj());
NominalType superClass = thisClass.getInstantiatedSuperclass();
if (superClass == null) {
// This indicates bad code and there will probably be other errors reported.
// In particular JSC_NTI_INHERITANCE_CYCLE for `class Foo extends Foo ...`.
warnings.add(JSError.make(expr, UNDEFINED_SUPER_CLASS, thisClass.toString()));
return new EnvTypePair(inEnv, UNKNOWN);
}
if (this.currentScope.isConstructor()) {
JSType superCtor = commonTypes.fromFunctionType(superClass.getConstructorFunction());
return new EnvTypePair(inEnv, superCtor);
}
return new EnvTypePair(inEnv, superClass.getInstanceAsJSType());
}
// Use of super in a static method.
Node funName = NodeUtil.getBestLValue(this.currentScope.getRoot());
Node classNameNode = funName.getFirstChild();
JSType thisClassAsJstype = analyzeExprFwd(classNameNode, inEnv).type;
FunctionType thisCtor = thisClassAsJstype.getFunTypeIfSingletonObj();
NominalType thisClass = thisCtor.getThisType().getNominalTypeIfSingletonObj();
NominalType superClass = thisClass.getInstantiatedSuperclass();
if (superClass == null) {
// This indicates bad code and there will probably be other errors reported.
// In particular JSC_NTI_INHERITANCE_CYCLE for `class Foo extends Foo ...`.
warnings.add(JSError.make(expr, UNDEFINED_SUPER_CLASS, funName.toString()));
return new EnvTypePair(inEnv, UNKNOWN);
}
return new EnvTypePair(inEnv, superClass.getNamespaceType());
}
use of com.google.javascript.jscomp.newtypes.FunctionType 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);
}
Aggregations