Hi Dave,
The current and old macro expanders differ on this example. I think you
can make a case for either result, but this kind of example bothers
Michael Ballantyne and William Hatch enough (on the grounds that it
should behave the old way) that they have been exploring different
notions of scope to get back the old behavior.
I don't think we've seen this specific example before, which uses a
macro defined at phase 1 to more simply provoke a difference in
expansions. Maybe Michael and William remember differently, though.
In the set of scopes model, the `x` introduced as a binding to 6 has no
extra scopes relative to the `x` introduced by the expansion of `(m2)`,
so the reference is captured by the binding. When you add `let`,
however, it introduces a scope that is not on the `x` from the
expansion of `(m2)`, so the binding to 6 doesn't capture in that case.
The mark-and-rename model of expansion, in contrast, effectively keeps
track of the order. The expansion of `(m2)` has an extra mark that
makes it ineligible for renaming by the binding of `x` to 6, even
without an extra `let` layer, so that's why the expansion of `(m2)`
produces a reference to the binding to 5.
I'm inclined to blame the discrepancy on definition contexts: the
example defines and uses `x`, `m2, and `m` all in the same definition
context, and that definition-and-use cycle creates a kind of ambiguity.
The differences that we see between the mark-and-rename and
set-of-scopes expanders are generally related to definition contexts
like that, and it's surely related to complexity in the old model [1]
that we're trying to avoid with scope sets.
Matthew
[1] Section 3.8 of "Macros that Work Together"