third_party/closure-compiler/src/src/com/google/javascript/jscomp/TypeInference.java
/** Infers all of a function's parameters if their types aren't declared. */
Infers all of a function's parameters if their types aren't declared.
Infers all of a function ' s parameters if their types aren ' t declared .
@SuppressWarnings("ReferenceEquality") 
  private FlowScope inferParameters(FlowScope entryFlowScope) {
    Node functionNode = containerScope.getRootNode();
    if (!functionNode.isFunction()) {
      return entryFlowScope; 
    } else if (NodeUtil.isBundledGoogModuleCall(functionNode.getParent())) {
      return entryFlowScope;
    }
    Node astParameters = functionNode.getSecondChild();
    Node iifeArgumentNode = null;
    if (NodeUtil.isInvocationTarget(functionNode)) {
      iifeArgumentNode = functionNode.getNext();
    }
    FunctionType functionType = JSType.toMaybeFunctionType(functionNode.getJSType());
    Node parameterTypeNode = functionType.getParametersNode().getFirstChild();
    for (Node astParameter : astParameters.children()) {
      if (iifeArgumentNode != null && iifeArgumentNode.isSpread()) {
        iifeArgumentNode = null;
      }
      JSType inferredType = getJSType(astParameter);
      if (iifeArgumentNode != null) {
        if (iifeArgumentNode.getJSType() != null) {
          inferredType = iifeArgumentNode.getJSType();
        }
      } else if (parameterTypeNode != null) {
        if (parameterTypeNode.getJSType() != null) {
          inferredType = parameterTypeNode.getJSType();
        }
      }
      Node defaultValue = null;
      if (astParameter.isDefaultValue()) {
        defaultValue = astParameter.getSecondChild();
        entryFlowScope = traverse(defaultValue, entryFlowScope);
        astParameter = astParameter.getFirstChild();
      } else if (astParameter.isRest()) {
        astParameter = astParameter.getOnlyChild();
        inferredType =
            registry.createTemplatizedType(registry.getNativeObjectType(ARRAY_TYPE), inferredType);
      }
      if (defaultValue != null) {
        inferredType =
            registry.createUnionType(
                inferredType.restrictByNotUndefined(), getJSType(defaultValue));
      }
      if (astParameter.isDestructuringPattern()) {
        entryFlowScope = updateDestructuringParameter(astParameter, inferredType, entryFlowScope);
      } else {
        entryFlowScope =
            updateNamedParameter(astParameter, defaultValue != null, inferredType, entryFlowScope);
      }
      parameterTypeNode = parameterTypeNode != null ? parameterTypeNode.getNext() : null;
      iifeArgumentNode = iifeArgumentNode != null ? iifeArgumentNode.getNext() : null;
    }
    return entryFlowScope;
  }
@ SuppressWarnings ( "ReferenceEquality" ) private FlowScope inferParameters ( FlowScope entryFlowScope ) { Node functionNode = containerScope . getRootNode ( ) ; if ( ! functionNode . isFunction ( ) ) { return entryFlowScope ; } else if ( NodeUtil . isBundledGoogModuleCall ( functionNode . getParent ( ) ) ) { return entryFlowScope ; } Node astParameters = functionNode . getSecondChild ( ) ; Node iifeArgumentNode = null ; if ( NodeUtil . isInvocationTarget ( functionNode ) ) { iifeArgumentNode = functionNode . getNext ( ) ; } FunctionType functionType = JSType . toMaybeFunctionType ( functionNode . getJSType ( ) ) ; Node parameterTypeNode = functionType . getParametersNode ( ) . getFirstChild ( ) ; for ( Node astParameter : astParameters . children ( ) ) { if ( iifeArgumentNode != null && iifeArgumentNode . isSpread ( ) ) { iifeArgumentNode = null ; } JSType inferredType = getJSType ( astParameter ) ; if ( iifeArgumentNode != null ) { if ( iifeArgumentNode . getJSType ( ) != null ) { inferredType = iifeArgumentNode . getJSType ( ) ; } } else if ( parameterTypeNode != null ) { if ( parameterTypeNode . getJSType ( ) != null ) { inferredType = parameterTypeNode . getJSType ( ) ; } } Node defaultValue = null ; if ( astParameter . isDefaultValue ( ) ) { defaultValue = astParameter . getSecondChild ( ) ; entryFlowScope = traverse ( defaultValue , entryFlowScope ) ; astParameter = astParameter . getFirstChild ( ) ; } else if ( astParameter . isRest ( ) ) { astParameter = astParameter . getOnlyChild ( ) ; inferredType = registry . createTemplatizedType ( registry . getNativeObjectType ( ARRAY_TYPE ) , inferredType ) ; } if ( defaultValue != null ) { inferredType = registry . createUnionType ( inferredType . restrictByNotUndefined ( ) , getJSType ( defaultValue ) ) ; } if ( astParameter . isDestructuringPattern ( ) ) { entryFlowScope = updateDestructuringParameter ( astParameter , inferredType , entryFlowScope ) ; } else { entryFlowScope = updateNamedParameter ( astParameter , defaultValue != null , inferredType , entryFlowScope ) ; } parameterTypeNode = parameterTypeNode != null ? parameterTypeNode . getNext ( ) : null ; iifeArgumentNode = iifeArgumentNode != null ? iifeArgumentNode . getNext ( ) : null ; } return entryFlowScope ; }
Infers all of a function's parameters if their types aren't declared.
Infers all of a function ' s parameters if their types aren ' t declared .
// unknownType is a singleton // we're in the global scope // Pretend the function literal in `goog.loadModule(function(exports) {` does not exist. // This really iterates over three different things at once: //   - the actual AST parameter nodes (which may be REST, DEFAULT_VALUE, etc.) //   - the argument nodes in an IIFE //   - the parameter type nodes from the FunctionType on the FUNCTION node // Always visit every AST parameter once, regardless of how many IIFE arguments or // FunctionType param nodes there are. // 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') // 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. // must call `traverse` to correctly type the default value // e.g. `function f(p1, ...restParamName) {}` // set astParameter = restParamName // convert 'number' into 'Array<number>' for rest parameters // The param could possibly be the default type, and `undefined` args won't propagate in. // 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) // for simple named parameters, we only need to update the scope/AST if we have a new // inferred type.