transformLoop_(func, tree, loopFactory) {
    let scope, initializerIsBlockBinding;
    if (tree.initializer &&
        tree.initializer.type === VARIABLE_DECLARATION_LIST &&
        tree.initializer.declarationType !== VAR) {
      initializerIsBlockBinding = true;
    }

    if (initializerIsBlockBinding) {
      scope = this.pushScope(tree);
    }

    // We only create an "iife" if the loop has block bindings and functions
    // that use those block binded variables
    let finder = new FindBlockBindingInLoop(tree, this.scopeBuilder_);
    finder.visitAny(tree);
    if (!finder.found) {
      let callFunc = () => {
        let currentLoopTree = this.currentLoopTree_;
        this.currentLoopTree_ = tree
        let rv = func(tree);
        this.currentLoopTree_ = currentLoopTree;
        return rv;
      };

      if (!initializerIsBlockBinding) {
        return callFunc();
      }

      // just switch it to var
      let renames = [];
      let initializer = new VariableDeclarationList(null, VAR,
          tree.initializer.declarations.map((declaration) => {
              let origName = this.getVariableName_(declaration);
              let newName = this.newNameFromOrig(origName, renames);

              let bindingIdentifier = createBindingIdentifier(newName);
              this.scope_.renameBinding(origName, bindingIdentifier,
                  VAR, this.reporter_);
              return new VariableDeclaration(null,
                  bindingIdentifier, null, declaration.initializer);
            }
          ));
      initializer = renameAll(renames, initializer);

      tree = loopFactory(initializer, renames, renameAll(renames, tree.body));
      this.revisitTreeForScopes(tree);
      tree = callFunc();

    } else {
      let iifeParameterList = [];
      let iifeArgumentList = [];
      let renames = [];
      let initializer = null;
      // switch to var and rename variables, holding them in potential
      // iife argument/parameter list
      if (tree.initializer) {
        if (tree.initializer.type === VARIABLE_DECLARATION_LIST &&
            tree.initializer.declarationType !== VAR) {
          initializer = new VariableDeclarationList(null, VAR,
              tree.initializer.declarations.map((declaration) => {
                let origName = this.getVariableName_(declaration);
                let newName = this.newNameFromOrig(origName, renames);

                iifeArgumentList.push(createIdentifierExpression(newName));
                iifeParameterList.push(new FormalParameter(null,
                    new BindingElement(null,
                        createBindingIdentifier(origName), null), null, []));

                let bindingIdentifier = createBindingIdentifier(newName);
                this.scope_.renameBinding(origName, bindingIdentifier,
                    VAR, this.reporter_);
                return new VariableDeclaration(null,
                    bindingIdentifier, null, declaration.initializer);
              }));

          initializer = renameAll(renames, initializer);
        } else  {
          initializer = this.transformAny(tree.initializer);
        }
      }

      // the loop might already have a label, let's keep it with us
      let loopLabel = this.labelledLoops_.get(tree);

      let iifeInfo = FnExtractAbruptCompletions.createIIFE(
          this.idGenerator_, tree.body, iifeParameterList, iifeArgumentList,
          () => {
            return loopLabel = loopLabel || createIdentifierToken(
                this.idGenerator_.generateUniqueIdentifier());
          }, this.scope_.inGenerator);

      tree = loopFactory(initializer, renames, iifeInfo.loopBody);

      if (loopLabel) {
        tree = new LabelledStatement(tree.location, loopLabel, tree);
      }

      tree = new AnonBlock(tree.location, [iifeInfo.variableStatements, tree]);

      this.revisitTreeForScopes(tree);
      tree = this.transformAny(tree);
    }

    if (initializerIsBlockBinding) {
      tree = this.flushRenames(tree);
      this.popScope(scope);
    }
    return tree;
  }
@param func a function that continues the transform of the loop
@param tree the loop tree
@param loopFactory a function that recreates the loop with a provided
   initializer, a set of renames for the loop headers, and a loop body
@returns {ParseTree}