alma
alma copied to clipboard
Disallow using macro expansion to create lexical lookups outside of the code's environment
After my recent insights in how variable lookup needs to work in injectiles, I've been trying to test whether the rule of "injectile variables are always direct, mainline variables are always lookup" is enough. In doing so, I came up with this code:
my q;
macro m1(expr) {
q = expr;
}
macro m2() {
return q;
}
for [1, 2, 3] -> v {
m1(v);
}
for [4, 5, 6] -> v {
say(m2());
}
Current 007 outputs 4\n5\n6
. I believe it should output 3\n3\n3\n
, if it outputs anything.
After some discussion on #perl6, we have tentatively concluded it should probably be an expansion-time error. I'm somewhat relieved at this.
So as things stand, this is a bug because 007 currently allows this when it shouldn't.
I was going to drop in here and say that it fits nicely with the things later described in #410. But then I looked at the example and had to pause a bit.
#410 doesn't mention the thing going on here, but I think it fits well with its world view. The v
that's being sent into m1
here is being reintegrated by m2
into another scope... one which can't see that original v
declaration. And that should be enough to throw the needed exception.
And that should be enough to throw the needed exception.
Should it, really? Isn't the "can't see the original declaration" criterion the one we wanted to use for regular macro hygiene stuff?
I call bullsh my old self confused (as usual), and I'm back to wanting the behavior of OP to be 3\n3\n3\n
.
And that should be enough to throw the needed exception.
Should it, really? Isn't the "can't see the original declaration" criterion the one we wanted to use for regular macro hygiene stuff?
Still don't know whether this is a good idea, but...
...there is one thing that could distinguish the v
here from regular macro hygiene stuff. Namely, the v
sent to m1
was uniquified as part of macro argument detachment, whereas in regular macro hygiene, variables are uniquified as part of quasiquote detachment.
My current status: happy and a little bit relieved that there actually is a distinction after all (and so it would probably be possible to throw an exception in this case), but not at all sure yet that it's a good idea to make the distinction.
In some sense, there are three types of code:
- (a) mainline code that hasn't been managed by macros at all;
- (b) code that originates from inside a quasi;
- (c) mainline code that was passed through macro processing because it was an "argument" (in a more or less strict sense) to a macro.
If we can distinguish (b)-uniquified variables from (c)-uniquified variables, we might be able to throw an exception only for (c)-uniquified variables that, when re-integrated, can't see their original declaration.
...the rationale for this difference in treatment being that (b)-style code "knows what it's doing" playing with fire^Wdetached lexical lookups, whereas (c)-style code is by its definition hapless, acted-upon, and in all ways an NPC. Allowing (c)-style code to make such an advanced lookup when it's not even privy to macro/quasi technology would be tantamount to letting a bunch of energetic children into a fireworks factory, while handing them a box of matches.