Switch how iteratorExpr is replaced

Previously for non-zippered iterators we did a simple pointer assignment. We
have doubts as to whether the dead AST node actually gets cleaned up (will
investigate at a later time.) Then for zippered iterators we did checks to see
if we had a new iterator and if so called replace() on iteratorExpr.

To avoid any GC issues for this patch, this updates the functions to always
replace the itratorExpr if a direct iterator is being used. It pushes the
replace into the tryToUseDirectRangeIterator() function. This eliminates the
(duplicate) code in optimizeAnonymousRangeIteration() that checked if the
iterator has been replaced.

Calling replace() requires that the AST node have a parent expr. Since we're so
early in compilation the iteratorExpr for non-zippered cases didn't have a
parentExpr where it was originally called, so I moved it to be called after
it's inserted into other AST nodes.

I think this is a nice code cleanup, and means regardless of other GC issues we
have to consider, this patch doesn't introduce any more.

Because replace now happens in tryToReplaceWithDirectRangeIterator(), this
means the two functions are now void instead of returning (a usually unchanged)
iteratorExpr