Search in sources :

Example 1 with FunctionTypeBuilder

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

the class GlobalTypeInfoCollector method process.

@Override
public void process(Node externs, Node root) {
    checkNotNull(warnings, "Cannot rerun GlobalTypeInfoCollector.process");
    checkArgument(externs == null || externs.isRoot());
    checkArgument(root.isRoot(), "Root must be ROOT, but is %s", root.getToken());
    this.compiler.setMostRecentTypechecker(MostRecentTypechecker.NTI);
    NTIScope globalScope = new NTIScope(root, null, ImmutableList.<String>of(), getCommonTypes());
    globalScope.addUnknownTypeNames(this.globalTypeInfo.getUnknownTypeNames());
    this.globalTypeInfo.setGlobalScope(globalScope);
    this.scopes.add(globalScope);
    // Processing of a scope is split into many separate phases, and it's not
    // straightforward to remember which phase does what.
    // (1) Find names of classes, interfaces, typedefs, enums, and namespaces
    // defined in the global scope.
    CollectNamedTypes rootCnt = new CollectNamedTypes(globalScope);
    NodeTraversal.traverseEs6(this.compiler, externs, this.orderedExterns);
    rootCnt.collectNamedTypesInExterns();
    defineObjectAndFunctionIfMissing();
    NodeTraversal.traverseEs6(compiler, root, rootCnt);
    // (2) Determine the type represented by each typedef and each enum
    globalScope.resolveTypedefs(getTypeParser());
    globalScope.resolveEnums(getTypeParser());
    // (3) Repeat steps 1-2 for all the other scopes (outer-to-inner)
    for (int i = 1; i < this.scopes.size(); i++) {
        NTIScope s = this.scopes.get(i);
        CollectNamedTypes cnt = new CollectNamedTypes(s);
        NodeTraversal.traverseEs6(compiler, s.getBody(), cnt);
        s.resolveTypedefs(getTypeParser());
        s.resolveEnums(getTypeParser());
        if (NewTypeInference.measureMem) {
            NewTypeInference.updatePeakMem();
        }
    }
    // (4) The bulk of the global-scope processing happens here:
    // - Create scopes for functions
    // - Declare properties on types
    ProcessScope rootPs = new ProcessScope(globalScope);
    if (externs != null) {
        NodeTraversal.traverseEs6(compiler, externs, rootPs);
    }
    NodeTraversal.traverseEs6(compiler, root, rootPs);
    // (5) Things that must happen after the traversal of the scope
    rootPs.finishProcessingScope();
    // (6) Repeat steps 4-5 for all the other scopes (outer-to-inner)
    for (int i = 1; i < this.scopes.size(); i++) {
        NTIScope s = this.scopes.get(i);
        ProcessScope ps = new ProcessScope(s);
        NodeTraversal.traverseEs6(compiler, s.getBody(), ps);
        ps.finishProcessingScope();
        if (NewTypeInference.measureMem) {
            NewTypeInference.updatePeakMem();
        }
    }
    // (7) Adjust types of properties based on inheritance information.
    // Report errors in the inheritance chain. Do Window last.
    Collection<RawNominalType> windows = new ArrayList<>();
    for (Map.Entry<Node, RawNominalType> entry : nominaltypesByNode.entrySet()) {
        RawNominalType rawType = entry.getValue();
        if (this.window != null && rawType.hasAncestorClass(this.window)) {
            windows.add(rawType);
            continue;
        }
        checkAndFreezeNominalType(rawType);
    }
    JSType globalThisType = null;
    if (this.window != null) {
        // Copy properties from window to Window.prototype, because sometimes
        // people pass window around rather than using it directly.
        Namespace winNs = globalScope.getNamespace(WINDOW_INSTANCE);
        if (winNs != null) {
            winNs.copyWindowProperties(getCommonTypes(), this.window);
        }
        for (RawNominalType rawType : windows) {
            checkAndFreezeNominalType(rawType);
        }
        if (winNs != null) {
            ((NamespaceLit) winNs).setWindowType(this.window.getAsNominalType());
            // Type the global THIS as window
            globalThisType = winNs.toJSType();
        }
    }
    if (globalThisType == null) {
        // Type the global THIS as a loose object
        globalThisType = getCommonTypes().getTopObject().withLoose();
    }
    getCommonTypes().setGlobalThis(globalThisType);
    globalScope.setDeclaredType((new FunctionTypeBuilder(getCommonTypes())).addReceiverType(globalThisType).buildDeclaration());
    this.globalTypeInfo.setRawNominalTypes(nominaltypesByNode.values());
    nominaltypesByNode = null;
    propertyDefs = null;
    for (NTIScope s : this.scopes) {
        s.freezeScope();
    }
    this.simpleInference.setScopesAreFrozen();
    // Traverse the externs and annotate them with types.
    // Only works for the top level, not inside function bodies.
    NodeTraversal.traverseEs6(this.compiler, externs, new NodeTraversal.AbstractShallowCallback() {

        @Override
        public void visit(NodeTraversal t, Node n, Node parent) {
            if (n.isQualifiedName()) {
                Declaration d = getGlobalScope().getDeclaration(QualifiedName.fromNode(n), false);
                JSType type = simpleInferDeclaration(d);
                if (type == null) {
                    type = simpleInferExpr(n, getGlobalScope());
                }
                // Type-based passes expect the externs to be annotated, so use ? when type is null.
                n.setTypeI(type != null ? type : getCommonTypes().UNKNOWN);
            }
        }
    });
    Map<Node, String> unknownTypes = getTypeParser().getUnknownTypesMap();
    for (Map.Entry<Node, String> unknownTypeEntry : unknownTypes.entrySet()) {
        this.warnings.add(JSError.make(unknownTypeEntry.getKey(), UNRECOGNIZED_TYPE_NAME, unknownTypeEntry.getValue()));
    }
    // package, so we collect its warnings here.
    for (JSError warning : getTypeParser().getWarnings()) {
        this.warnings.add(warning);
    }
    this.warnings = null;
    this.funNameGen = null;
    reorderScopesForNTI();
    this.compiler.setExternProperties(ImmutableSet.copyOf(getExternPropertyNames()));
}
Also used : JSType(com.google.javascript.jscomp.newtypes.JSType) Node(com.google.javascript.rhino.Node) ArrayList(java.util.ArrayList) NamespaceLit(com.google.javascript.jscomp.newtypes.NamespaceLit) AbstractShallowCallback(com.google.javascript.jscomp.NodeTraversal.AbstractShallowCallback) Namespace(com.google.javascript.jscomp.newtypes.Namespace) FunctionNamespace(com.google.javascript.jscomp.newtypes.FunctionNamespace) RawNominalType(com.google.javascript.jscomp.newtypes.RawNominalType) Declaration(com.google.javascript.jscomp.newtypes.Declaration) Map(java.util.Map) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) FunctionTypeBuilder(com.google.javascript.jscomp.newtypes.FunctionTypeBuilder)

Example 2 with FunctionTypeBuilder

use of com.google.javascript.jscomp.newtypes.FunctionTypeBuilder 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 3 with FunctionTypeBuilder

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

the class NewTypeInference method createSummary.

private void createSummary(NTIScope fn) {
    Node fnRoot = fn.getRoot();
    checkArgument(!fnRoot.isFromExterns());
    FunctionTypeBuilder builder = new FunctionTypeBuilder(this.commonTypes);
    TypeEnv entryEnv = getEntryTypeEnv();
    TypeEnv exitEnv = getExitTypeEnv();
    DeclaredFunctionType declType = fn.getDeclaredFunctionType();
    int reqArity = declType.getRequiredArity();
    int optArity = declType.getOptionalArity();
    if (declType.isGeneric()) {
        builder.addTypeParameters(declType.getTypeParameters());
    }
    // Every trailing undeclared formal whose inferred type is ?
    // or contains undefined can be marked as optional.
    List<String> formals = fn.getFormals();
    for (int i = reqArity - 1; i >= 0; i--) {
        JSType formalType = declType.getFormalType(i);
        if (formalType != null) {
            break;
        }
        String formalName = formals.get(i);
        formalType = getTypeAfterFwd(formalName, entryEnv, exitEnv);
        if (formalType.isUnknown() || UNDEFINED.isSubtypeOf(formalType)) {
            reqArity--;
        } else {
            break;
        }
    }
    // Collect types of formals in the builder
    int i = 0;
    for (String formalName : formals) {
        JSType formalType = declType.getFormalType(i);
        if (formalType == null) {
            formalType = getTypeAfterFwd(formalName, entryEnv, exitEnv);
        }
        if (i < reqArity) {
            builder.addReqFormal(formalType);
        } else if (i < optArity) {
            builder.addOptFormal(formalType);
        }
        i++;
    }
    if (declType.hasRestFormals()) {
        builder.addRestFormals(declType.getFormalType(i));
    }
    for (String outer : fn.getOuterVars()) {
        println("Free var ", outer, " going in summary");
        builder.addOuterVarPrecondition(outer, envGetType(entryEnv, outer));
    }
    builder.addNominalType(declType.getNominalType());
    builder.addReceiverType(declType.getReceiverType());
    builder.addAbstract(declType.isAbstract());
    addRetTypeAndWarn(fn, exitEnv, declType, builder);
    JSType summary = commonTypes.fromFunctionType(builder.buildFunction());
    println("Function summary for ", fn.getReadableName());
    println("\t", summary);
    summary = changeTypeIfFunctionNamespace(fn, summary);
    summaries.put(fn, summary);
    maybeSetTypeI(fnRoot, summary);
    Node fnNameNode = NodeUtil.getNameNode(fnRoot);
    if (fnNameNode != null) {
        maybeSetTypeI(fnNameNode, summary);
    }
}
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) FunctionTypeBuilder(com.google.javascript.jscomp.newtypes.FunctionTypeBuilder)

Example 4 with FunctionTypeBuilder

use of com.google.javascript.jscomp.newtypes.FunctionTypeBuilder 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 5 with FunctionTypeBuilder

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

Aggregations

FunctionTypeBuilder (com.google.javascript.jscomp.newtypes.FunctionTypeBuilder)5 JSType (com.google.javascript.jscomp.newtypes.JSType)5 Node (com.google.javascript.rhino.Node)5 DiGraphNode (com.google.javascript.jscomp.graph.DiGraph.DiGraphNode)4 TypeEnv (com.google.javascript.jscomp.newtypes.TypeEnv)4 DeclaredFunctionType (com.google.javascript.jscomp.newtypes.DeclaredFunctionType)3 FunctionType (com.google.javascript.jscomp.newtypes.FunctionType)2 ArrayList (java.util.ArrayList)2 Bind (com.google.javascript.jscomp.CodingConvention.Bind)1 AbstractShallowCallback (com.google.javascript.jscomp.NodeTraversal.AbstractShallowCallback)1 Declaration (com.google.javascript.jscomp.newtypes.Declaration)1 FunctionNamespace (com.google.javascript.jscomp.newtypes.FunctionNamespace)1 Namespace (com.google.javascript.jscomp.newtypes.Namespace)1 NamespaceLit (com.google.javascript.jscomp.newtypes.NamespaceLit)1 RawNominalType (com.google.javascript.jscomp.newtypes.RawNominalType)1 HashMap (java.util.HashMap)1 LinkedHashMap (java.util.LinkedHashMap)1 Map (java.util.Map)1