Program: 28069
Project: 28069
Buggy source:
/** 
 * For functions with function(this: T, ...) and T as parameters, type inference will set the type of this on a function literal argument to the the actual type of T.
 */
private void updateTypeOfThisOnClosure(Node n,FunctionType fnType){
  if (fnType.getTemplateTypeName() == null) {
    return;
  }
  int i=0;
  int childCount=n.getChildCount();
  for (  Node iParameter : fnType.getParameters()) {
    JSType iParameterType=getJSType(iParameter).restrictByNotNullOrUndefined();
    if (iParameterType.isTemplateType()) {
      JSType iArgumentType=null;
      if (i + 1 < childCount) {
        Node iArgument=n.getChildAtIndex(i + 1);
        iArgumentType=getJSType(iArgument).restrictByNotNullOrUndefined();
        if (!(iArgumentType instanceof ObjectType)) {
          compiler.report(JSError.make(NodeUtil.getSourceName(iArgument),iArgument,TEMPLATE_TYPE_NOT_OBJECT_TYPE));
          return;
        }
      }
      boolean foundTemplateTypeOfThisParameter=false;
      int j=0;
      for (      Node jParameter : fnType.getParameters()) {
        JSType jParameterType=getJSType(jParameter).restrictByNotNullOrUndefined();
        if (jParameterType.isFunctionType()) {
          FunctionType jParameterFnType=jParameterType.toMaybeFunctionType();
          if (jParameterFnType.getTypeOfThis().equals(iParameterType)) {
            foundTemplateTypeOfThisParameter=true;
            if (j + 1 >= childCount) {
              return;
            }
            Node jArgument=n.getChildAtIndex(j + 1);
            JSType jArgumentType=getJSType(jArgument);
            if (jArgument.getType() == Token.FUNCTION && jArgumentType.isFunctionType()) {
              if (iArgumentType != null && !iArgumentType.isNoType()) {
                FunctionType jArgumentFnType=jArgumentType.toMaybeFunctionType();
                if (jArgumentFnType.getTypeOfThis().isUnknownType()) {
                  jArgument.setJSType(registry.createFunctionTypeWithNewThisType(jArgumentFnType,(ObjectType)iArgumentType));
                }
              }
 else {
                if (NodeUtil.referencesThis(NodeUtil.getFunctionBody(jArgument))) {
                  compiler.report(JSError.make(NodeUtil.getSourceName(n),n,FUNCTION_LITERAL_UNDEFINED_THIS));
                }
              }
            }
          }
        }
        j++;
      }
      if (!foundTemplateTypeOfThisParameter) {
        compiler.report(JSError.make(NodeUtil.getSourceName(n),n,TEMPLATE_TYPE_OF_THIS_EXPECTED));
        return;
      }
    }
    i++;
  }
}

Fixed version (ground truth):
/** 
 * For functions with function(this: T, ...) and T as parameters, type inference will set the type of this on a function literal argument to the the actual type of T.
 */
private void updateTypeOfThisOnClosure(Node n,FunctionType fnType){
  if (fnType.getTemplateTypeName() == null) {
    return;
  }
  int i=0;
  int childCount=n.getChildCount();
  for (  Node iParameter : fnType.getParameters()) {
    JSType iParameterType=getJSType(iParameter).restrictByNotNullOrUndefined();
    if (iParameterType.isTemplateType()) {
      ObjectType iArgumentType=null;
      if (i + 1 < childCount) {
        Node iArgument=n.getChildAtIndex(i + 1);
        iArgumentType=getJSType(iArgument).restrictByNotNullOrUndefined().collapseUnion().toObjectType();
        if (iArgumentType == null) {
          compiler.report(JSError.make(NodeUtil.getSourceName(iArgument),iArgument,TEMPLATE_TYPE_NOT_OBJECT_TYPE,getJSType(iArgument).toString()));
          return;
        }
      }
      boolean foundTemplateTypeOfThisParameter=false;
      int j=0;
      for (      Node jParameter : fnType.getParameters()) {
        JSType jParameterType=getJSType(jParameter).restrictByNotNullOrUndefined();
        if (jParameterType.isFunctionType()) {
          FunctionType jParameterFnType=jParameterType.toMaybeFunctionType();
          if (jParameterFnType.getTypeOfThis().equals(iParameterType)) {
            foundTemplateTypeOfThisParameter=true;
            if (j + 1 >= childCount) {
              return;
            }
            Node jArgument=n.getChildAtIndex(j + 1);
            JSType jArgumentType=getJSType(jArgument);
            if (jArgument.getType() == Token.FUNCTION && jArgumentType.isFunctionType()) {
              if (iArgumentType != null && !iArgumentType.isNoType()) {
                FunctionType jArgumentFnType=jArgumentType.toMaybeFunctionType();
                if (jArgumentFnType.getTypeOfThis().isUnknownType()) {
                  jArgument.setJSType(registry.createFunctionTypeWithNewThisType(jArgumentFnType,iArgumentType));
                }
              }
 else {
                if (NodeUtil.referencesThis(NodeUtil.getFunctionBody(jArgument))) {
                  compiler.report(JSError.make(NodeUtil.getSourceName(n),n,FUNCTION_LITERAL_UNDEFINED_THIS));
                }
              }
            }
          }
        }
        j++;
      }
      if (!foundTemplateTypeOfThisParameter) {
        compiler.report(JSError.make(NodeUtil.getSourceName(n),n,TEMPLATE_TYPE_OF_THIS_EXPECTED));
        return;
      }
    }
    i++;
  }
}