Open straight-shoota opened 3 years ago
foo { |x| x.upcase }
doesn't work either, so it would be weird if only the short blocks expand to { |x| {{ x }}.upcase }
.
Why would it be weird? The short block syntax is supposed to construct a call on the first block argument. That's what it should do, even in a macro call.
The current behaviour for macro calls is insufficient because the injected local variable (e.g. __arg0
) does not exist. The generated code is broken. We should fix that.
Alternatively, we could remove short block syntax from macro calls entirely because it's unusable.
Because then &.upcase
would have a different expansion depending on whether foo
resolves to a macro call, and the parser definitely doesn't have enough information for that.
Sure, this needs to be handled at the semantic stage when we know whether the call is for a macro or a method.
It's just a technical question of how to implement it. I don't think it should be hard to do really.
Block
could get a flag to designate it as being expanded short block syntax. The body is always a single Call
. The macro interpreter can pick up on the flag and replace the receiver of the call.
I don't think yield
with an argument is implemented well in the language. So maybe the best thing to do is to leave this feature alone, and eventually deprecate it. It's confusing.
Sry, @asterite what do you mean with "yield
with an argument"? yield foo
? I can't see what's confusing with this (or anything else we've talked about here).
The part where the block is assumed to be a macro. Usually when you call a method with a block, the block is regular Crystal, not macro code. It's very confusing.
I see. Yes, that's indeed a bit confusing.
But short block syntax actually avoids that completely if it worked like I sketched above 😆 So if we were to deprecate full block syntax for macros with arguments, short block syntax could actually serve as a practical replacement, at least for some simple use cases.
Using short block syntax with macro yield is broken because the implicit receiver is mapped to a non-existent local variable instead of the macro block argument.
It's possible to trick the compiler by sneaking in the block var like this:
This workaround is not very user-friendly and has limitations when the argument is not a literal but a fresh variable for example.