Search in sources :

Example 11 with FunctionType

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()));
}
Also used : Bind(com.google.javascript.jscomp.CodingConvention.Bind) JSType(com.google.javascript.jscomp.newtypes.JSType) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) FunctionType(com.google.javascript.jscomp.newtypes.FunctionType) DeclaredFunctionType(com.google.javascript.jscomp.newtypes.DeclaredFunctionType) ArrayList(java.util.ArrayList) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv) FunctionTypeBuilder(com.google.javascript.jscomp.newtypes.FunctionTypeBuilder)

Example 12 with FunctionType

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);
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) FunctionType(com.google.javascript.jscomp.newtypes.FunctionType) DeclaredFunctionType(com.google.javascript.jscomp.newtypes.DeclaredFunctionType) QualifiedName(com.google.javascript.jscomp.newtypes.QualifiedName) JSDocInfo(com.google.javascript.rhino.JSDocInfo) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv)

Example 13 with FunctionType

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);
    }
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) DeclaredFunctionType(com.google.javascript.jscomp.newtypes.DeclaredFunctionType) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) FunctionType(com.google.javascript.jscomp.newtypes.FunctionType) DeclaredFunctionType(com.google.javascript.jscomp.newtypes.DeclaredFunctionType)

Example 14 with FunctionType

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());
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) NominalType(com.google.javascript.jscomp.newtypes.NominalType) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) FunctionType(com.google.javascript.jscomp.newtypes.FunctionType) DeclaredFunctionType(com.google.javascript.jscomp.newtypes.DeclaredFunctionType)

Example 15 with FunctionType

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);
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) FunctionType(com.google.javascript.jscomp.newtypes.FunctionType) DeclaredFunctionType(com.google.javascript.jscomp.newtypes.DeclaredFunctionType) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv) FunctionTypeBuilder(com.google.javascript.jscomp.newtypes.FunctionTypeBuilder)

Aggregations

DeclaredFunctionType (com.google.javascript.jscomp.newtypes.DeclaredFunctionType)17 FunctionType (com.google.javascript.jscomp.newtypes.FunctionType)17 JSType (com.google.javascript.jscomp.newtypes.JSType)16 Node (com.google.javascript.rhino.Node)13 DiGraphNode (com.google.javascript.jscomp.graph.DiGraph.DiGraphNode)11 TypeEnv (com.google.javascript.jscomp.newtypes.TypeEnv)7 QualifiedName (com.google.javascript.jscomp.newtypes.QualifiedName)5 FunctionTypeBuilder (com.google.javascript.jscomp.newtypes.FunctionTypeBuilder)2 NominalType (com.google.javascript.jscomp.newtypes.NominalType)2 JSDocInfo (com.google.javascript.rhino.JSDocInfo)2 ArrayList (java.util.ArrayList)2 AssertionFunctionSpec (com.google.javascript.jscomp.CodingConvention.AssertionFunctionSpec)1 Bind (com.google.javascript.jscomp.CodingConvention.Bind)1 ObjectLiteralCast (com.google.javascript.jscomp.CodingConvention.ObjectLiteralCast)1 Declaration (com.google.javascript.jscomp.newtypes.Declaration)1 EnumType (com.google.javascript.jscomp.newtypes.EnumType)1 FunctionNamespace (com.google.javascript.jscomp.newtypes.FunctionNamespace)1 Namespace (com.google.javascript.jscomp.newtypes.Namespace)1 RawNominalType (com.google.javascript.jscomp.newtypes.RawNominalType)1