Search in sources :

Example 11 with Parameter

use of com.google.javascript.rhino.jstype.FunctionType.Parameter in project closure-compiler by google.

the class TypeInference method inferParameters.

/**
 * Infers all of a function's parameters if their types aren't declared.
 */
private FlowScope inferParameters(FlowScope entryFlowScope) {
    Node functionNode = containerScope.getRootNode();
    if (!functionNode.isFunction()) {
        // we're in the global scope
        return entryFlowScope;
    } else if (NodeUtil.isBundledGoogModuleCall(functionNode.getParent())) {
        // Pretend the function literal in `goog.loadModule(function(exports) {` does not exist.
        return entryFlowScope;
    }
    Node astParameters = functionNode.getSecondChild();
    Node iifeArgumentNode = null;
    if (NodeUtil.isInvocationTarget(functionNode)) {
        iifeArgumentNode = functionNode.getNext();
    }
    FunctionType functionType = JSType.toMaybeFunctionType(functionNode.getJSType());
    Iterator<Parameter> parameterTypes = functionType.getParameters().iterator();
    Parameter parameter = parameterTypes.hasNext() ? parameterTypes.next() : null;
    // FunctionType param nodes there are.
    for (Node astParamItr = astParameters.getFirstChild(); astParamItr != null; astParamItr = astParamItr.getNext()) {
        Node astParam = astParamItr;
        if (iifeArgumentNode != null && iifeArgumentNode.isSpread()) {
            // block inference on all parameters that might possibly be set by a spread, e.g. `z` in
            // (function f(x, y, z = 1))(...[1, 2], 'foo')
            iifeArgumentNode = null;
        }
        // Running variable for the type of the param within the body of the function. We use the
        // existing type on the param node as the default, and then transform it according to the
        // declaration syntax.
        JSType inferredType = getJSType(astParam);
        if (iifeArgumentNode != null) {
            if (iifeArgumentNode.getJSType() != null) {
                inferredType = iifeArgumentNode.getJSType();
            }
        } else if (parameter != null) {
            if (parameter.getJSType() != null) {
                inferredType = parameter.getJSType();
            }
        }
        Node defaultValue = null;
        if (astParam.isDefaultValue()) {
            defaultValue = astParam.getSecondChild();
            // must call `traverse` to correctly type the default value
            entryFlowScope = traverse(defaultValue, entryFlowScope);
            astParam = astParam.getFirstChild();
        } else if (astParam.isRest()) {
            // e.g. `function f(p1, ...restParamName) {}`
            // set astParam = restParamName
            astParam = astParam.getOnlyChild();
            // convert 'number' into 'Array<number>' for rest parameters
            inferredType = registry.createTemplatizedType(registry.getNativeObjectType(ARRAY_TYPE), inferredType);
        }
        if (defaultValue != null) {
            // The param could possibly be the default type, and `undefined` args won't propagate in.
            inferredType = registry.createUnionType(inferredType.restrictByNotUndefined(), getJSType(defaultValue));
        }
        if (astParam.isDestructuringPattern()) {
            // even if the inferredType is null, we still need to type all the nodes inside the
            // destructuring pattern. (e.g. in computed properties or default value expressions)
            entryFlowScope = updateDestructuringParameter(astParam, inferredType, entryFlowScope);
        } else {
            // for simple named parameters, we only need to update the scope/AST if we have a new
            // inferred type.
            entryFlowScope = updateNamedParameter(astParam, defaultValue != null, inferredType, entryFlowScope);
        }
        parameter = parameterTypes.hasNext() ? parameterTypes.next() : null;
        iifeArgumentNode = iifeArgumentNode != null ? iifeArgumentNode.getNext() : null;
    }
    return entryFlowScope;
}
Also used : JSType(com.google.javascript.rhino.jstype.JSType) Node(com.google.javascript.rhino.Node) FunctionType(com.google.javascript.rhino.jstype.FunctionType) Parameter(com.google.javascript.rhino.jstype.FunctionType.Parameter)

Example 12 with Parameter

use of com.google.javascript.rhino.jstype.FunctionType.Parameter in project closure-compiler by google.

the class TypeInference method updateTypeOfArguments.

/**
 * Performs a limited back-inference on function arguments based on the expected parameter types.
 *
 * <p>Currently this only does back-inference in two cases: it infers the type of function literal
 * arguments and adds inferred properties to inferred object-typed arguments.
 *
 * <p>For example: if someone calls `Promise<string>.prototype.then` with `(result) => ...` then
 * we infer that the type of the arrow function is `function(string): ?`, and inside the arrow
 * function body we know that `result` is a string.
 */
private void updateTypeOfArguments(Node n, FunctionType fnType) {
    checkState(NodeUtil.isInvocation(n), n);
    Iterator<Parameter> parameters = fnType.getParameters().iterator();
    if (n.isTaggedTemplateLit()) {
        // subs, not an actual AST node, so there's nothing to update.
        if (!parameters.hasNext()) {
            // TypeCheck will warn if there is no first parameter. Just bail out here.
            return;
        }
        parameters.next();
    }
    Iterator<Node> arguments = NodeUtil.getInvocationArgsAsIterable(n).iterator();
    Parameter iParameter;
    Node iArgument;
    // Note: if there are too many or too few arguments, TypeCheck will warn.
    while (parameters.hasNext() && arguments.hasNext()) {
        iArgument = arguments.next();
        JSType iArgumentType = getJSType(iArgument);
        iParameter = parameters.next();
        JSType iParameterType = iParameter.getJSType() != null ? iParameter.getJSType() : unknownType;
        inferPropertyTypesToMatchConstraint(iArgumentType, iParameterType);
        // If the parameter to the call is a function expression, propagate the
        // function signature from the call site to the function node.
        // Filter out non-function types (such as null and undefined) as
        // we only care about FUNCTION subtypes here.
        FunctionType restrictedParameter = null;
        if (iParameterType.isUnionType()) {
            UnionType union = iParameterType.toMaybeUnionType();
            for (JSType alternative : union.getAlternates()) {
                if (alternative.isFunctionType()) {
                    // There is only one function type per union.
                    restrictedParameter = alternative.toMaybeFunctionType();
                    break;
                }
            }
        } else {
            restrictedParameter = iParameterType.toMaybeFunctionType();
        }
        if (restrictedParameter != null && iArgument.isFunction() && iArgumentType.isFunctionType()) {
            FunctionType argFnType = iArgumentType.toMaybeFunctionType();
            JSDocInfo argJsdoc = iArgument.getJSDocInfo();
            // Treat the parameter & return types of the function as 'declared' if the function has
            // JSDoc with type annotations, or a parameter has inline JSDoc.
            // Note that this does not distinguish between cases where all parameters have JSDoc vs
            // only one parameter has JSDoc.
            boolean declared = (argJsdoc != null && argJsdoc.containsDeclaration()) || NodeUtil.functionHasInlineJsdocs(iArgument);
            iArgument.setJSType(matchFunction(restrictedParameter, argFnType, declared));
        }
    }
}
Also used : UnionType(com.google.javascript.rhino.jstype.UnionType) JSType(com.google.javascript.rhino.jstype.JSType) Node(com.google.javascript.rhino.Node) FunctionType(com.google.javascript.rhino.jstype.FunctionType) Parameter(com.google.javascript.rhino.jstype.FunctionType.Parameter) JSDocInfo(com.google.javascript.rhino.JSDocInfo)

Example 13 with Parameter

use of com.google.javascript.rhino.jstype.FunctionType.Parameter in project closure-compiler by google.

the class FunctionParamBuilder method newParameter.

/**
 * Adds a parameter with the given type
 */
private void newParameter(JSType type, boolean isOptional, boolean isVariadic) {
    Parameter parameter = Parameter.create(type, isOptional, isVariadic);
    parameters.add(parameter);
}
Also used : Parameter(com.google.javascript.rhino.jstype.FunctionType.Parameter)

Aggregations

Parameter (com.google.javascript.rhino.jstype.FunctionType.Parameter)13 Node (com.google.javascript.rhino.Node)8 JSType (com.google.javascript.rhino.jstype.JSType)6 FunctionType (com.google.javascript.rhino.jstype.FunctionType)4 JSTypeExpression (com.google.javascript.rhino.JSTypeExpression)2 FunctionParamBuilder (com.google.javascript.rhino.jstype.FunctionParamBuilder)2 JSDocInfo (com.google.javascript.rhino.JSDocInfo)1 UnionType (com.google.javascript.rhino.jstype.UnionType)1