-
Notifications
You must be signed in to change notification settings - Fork 416
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Detect circular macro expansion #2767
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn’t it be simpler to just maintain a stack of expanded macros, add a macro’s name to it whenever we are inside its expansion and then pop it again afterwards? And if we try to expand a macro that’s in that list, emit an error?
c7c9704
to
5552efc
Compare
Do you consider a tail-recursive macro whose expansion eventually terminates to be bannable? I think we have to be very careful about what counts as non-productive recursion. |
Now you're approaching the territory of a termination checker. I suggest tracking expansions with a stack as suggested, but rather than query the stack let's use it to install a reasonable depth limit and call it a day - dumping the stack for diagnostics if need be. The full scope of efficiently rejecting general recursion in programs is an open area of research 😓 |
Unfortunately, I'm not sure what this number should be, and it seems neither do our peer compilers. |
@ahoppen and I have discussed in #2018 that recursive macro expansion is currently prohibited by the compiler. Notwithstanding, I think determining whether a tail-recursive macro will eventually terminate is akin to the halting problem? |
5552efc
to
ca32bff
Compare
I see, well then that is really quite restrictive and I do disagree with it but I defer to Alex on this one.
Absolutely, but there is a lot of research in restricted forms of termination checking, mostly in service of proof assistants. There, you're absolutely willing to sacrifice a certain class of (often, ill-typed anyways) terms that will happen to halt but that your termination checker can't really prove. There's heuristics like syntactic decrease all the way up to stuff like Andreas Abel's research on termination checking for Agda which reduces inter-procedural analysis to a series of matrix multiplies. It's really neat stuff! That said, if you peek around production compilers with different forms of macro evaluation, you'll see they all implement some kind of arbitrary expansion depth limit and usually some kind of compiler flag to allow you to raise or lower it as needed. It's all kinda gnarly. |
To be clear, we currently have the restriction that a macro can’t expand to itself in the compiler. And this PR is just implementing the same behavior in MacroSystem, which is used for
Did you address this comment yet, @AppAppWorks? I couldn’t find anything related to it in your latest commits. Just checking that we’re not mutually waiting for each other. |
1bdf205
to
2e694a1
Compare
I've just reverted to a previous commit as well as corrected the sites of stack popping, more precisely we now only pop a macro type name from the stack whenever such freestanding macro has been fully expanded. |
|
True, I'll put some more thought into refactoring. |
2e694a1
to
394075d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW the compiler also emits an error if an attached macro is recursively expanded in the same role. https://github.com/swiftlang/swift/blob/454dfb9a0b19917a64e2ecda31e714203a05231e/lib/Sema/TypeCheckMacros.cpp#L1364-L1369
I think it would be good to implement that in MacroSystem as well but that doesn’t have to be this PR.
I wrote this in #2018,
Should the upcoming PR also solve this incoherent behaviour across different types of attached macros? |
Yes, let’s do a separate PR for that. |
8e2bca3
to
0489d74
Compare
0489d74
to
9c800f9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking great
@swift-ci Please test |
@swift-ci Please test Windows |
Could you run swift-format? https://github.com/swiftlang/swift-syntax/blob/main/CONTRIBUTING.md#formatting |
- `MacroApplication` now detects any freestanding macro that appears on an expansion path more than once and throws `MacroExpansionError.recursiveExpansion` - added a test case in `ExpressionMacroTests` rdar://113567654 Fixes swiftlang#2018
Head branch was pushed to by a user without write access
9c800f9
to
6edc2e1
Compare
Formatted, please test again. |
@swift-ci Please test |
@swift-ci Please test Windows |
fixes #2018