Search in sources :

Example 1 with FunctionType

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

the class SimpleInference method inferPropAccess.

private JSType inferPropAccess(Node recv, String pname, NTIScope scope) {
    if (recv.isGetProp() && recv.getLastChild().getString().equals("prototype")) {
        return inferPrototypeProperty(recv.getFirstChild(), pname, scope);
    }
    QualifiedName propQname = new QualifiedName(pname);
    JSType recvType = null;
    if (recv.isQualifiedName()) {
        QualifiedName recvQname = QualifiedName.fromNode(recv);
        Declaration decl = scope.getDeclaration(recvQname, false);
        if (decl != null) {
            EnumType et = decl.getEnum();
            if (et != null && et.enumLiteralHasKey(pname)) {
                return et.getPropType();
            }
            Namespace ns = decl.getNamespace();
            if (ns != null) {
                return inferDeclaration(ns.getDeclaration(propQname));
            }
            recvType = decl.getTypeOfSimpleDecl();
        }
    }
    if (recvType == null) {
        recvType = inferExprRecur(recv, scope);
    }
    if (recvType == null) {
        return null;
    }
    if (recvType.isScalar()) {
        recvType = recvType.autobox();
    }
    FunctionType ft = recvType.getFunTypeIfSingletonObj();
    if (ft != null && pname.equals("call")) {
        return this.commonTypes.fromFunctionType(ft.transformByCallProperty());
    } else if (ft != null && pname.equals("apply")) {
        return this.commonTypes.fromFunctionType(ft.transformByApplyProperty());
    }
    if (recvType.mayHaveProp(propQname)) {
        return recvType.getProp(propQname);
    }
    return null;
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) EnumType(com.google.javascript.jscomp.newtypes.EnumType) QualifiedName(com.google.javascript.jscomp.newtypes.QualifiedName) FunctionType(com.google.javascript.jscomp.newtypes.FunctionType) DeclaredFunctionType(com.google.javascript.jscomp.newtypes.DeclaredFunctionType) Declaration(com.google.javascript.jscomp.newtypes.Declaration) FunctionNamespace(com.google.javascript.jscomp.newtypes.FunctionNamespace) Namespace(com.google.javascript.jscomp.newtypes.Namespace)

Example 2 with FunctionType

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

the class NewTypeInference method collectTypesForEscapedVarsFwd.

/**
 * Used when analyzing a scope that defines variables used in inner scopes.
 * Returns a type environment that combines the types from all uses of a variable.
 */
private TypeEnv collectTypesForEscapedVarsFwd(Node n, TypeEnv env) {
    checkArgument(n.isFunction() || (n.isName() && NodeUtil.isInvocationTarget(n)), "Expected invovation target, found %s", n);
    String fnName = n.isFunction() ? symbolTable.getFunInternalName(n) : n.getString();
    NTIScope innerScope = this.currentScope.getScope(fnName);
    JSType summaryAsJstype = summaries.get(innerScope);
    if (summaryAsJstype == null) {
        // NOTE(dimvar): The n.isFromExterns part is here because the polymer pass does some weird
        // rewriting which AFAIU can copy some @polymerBehavior code from the externs to the source,
        // but the AST function nodes are still marked as externs, and don't have summaries.
        // We don't have a unit test for it.
        checkState(NodeUtil.isUnannotatedCallback(n) || n.isFromExterns());
        return env;
    }
    FunctionType summary = summaryAsJstype.getFunType();
    for (String freeVar : innerScope.getOuterVars()) {
        if (innerScope.getDeclaredTypeOf(freeVar) == null) {
            JSType outerType = envGetType(env, freeVar);
            if (outerType == null) {
                outerType = UNKNOWN;
            }
            JSType innerType = summary.getOuterVarPrecondition(freeVar);
            if (// haven't found an easy way to avoid false positives.
            !innerType.isLoose() && // so we don't warn for uninitialized variables.
            (n.isName() || (n.isFunction() && !outerType.isUndefined())) && !JSType.haveCommonSubtype(outerType, innerType)) {
                warnings.add(JSError.make(n, CROSS_SCOPE_GOTCHA, freeVar, outerType.toString(), innerType.toString()));
            }
            // If n is a callee node, we only want to keep the type in the callee.
            // If n is a function expression, we don't know if it will get called, so we take the
            // types from both scopes into account.
            JSType freeVarType;
            if (n.isFunction()) {
                // defined in this scope, and it's more likely that this type is correct.
                if (// only keep outerType for initialized variables
                !outerType.isNullOrUndef() && !outerType.isUnknown() && !innerType.isUnknown() && outerType.isSubtypeOf(innerType)) {
                    freeVarType = outerType;
                } else {
                    freeVarType = JSType.join(innerType, outerType);
                }
            } else {
                freeVarType = innerType;
            }
            env = envPutType(env, freeVar, freeVarType);
        }
    }
    return env;
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) FunctionType(com.google.javascript.jscomp.newtypes.FunctionType) DeclaredFunctionType(com.google.javascript.jscomp.newtypes.DeclaredFunctionType)

Example 3 with FunctionType

use of com.google.javascript.jscomp.newtypes.FunctionType 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)

Example 4 with FunctionType

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

the class NewTypeInference method analyzePropLValFwd.

private LValueResultFwd analyzePropLValFwd(Node obj, QualifiedName pname, LValueResultFwd recvLvalue, JSType requiredType, boolean insideQualifiedName) {
    checkArgument(pname.isIdentifier());
    TypeEnv inEnv = recvLvalue.env;
    JSType recvType = recvLvalue.type;
    if (!recvType.isUnion() && !recvType.isSingletonObj()) {
        // The lvalue is a subtype of TOP_OBJECT, but does not contain an object
        // yet, eg, it is ?, truthy, or bottom.
        recvType = TOP_OBJECT.withLoose();
    }
    Node propAccessNode = obj.getParent();
    if (propAccessNode.isGetProp() && propAccessNode.getParent().isAssign() && mayWarnAboutPropCreation(pname, propAccessNode, recvType)) {
        return new LValueResultFwd(inEnv, requiredType, null, null);
    }
    if (!insideQualifiedName && mayWarnAboutConstProp(propAccessNode, recvType, pname)) {
        return new LValueResultFwd(inEnv, requiredType, null, null);
    }
    if (!recvType.hasProp(pname)) {
        // name, or for assignment ops that won't create a new property.
        if (insideQualifiedName || !propAccessNode.getParent().isAssign()) {
            mayWarnAboutInexistentProp(propAccessNode, recvType, pname);
            if (!recvType.isLoose()) {
                return new LValueResultFwd(inEnv, requiredType, null, null);
            }
        }
        if (recvType.isLoose()) {
            // For loose objects, create the inner property if it doesn't exist.
            recvType = recvType.withProperty(pname, UNKNOWN);
            inEnv = updateLvalueTypeInEnv(inEnv, obj, recvLvalue.ptr, recvType);
        }
    }
    if (propAccessNode.isGetElem()) {
        mayWarnAboutStructPropAccess(obj, recvType);
    } else if (propAccessNode.isGetProp()) {
        mayWarnAboutDictPropAccess(obj, recvType);
    }
    QualifiedName setterPname = new QualifiedName(commonTypes.createSetterPropName(pname.getLeftmostName()));
    if (recvType.hasProp(setterPname)) {
        FunctionType funType = recvType.getProp(setterPname).getFunType();
        checkNotNull(funType, "recvType=%s, setterPname=%s", recvType, setterPname);
        JSType formalType = funType.getFormalType(0);
        checkState(!formalType.isBottom());
        return new LValueResultFwd(inEnv, formalType, formalType, null);
    }
    QualifiedName ptr = recvLvalue.ptr == null ? null : QualifiedName.join(recvLvalue.ptr, pname);
    return recvType.mayHaveProp(pname) ? new LValueResultFwd(inEnv, recvType.getProp(pname), recvType.getDeclaredProp(pname), ptr) : new LValueResultFwd(inEnv, UNKNOWN, null, ptr);
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) Node(com.google.javascript.rhino.Node) DiGraphNode(com.google.javascript.jscomp.graph.DiGraph.DiGraphNode) QualifiedName(com.google.javascript.jscomp.newtypes.QualifiedName) FunctionType(com.google.javascript.jscomp.newtypes.FunctionType) DeclaredFunctionType(com.google.javascript.jscomp.newtypes.DeclaredFunctionType) TypeEnv(com.google.javascript.jscomp.newtypes.TypeEnv)

Example 5 with FunctionType

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

the class NewTypeInference method instantiateGoogBind.

private void instantiateGoogBind(Node n, JSType recvType) {
    if (NodeUtil.isGoogBind(n)) {
        JSType t = (JSType) n.getTypeI();
        if (t.isFunctionType()) {
            FunctionType ft = t.getFunType();
            if (ft.isGeneric()) {
                FunctionType instantiatedFunction = ft.instantiateGenericsFromArgumentTypes(null, ImmutableList.of(UNKNOWN, recvType));
                n.setTypeI(this.commonTypes.fromFunctionType(instantiatedFunction));
            }
        }
    }
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) FunctionType(com.google.javascript.jscomp.newtypes.FunctionType) DeclaredFunctionType(com.google.javascript.jscomp.newtypes.DeclaredFunctionType)

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