Search in sources :

Example 26 with TypeEnv

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()));
}
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 27 with TypeEnv

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);
}
Also used : LinkedHashSet(java.util.LinkedHashSet) DiGraphEdge(com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv)

Example 28 with TypeEnv

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);
}
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 29 with TypeEnv

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);
}
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)

Example 30 with TypeEnv

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

Aggregations

TypeEnv (com.google.javascript.jscomp.newtypes.TypeEnv)35 DiGraphNode (com.google.javascript.jscomp.graph.DiGraph.DiGraphNode)30 Node (com.google.javascript.rhino.Node)30 JSType (com.google.javascript.jscomp.newtypes.JSType)28 DeclaredFunctionType (com.google.javascript.jscomp.newtypes.DeclaredFunctionType)9 FunctionType (com.google.javascript.jscomp.newtypes.FunctionType)7 QualifiedName (com.google.javascript.jscomp.newtypes.QualifiedName)7 FunctionTypeBuilder (com.google.javascript.jscomp.newtypes.FunctionTypeBuilder)4 DiGraphEdge (com.google.javascript.jscomp.graph.DiGraph.DiGraphEdge)2 ArrayList (java.util.ArrayList)2 LinkedHashSet (java.util.LinkedHashSet)2 AssertionFunctionSpec (com.google.javascript.jscomp.CodingConvention.AssertionFunctionSpec)1 Bind (com.google.javascript.jscomp.CodingConvention.Bind)1 JSDocInfo (com.google.javascript.rhino.JSDocInfo)1 Token (com.google.javascript.rhino.Token)1