Search in sources :

Example 16 with TypeEnv

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

the class NewTypeInference method analyzeLooseCallNodeBwd.

private EnvTypePair analyzeLooseCallNodeBwd(Node callNode, TypeEnv outEnv, JSType retType) {
    checkArgument(callNode.isCall() || callNode.isNew());
    checkNotNull(retType);
    Node callee = callNode.getFirstChild();
    TypeEnv tmpEnv = outEnv;
    FunctionTypeBuilder builder = new FunctionTypeBuilder(this.commonTypes);
    Node target = callNode.getFirstChild();
    for (Node arg = callNode.getLastChild(); arg != target; arg = arg.getPrevious()) {
        EnvTypePair pair = analyzeExprBwd(arg, tmpEnv);
        JSType argType = pair.type;
        tmpEnv = pair.env;
        // May wait until FWD to get more precise argument types.
        builder.addReqFormalToFront(isImpreciseType(argType) ? BOTTOM : argType);
    }
    JSType looseRetType = retType.isUnknown() ? BOTTOM : retType;
    JSType looseFunctionType = commonTypes.fromFunctionType(builder.addRetType(looseRetType).addLoose().buildFunction());
    println("loose function type is ", looseFunctionType);
    EnvTypePair calleePair = analyzeExprBwd(callee, tmpEnv, looseFunctionType);
    return new EnvTypePair(calleePair.env, retType);
}
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) FunctionTypeBuilder(com.google.javascript.jscomp.newtypes.FunctionTypeBuilder)

Example 17 with TypeEnv

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

the class NewTypeInference method analyzeBinaryNumericOpBwd.

private EnvTypePair analyzeBinaryNumericOpBwd(Node expr, TypeEnv outEnv) {
    Node lhs = expr.getFirstChild();
    Node rhs = expr.getLastChild();
    TypeEnv rhsEnv = analyzeExprBwd(rhs, outEnv, NUMBER).env;
    EnvTypePair pair = analyzeExprBwd(lhs, rhsEnv, NUMBER);
    pair.type = NUMBER;
    return pair;
}
Also used : Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv)

Example 18 with TypeEnv

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

the class NewTypeInference method analyzePropAccessFwd.

private EnvTypePair analyzePropAccessFwd(Node receiver, String pname, TypeEnv inEnv, JSType requiredType, JSType specializedType) {
    QualifiedName propQname = new QualifiedName(pname);
    Node propAccessNode = receiver.getParent();
    EnvTypePair pair;
    JSType reqObjType = pickReqObjType(propAccessNode);
    JSType recvReqType;
    JSType recvSpecType;
    // First, analyze the receiver object.
    if ((NodeUtil.isPropertyTest(compiler, propAccessNode) && !specializedType.isFalseOrFalsy()) || (NodeUtil.isPropertyAbsenceTest(propAccessNode) && !specializedType.isTrueOrTruthy()) || // else branch of "if (!x.prop)" is a property test.
    specializedType.isTrueOrTruthy()) {
        recvReqType = reqObjType;
        pair = analyzeExprFwd(receiver, inEnv, recvReqType);
        JSType subtypeWithProp = pair.type.findSubtypeWithProp(propQname);
        if (subtypeWithProp.isBottom()) {
            recvSpecType = reqObjType;
        } else {
            recvSpecType = subtypeWithProp;
        }
        if (specializedType.isTrueOrTruthy()) {
            // This handles cases like: if (x.prop1 && x.prop1.prop2) { ... }
            // In the THEN branch, the only thing we know about x.prop1 is that it
            // has a truthy property, so x.prop1 should be a loose object to avoid
            // spurious warnings.
            recvSpecType = recvSpecType.withLoose().withProperty(propQname, specializedType);
        } else {
            recvSpecType = recvSpecType.withProperty(propQname, specializedType);
        }
    } else if (specializedType.isFalseOrFalsy()) {
        recvReqType = recvSpecType = reqObjType;
    } else {
        recvReqType = reqObjType.withProperty(propQname, requiredType);
        recvSpecType = reqObjType.withProperty(propQname, specializedType);
    }
    pair = analyzeExprFwd(receiver, inEnv, recvReqType, recvSpecType);
    pair = mayWarnAboutNullableReferenceAndTighten(receiver, pair.type, recvSpecType, pair.env);
    JSType recvType = pair.type.autobox();
    if (recvType.isUnknown() || recvType.isTrueOrTruthy()) {
        mayWarnAboutInexistentProp(propAccessNode, recvType, propQname);
        return new EnvTypePair(pair.env, requiredType);
    }
    if (mayWarnAboutNonObject(receiver, recvType, specializedType)) {
        return new EnvTypePair(pair.env, requiredType);
    }
    FunctionType ft = recvType.getFunTypeIfSingletonObj();
    if (ft != null && (pname.equals("call") || pname.equals("apply"))) {
        if (ft.isAbstract()) {
            // We don't check if the parent of the property access is a call node.
            // This catches calls that are a few nodes away, and also warns on .call/.apply
            // accesses that do not result in calls (these should be very rare).
            String funName = receiver.isQualifiedName() ? receiver.getQualifiedName() : "";
            warnings.add(JSError.make(propAccessNode, ABSTRACT_SUPER_METHOD_NOT_CALLABLE, funName));
        }
        return new EnvTypePair(pair.env, pname.equals("call") ? commonTypes.fromFunctionType(ft.transformByCallProperty()) : commonTypes.fromFunctionType(ft.transformByApplyProperty()));
    }
    if (this.convention.isSuperClassReference(pname)) {
        if (ft != null && ft.isUniqueConstructor()) {
            JSType result = ft.getSuperPrototype();
            pair.type = firstNonNull(result, UNDEFINED);
            return pair;
        }
    }
    if (propAccessNode.isGetProp() && mayWarnAboutDictPropAccess(receiver, recvType)) {
        return new EnvTypePair(pair.env, requiredType);
    }
    if (recvType.isTop()) {
        recvType = TOP_OBJECT;
    }
    if (propAccessNode.getParent().isDelProp() && recvType.hasConstantProp(propQname)) {
        warnings.add(JSError.make(propAccessNode.getParent(), CONST_PROPERTY_DELETED, pname));
    }
    // Then, analyze the property access.
    QualifiedName getterPname = new QualifiedName(commonTypes.createGetterPropName(pname));
    if (recvType.hasProp(getterPname)) {
        return new EnvTypePair(pair.env, recvType.getProp(getterPname));
    }
    JSType resultType = recvType.getProp(propQname);
    if (resultType != null && resultType.isBottom()) {
        warnings.add(JSError.make(propAccessNode, BOTTOM_PROP, pname, recvType.toString()));
        return new EnvTypePair(pair.env, UNKNOWN);
    }
    if (!propAccessNode.getParent().isExprResult() && !specializedType.isTrueOrTruthy() && !specializedType.isFalseOrFalsy() && !recvType.mayBeDict() && !mayWarnAboutInexistentProp(propAccessNode, recvType, propQname) && recvType.hasProp(propQname) && !resultType.isSubtypeOf(requiredType) && tightenPropertyTypeAndDontWarn(receiver.isName() ? receiver.getString() : null, propAccessNode, recvType, recvType.getDeclaredProp(propQname), resultType, requiredType)) {
        // Tighten the inferred type and don't warn.
        // See analyzeNameFwd for explanation about types as lower/upper bounds.
        resultType = resultType.specialize(requiredType);
        LValueResultFwd lvr = analyzeLValueFwd(propAccessNode, inEnv, resultType);
        TypeEnv updatedEnv = updateLvalueTypeInEnv(lvr.env, propAccessNode, lvr.ptr, resultType);
        return new EnvTypePair(updatedEnv, resultType);
    }
    // We've already warned about missing props, and never want to return null.
    if (resultType == null) {
        resultType = UNKNOWN;
    }
    // Any potential type mismatch will be caught by the context
    return new EnvTypePair(pair.env, resultType);
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) QualifiedName(com.google.javascript.jscomp.newtypes.QualifiedName) 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 19 with TypeEnv

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

the class NewTypeInference method analyzeFunction.

private void analyzeFunction(NTIScope scope) {
    println("=== Analyzing function: ", scope.getReadableName(), " ===");
    currentScope = scope;
    exitEnvs = new ArrayList<>();
    Node scopeRoot = scope.getRoot();
    if (NodeUtil.isUnannotatedCallback(scopeRoot)) {
        computeFnDeclaredTypeForCallback(scope);
    }
    ControlFlowAnalysis cfa = new ControlFlowAnalysis(compiler, false, false);
    cfa.process(null, scopeRoot);
    this.cfg = cfa.getCfg();
    println(this.cfg);
    // The size is > 1 when multiple files are compiled
    // Preconditions.checkState(cfg.getEntry().getOutEdges().size() == 1);
    NTIWorkset workset = NTIWorkset.create(this.cfg);
    this.typeEnvFromDeclaredTypes = getTypeEnvFromDeclaredTypes();
    if (scope.isFunction() && scope.hasUndeclaredFormalsOrOuters()) {
        // correctly waits for all incoming edges).
        for (DiGraphEdge<Node, ControlFlowGraph.Branch> e : this.cfg.getEdges()) {
            envs.put(e, this.typeEnvFromDeclaredTypes);
        }
        analyzeFunctionBwd(workset);
        // TODO(dimvar): Revisit what we throw away after the bwd analysis
        TypeEnv entryEnv = getEntryTypeEnv();
        // Gives better results than starting them at unknown.
        for (String varName : scope.getOuterVars()) {
            JSType inferred = scope.getInferredTypeOf(varName);
            if (inferred != null) {
                entryEnv = envPutType(entryEnv, varName, inferred);
            }
        }
        initEdgeEnvsFwd(entryEnv);
        if (measureMem) {
            updatePeakMem();
        }
    } else {
        TypeEnv entryEnv = this.typeEnvFromDeclaredTypes;
        initEdgeEnvsFwd(entryEnv);
    }
    this.typeEnvFromDeclaredTypes = null;
    analyzeFunctionFwd(workset);
    if (scope.isFunction()) {
        createSummary(scope);
    }
    if (measureMem) {
        updatePeakMem();
    }
}
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 20 with TypeEnv

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

the class NewTypeInference method analyzeEqNeBwd.

private EnvTypePair analyzeEqNeBwd(Node expr, TypeEnv outEnv) {
    TypeEnv rhsEnv = analyzeExprBwd(expr.getLastChild(), outEnv).env;
    EnvTypePair pair = analyzeExprBwd(expr.getFirstChild(), rhsEnv);
    pair.type = BOOLEAN;
    return pair;
}
Also used : 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