Search in sources :

Example 31 with TypeEnv

use of com.google.javascript.jscomp.newtypes.TypeEnv in project closure-compiler by google.

the class NewTypeInference method analyzeInvocationArgumentsFwd.

private TypeEnv analyzeInvocationArgumentsFwd(Node n, Iterable<Node> args, FunctionType funType, List<JSType> argTypesForDeferredCheck, TypeEnv inEnv) {
    checkState(NodeUtil.isCallOrNew(n) || n.isTemplateLit());
    TypeEnv env = inEnv;
    int i = n.isTemplateLit() ? 1 : 0;
    for (Node arg : args) {
        JSType formalType = funType.getFormalType(i);
        checkState(!formalType.isBottom());
        EnvTypePair pair = analyzeExprFwd(arg, env, formalType);
        if (NodeUtil.isUnannotatedCallback(arg) && formalType.getFunType() != null) {
            i++;
            // No deferred check needed.
            argTypesForDeferredCheck.add(null);
            continue;
        }
        JSType argTypeForDeferredCheck = pair.type;
        // Allow passing undefined for an optional argument.
        if (funType.isOptionalArg(i) && pair.type.equals(UNDEFINED)) {
            // No deferred check needed.
            argTypeForDeferredCheck = null;
        } else if (!pair.type.isSubtypeOf(formalType)) {
            warnAboutInvalidArgument(n, arg, i, formalType, pair.type);
            // No deferred check needed.
            argTypeForDeferredCheck = null;
        } else {
            registerImplicitUses(arg, pair.type, formalType);
        }
        argTypesForDeferredCheck.add(argTypeForDeferredCheck);
        env = pair.env;
        i++;
    }
    return env;
}
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)

Example 32 with TypeEnv

use of com.google.javascript.jscomp.newtypes.TypeEnv in project closure-compiler by google.

the class NewTypeInference method analyzeFunctionFwd.

private void analyzeFunctionFwd(NTIWorkset workset) {
    for (DiGraphNode<Node, ControlFlowGraph.Branch> dn : workset.forward()) {
        Node n = dn.getValue();
        Node parent = n.getParent();
        checkState(n != null, "Implicit return should not be in workset.");
        TypeEnv inEnv = getInEnv(dn);
        TypeEnv outEnv = null;
        if (parent.isScript() || (parent.isNormalBlock() && parent.getParent().isFunction())) {
            // All joins have merged; forget changes
            inEnv = inEnv.clearChangeLog();
        }
        println("\tFWD Statment: ", n);
        println("\t\tinEnv: ", inEnv);
        boolean conditional = false;
        switch(n.getToken()) {
            case BLOCK:
            case ROOT:
            case BREAK:
            case CONTINUE:
            case DEFAULT_CASE:
            case DEBUGGER:
            case EMPTY:
            case FUNCTION:
            case SCRIPT:
            case TRY:
            case // We don't typecheck WITH, we just avoid crashing.
            WITH:
                outEnv = inEnv;
                break;
            case CATCH:
                Node catchVar = n.getFirstChild();
                String catchVarname = catchVar.getString();
                outEnv = envPutType(inEnv, catchVarname, UNKNOWN);
                maybeSetTypeI(catchVar, UNKNOWN);
                break;
            case EXPR_RESULT:
                println("\tsemi ", n.getFirstChild().getToken());
                if (n.getBooleanProp(Node.ANALYZED_DURING_GTI)) {
                    n.removeProp(Node.ANALYZED_DURING_GTI);
                    outEnv = inEnv;
                } else {
                    outEnv = analyzeExprFwd(n.getFirstChild(), inEnv, UNKNOWN).env;
                }
                break;
            case RETURN:
                outEnv = analyzeReturnFwd(n, inEnv);
                break;
            case DO:
            case IF:
            case FOR:
            case WHILE:
                conditional = true;
                analyzeConditionalStmFwd(dn, NodeUtil.getConditionExpression(n), inEnv);
                break;
            case FOR_IN:
                outEnv = analyzeForInFwd(n, inEnv);
                break;
            case FOR_OF:
                outEnv = analyzeForOfFwd(n, inEnv);
                break;
            case CASE:
                {
                    conditional = true;
                    // See analyzeExprFwd#Token.CASE for how to handle this precisely
                    analyzeConditionalStmFwd(dn, n, inEnv);
                    break;
                }
            case VAR:
                outEnv = inEnv;
                if (NodeUtil.isTypedefDecl(n)) {
                    maybeSetTypeI(n.getFirstChild(), UNDEFINED);
                    break;
                }
                for (Node nameNode : n.children()) {
                    outEnv = analyzeVarDeclFwd(nameNode, outEnv);
                }
                break;
            case SWITCH:
                outEnv = analyzeExprFwd(n.getFirstChild(), inEnv).env;
                break;
            case THROW:
                {
                    outEnv = analyzeExprFwd(n.getFirstChild(), inEnv).env;
                    exitEnvs.add(outEnv);
                    break;
                }
            default:
                if (NodeUtil.isStatement(n)) {
                    throw new RuntimeException("Unhandled statement type: " + n.getToken());
                } else {
                    outEnv = analyzeExprFwd(n, inEnv, UNKNOWN).env;
                    break;
                }
        }
        if (!conditional) {
            println("\t\toutEnv: ", outEnv);
            setOutEnv(dn, outEnv);
        }
    }
}
Also used : Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv)

Example 33 with TypeEnv

use of com.google.javascript.jscomp.newtypes.TypeEnv in project closure-compiler by google.

the class NewTypeInference method getTypeEnvFromDeclaredTypes.

private TypeEnv getTypeEnvFromDeclaredTypes() {
    TypeEnv env = new TypeEnv();
    Set<String> varNames = this.currentScope.getOuterVars();
    Set<String> locals = this.currentScope.getLocals();
    varNames.addAll(locals);
    varNames.addAll(this.currentScope.getExterns());
    if (this.currentScope.hasThis()) {
        varNames.add(THIS_ID);
    }
    if (this.currentScope.isFunction()) {
        Node fn = this.currentScope.getRoot();
        if (!this.currentScope.hasThis() && // a function.
        NodeUtil.containsType(fn.getLastChild(), Token.SUPER, NodeUtil.MATCH_NOT_FUNCTION)) {
            // This function is a static method on some class. To do lookups of the
            // class name, we add the root of the qualified name to the environment.
            Node funNameNode = NodeUtil.getBestLValue(fn);
            Node qnameRoot = NodeUtil.getRootOfQualifiedName(funNameNode);
            checkState(qnameRoot.isName());
            varNames.add(qnameRoot.getString());
        }
        if (this.currentScope.getName() != null) {
            varNames.add(this.currentScope.getName());
        }
        varNames.addAll(this.currentScope.getFormals());
        // In the rare case when there is a local variable named "arguments",
        // this entry will be overwritten in the foreach loop below.
        JSType argumentsType;
        DeclaredFunctionType dft = this.currentScope.getDeclaredTypeForOwnBody();
        if (dft.getOptionalArity() == 0 && dft.hasRestFormals()) {
            argumentsType = dft.getRestFormalsType();
        } else {
            argumentsType = UNKNOWN;
        }
        env = envPutType(env, "arguments", commonTypes.getArgumentsArrayType(argumentsType));
    }
    for (String varName : varNames) {
        if (!this.currentScope.isLocalFunDef(varName)) {
            JSType declType = this.currentScope.getDeclaredTypeOf(varName);
            if (declType == null) {
                declType = UNKNOWN;
            } else if (areTypeVariablesUnknown) {
                declType = declType.substituteGenericsWithUnknown();
            }
            env = envPutType(env, varName, declType);
        }
    }
    for (String fnName : this.currentScope.getLocalFunDefs()) {
        env = envPutType(env, fnName, getSummaryOfLocalFunDef(fnName));
    }
    return env;
}
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) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv)

Example 34 with TypeEnv

use of com.google.javascript.jscomp.newtypes.TypeEnv in project closure-compiler by google.

the class NewTypeInference method analyzeInvocationBwd.

private EnvTypePair analyzeInvocationBwd(Node expr, TypeEnv outEnv, JSType requiredType) {
    checkArgument(expr.isNew() || expr.isCall() || expr.isTaggedTemplateLit());
    Node callee = expr.getFirstChild();
    EnvTypePair pair = analyzeExprBwd(callee, outEnv, commonTypes.topFunction());
    TypeEnv envAfterCallee = pair.env;
    FunctionType funType = pair.type.getFunType();
    if (funType == null) {
        return analyzeInvocationArgumentsBwd(expr, expr.getFirstChild(), envAfterCallee);
    } else if (funType.isLoose()) {
        return analyzeLooseCallNodeBwd(expr, envAfterCallee, requiredType);
    } else if ((expr.isCall() && funType.isSomeConstructorOrInterface()) || (expr.isNew() && !funType.isSomeConstructorOrInterface())) {
        return analyzeInvocationArgumentsBwd(expr, expr.getFirstChild(), envAfterCallee);
    } else if (funType.isTopFunction()) {
        return analyzeInvocationArgumentsBwd(expr, expr.getFirstChild(), envAfterCallee);
    }
    if (callee.isName() && !funType.isGeneric() && (expr.isCall() || expr.isTaggedTemplateLit())) {
        createDeferredCheckBwd(expr, requiredType);
    }
    int numArgs = NodeUtil.getInvocationArgsCount(expr);
    if (numArgs < funType.getMinArity() || numArgs > funType.getMaxArity()) {
        if (expr.isTaggedTemplateLit()) {
            return analyzeInvocationArgumentsBwd(expr.getLastChild(), null, envAfterCallee);
        } else {
            return analyzeInvocationArgumentsBwd(expr, expr.getFirstChild(), envAfterCallee);
        }
    }
    if (funType.isGeneric()) {
        Map<String, JSType> typeMap = calcTypeInstantiationBwd(expr, funType, envAfterCallee);
        funType = funType.instantiateGenerics(typeMap);
    }
    TypeEnv tmpEnv = envAfterCallee;
    // In bwd direction, analyze arguments in reverse
    Node target = expr.isTaggedTemplateLit() ? null : expr.getFirstChild();
    Node start = expr.isTaggedTemplateLit() ? expr.getLastChild().getLastChild() : expr.getLastChild();
    int i = numArgs;
    for (Node arg = start; arg != target; arg = arg.getPrevious()) {
        if (expr.isTaggedTemplateLit() && !arg.isTemplateLitSub()) {
            // with the formal types of the tag function, i needs to stay unchanged here.
            continue;
        }
        i--;
        JSType formalType = funType.getFormalType(i);
        // The type of a formal can be BOTTOM as the result of a join.
        // Don't use this as a requiredType.
        formalType = firstNonBottom(formalType, UNKNOWN);
        tmpEnv = analyzeExprBwd(arg, tmpEnv, formalType).env;
    // We don't need deferred checks for args in BWD
    }
    JSType retType = expr.isNew() ? funType.getThisType() : funType.getReturnType();
    return new EnvTypePair(tmpEnv, retType);
}
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)

Example 35 with TypeEnv

use of com.google.javascript.jscomp.newtypes.TypeEnv in project closure-compiler by google.

the class NewTypeInference method mayWarnAboutNullableReferenceAndTighten.

private EnvTypePair mayWarnAboutNullableReferenceAndTighten(Node obj, JSType recvType, JSType maybeSpecType, TypeEnv inEnv) {
    if (!recvType.isUnknown() && !recvType.isTop() && (NULL.isSubtypeOf(recvType) || UNDEFINED.isSubtypeOf(recvType))) {
        JSType minusNull = recvType.removeType(NULL_OR_UNDEFINED);
        if (!minusNull.isBottom()) {
            if (this.reportNullDeref) {
                warnings.add(JSError.make(obj, NULLABLE_DEREFERENCE, recvType.toString()));
            }
            TypeEnv outEnv = inEnv;
            if (obj.isQualifiedName()) {
                QualifiedName qname = QualifiedName.fromNode(obj);
                if (maybeSpecType != null && maybeSpecType.isSubtypeOf(minusNull)) {
                    minusNull = maybeSpecType;
                }
                outEnv = updateLvalueTypeInEnv(inEnv, obj, qname, minusNull);
            }
            return new EnvTypePair(outEnv, minusNull);
        }
    }
    return new EnvTypePair(inEnv, recvType);
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) QualifiedName(com.google.javascript.jscomp.newtypes.QualifiedName) 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