code: private boolean inferTemplatedTypesForCall(Node n, FunctionType fnType, FlowScope scope) {
      ImmutableList<TemplateType> keys = fnType.getTemplateTypeMap().getTemplateKeys();
      if (keys.isEmpty()) {
        return false;
      }
  
      // Try to infer the template types
      Map<TemplateType, JSType> rawInferrence = inferTemplateTypesFromParameters(fnType, n, scope);
      Map<TemplateType, JSType> inferred = Maps.newIdentityHashMap();
      for (TemplateType key : keys) {
        JSType type = rawInferrence.get(key);
        if (type == null) {
          type = unknownType;
        }
        inferred.put(key, type);
      }
  
      // Try to infer the template types using the type transformations
      Map<TemplateType, JSType> typeTransformations =
          evaluateTypeTransformations(keys, inferred, scope);
      if (typeTransformations != null) {
        inferred.putAll(typeTransformations);
      }
  
      // Replace all template types. If we couldn't find a replacement, we
      // replace it with UNKNOWN.
      TemplateTypeReplacer replacer = new TemplateTypeReplacer(registry, inferred);
      Node callTarget = n.getFirstChild();
  
      FunctionType replacementFnType = fnType.visit(replacer).toMaybeFunctionType();
      checkNotNull(replacementFnType);
      callTarget.setJSType(replacementFnType);
      n.setJSType(replacementFnType.getReturnType());
  
      return replacer.madeChanges;
    }
docs: For functions that use template types, specialize the function type for the call target based
  on the call-site specific arguments. Specifically, this enables inference to set the type of
  any function literal parameters based on these inferred types.