Search in sources :

Example 1 with AssertionFunctionSpec

use of com.google.javascript.jscomp.CodingConvention.AssertionFunctionSpec in project closure-compiler by google.

the class TypeInference method tightenTypesAfterAssertions.

private FlowScope tightenTypesAfterAssertions(FlowScope scope, Node callNode) {
    Node left = callNode.getFirstChild();
    Node firstParam = left.getNext();
    AssertionFunctionSpec assertionFunctionSpec = assertionFunctionsMap.get(left.getQualifiedName());
    if (assertionFunctionSpec == null || firstParam == null) {
        return scope;
    }
    Node assertedNode = assertionFunctionSpec.getAssertedParam(firstParam);
    if (assertedNode == null) {
        return scope;
    }
    JSType assertedType = assertionFunctionSpec.getAssertedOldType(callNode, registry);
    String assertedNodeName = assertedNode.getQualifiedName();
    JSType narrowed;
    // Handle assertions that enforce expressions evaluate to true.
    if (assertedType == null) {
        // Handle arbitrary expressions within the assert.
        scope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome(assertedNode, scope, true);
        // Build the result of the assertExpression
        narrowed = getJSType(assertedNode).restrictByNotNullOrUndefined();
    } else {
        // Handle assertions that enforce expressions are of a certain type.
        JSType type = getJSType(assertedNode);
        if (assertedType.isUnknownType() || type.isUnknownType()) {
            narrowed = assertedType;
        } else {
            narrowed = type.getGreatestSubtype(assertedType);
        }
        if (assertedNodeName != null && type.differsFrom(narrowed)) {
            scope = narrowScope(scope, assertedNode, narrowed);
        }
    }
    callNode.setJSType(narrowed);
    return scope;
}
Also used : JSType(com.google.javascript.rhino.jstype.JSType) Node(com.google.javascript.rhino.Node) AssertionFunctionSpec(com.google.javascript.jscomp.CodingConvention.AssertionFunctionSpec)

Example 2 with AssertionFunctionSpec

use of com.google.javascript.jscomp.CodingConvention.AssertionFunctionSpec in project closure-compiler by google.

the class NewTypeInference method analyzeInvocationFwd.

private EnvTypePair analyzeInvocationFwd(Node expr, TypeEnv inEnv, JSType requiredType, JSType specializedType) {
    if (isPropertyTestCall(expr)) {
        return analyzePropertyTestCallFwd(expr, inEnv, specializedType);
    }
    if (expr.isCall() && this.convention.getObjectLiteralCast(expr) != null) {
        return analyzeObjLitCastFwd(this.convention.getObjectLiteralCast(expr), expr, inEnv);
    }
    Node callee = expr.getFirstChild();
    if (isFunctionBind(callee, inEnv, true)) {
        return analyzeFunctionBindFwd(expr, inEnv);
    }
    AssertionFunctionSpec assertionFunctionSpec = assertionFunctionsMap.get(callee.getQualifiedName());
    if (assertionFunctionSpec != null) {
        return analyzeAssertionCall(expr, inEnv, assertionFunctionSpec);
    }
    EnvTypePair calleePair = analyzeExprFwd(callee, inEnv, commonTypes.topFunction());
    TypeEnv envAfterCallee = calleePair.env;
    calleePair = mayWarnAboutNullableReferenceAndTighten(callee, calleePair.type, null, envAfterCallee);
    JSType calleeType = calleePair.type;
    if (calleeType.isBottom() || !calleeType.isSubtypeOf(commonTypes.topFunction())) {
        warnings.add(JSError.make(expr, NOT_CALLABLE, calleeType.toString()));
    }
    FunctionType funType = calleeType.getFunTypeIfSingletonObj();
    if (funType == null || funType.isTopFunction() || funType.isQmarkFunction()) {
        return analyzeInvocationArgsFwdWhenError(expr, envAfterCallee);
    } else if (funType.isLoose()) {
        return analyzeLooseCallNodeFwd(expr, envAfterCallee, requiredType);
    } else if (!isConstructorCall(expr) && funType.isSomeConstructorOrInterface() && (funType.getReturnType().isUnknown() || funType.getReturnType().isUndefined())) {
        warnings.add(JSError.make(expr, CONSTRUCTOR_NOT_CALLABLE, funType.toString()));
        return analyzeInvocationArgsFwdWhenError(expr, envAfterCallee);
    } else if (expr.isNew()) {
        if (!funType.isSomeConstructorOrInterface() || funType.isInterfaceDefinition()) {
            // or as an arbitrarily nested property), don't warn.
            if (callee.isQualifiedName()) {
                String qnameRoot = QualifiedName.fromNode(callee).getLeftmostName();
                if (!this.currentScope.isFormalParamInAnyAncestorScope(qnameRoot)) {
                    warnings.add(JSError.make(expr, NOT_A_CONSTRUCTOR, funType.toString()));
                }
            }
            return analyzeInvocationArgsFwdWhenError(expr, envAfterCallee);
        } else if (funType.isConstructorOfAbstractClass()) {
            warnings.add(JSError.make(expr, CANNOT_INSTANTIATE_ABSTRACT_CLASS, funType.toString()));
            return analyzeInvocationArgsFwdWhenError(expr, envAfterCallee);
        }
    } else if (expr.isTaggedTemplateLit()) {
        funType = checkTaggedFunctionFirstParam(expr.getLastChild(), expr.getFirstChild(), funType);
    }
    if (!isInvocationArgCountCorrectAndWarn(funType, expr, callee)) {
        return analyzeInvocationArgsFwdWhenError(expr, envAfterCallee);
    }
    // save for later
    FunctionType originalFunType = funType;
    if (funType.isGeneric()) {
        Node receiver = callee.isGetProp() ? callee.getFirstChild() : null;
        Node firstArg = expr.getSecondChild();
        ImmutableMap<String, JSType> typeMap = calcTypeInstantiationFwd(expr, receiver, firstArg, funType, envAfterCallee);
        funType = instantiateCalleeMaybeWithTTL(funType, typeMap);
        callee.setTypeI(this.commonTypes.fromFunctionType(funType));
        println("Instantiated function type: ", funType);
    }
    // argTypes collects types of actuals for deferred checks.
    List<JSType> argTypes = new ArrayList<>();
    Node invocationNode = expr.isTaggedTemplateLit() ? expr.getLastChild() : expr;
    Iterable<Node> argIterable = NodeUtil.getInvocationArgsAsIterable(expr);
    TypeEnv tmpEnv = analyzeInvocationArgumentsFwd(invocationNode, argIterable, funType, argTypes, envAfterCallee);
    if (callee.isName()) {
        String calleeName = callee.getString();
        if (this.currentScope.isKnownFunction(calleeName) && !this.currentScope.isExternalFunction(calleeName)) {
            // exactly using their summaries, and don't need deferred checks
            if (this.currentScope.isLocalFunDef(calleeName)) {
                tmpEnv = collectTypesForEscapedVarsFwd(callee, tmpEnv);
            } else if (!originalFunType.isGeneric()) {
                JSType expectedRetType = requiredType;
                println("Updating deferred check with ret: ", expectedRetType, " and args: ", argTypes);
                DeferredCheck dc;
                if (funType.isSomeConstructorOrInterface()) {
                    dc = new DeferredCheck(expr, null, this.currentScope, this.currentScope.getScope(calleeName));
                    deferredChecks.put(expr, dc);
                } else {
                    dc = deferredChecks.get(expr);
                    if (dc != null) {
                        dc.updateReturn(expectedRetType);
                    } else {
                        // The backward analysis of a function is skipped when all
                        // variables, including outer vars, are declared.
                        // So, we check that dc is null iff bwd was skipped.
                        Preconditions.checkState(!this.currentScope.hasUndeclaredFormalsOrOuters(), "No deferred check created in backward direction for %s", expr);
                    }
                }
                if (dc != null) {
                    dc.updateArgTypes(argTypes);
                }
            }
        }
    }
    JSType retType = expr.isNew() ? funType.getThisType() : funType.getReturnType();
    if (retType.isSubtypeOf(requiredType)) {
        retType = retType.specialize(specializedType);
    }
    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) ArrayList(java.util.ArrayList) AssertionFunctionSpec(com.google.javascript.jscomp.CodingConvention.AssertionFunctionSpec) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv)

Aggregations

AssertionFunctionSpec (com.google.javascript.jscomp.CodingConvention.AssertionFunctionSpec)2 Node (com.google.javascript.rhino.Node)2 DiGraphNode (com.google.javascript.jscomp.graph.DiGraph.DiGraphNode)1 DeclaredFunctionType (com.google.javascript.jscomp.newtypes.DeclaredFunctionType)1 FunctionType (com.google.javascript.jscomp.newtypes.FunctionType)1 JSType (com.google.javascript.jscomp.newtypes.JSType)1 TypeEnv (com.google.javascript.jscomp.newtypes.TypeEnv)1 JSType (com.google.javascript.rhino.jstype.JSType)1 ArrayList (java.util.ArrayList)1