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;
}
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));
}
}
}
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);
}
Aggregations