Change code back to clobber the procedure-block's parent when a
procedure is undrifted. If this is not done the operations
`block-ancestor-or-self?' and `block-nearest-common-ancestor' return
the wrong answers, and consequently must be replaced with new
operations that take the undrifting into account (yet another set of
nearly-identical operations!).
Rather than do this, I attacked the problem of why clobbering the
parent causes problems. The losing scenario seems to be as follows:
procedure A is a child of procedure B; procedure B and procedure C are
siblings; procedure A is a free-caller of procedure C (and so is
procedure B by transitivity); procedure B has drifted up one or more
blocks, while A and C have not drifted at all.
The problem occurs when A is examined before B for undrifting: because
C is not accessible from A (due to B's drifting), it is undrifted.
Later, B is also undrifted (because it is also a free-caller of C);
note that had B been undrifted before we looked at A there would have
been no reason to undrift A. Finally, `setup-block-types!' closes
both A and B because they have been undrifted, which allows them both
to reference their free variables; this reference is possible
-because- the original parent was not changed when the undrifting
occurred. Had the original parent been changed at that time, the
closing would have failed.
Now many times the only reason that A and B are being closed is
because of the undrifting -- there is really no reason for them to be
closed at all (in these cases, we would have been better off never
having tried to drift procedure A in the first place). Furthermore,
because this closing is bypassing the normal closing mechanism, some
other inconsistencies are introduced, in particular the
`virtual-closure?' bit is not cleared (it was the bug caused by this
inconsistency which forced me to reexamine this code in the first
place).
OK, so let's try this again. Suppose we -don't- close undrifted
procedures unless there's some other reason to do so (which we can
detect by looking at the `closure-context' or `closure-reasons').
Then the way to avoid the losing scenario above is to guarantee that
we undrift B before considering A for undrifting. This is easily
accomplished by performing a topological sort on the `free-callers'.
This sorting is sufficient because the decision to undrift A can only
depend on ancestors who are also members of the `free-callers' set.
So that's the story: I've added a topological sort of
`procedure-free-callers', changed `undrift-procedure!' to immediately
update the `procedure-closing-block', and changed `setup-block-types!'
to base the closing decision on `procedure-closure-context' rather
than (the now inaptly named) `close-procedure?'.