Skip to content
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

Add location to result from macro method interpretation #15213

Conversation

straight-shoota
Copy link
Member

When calling a macro method, the result is typically a newly created AST node. So in most cases, the location of the AST node should be the location of the call. There are some exceptions though. Some methods don't create new nodes, they are just getters for pre-existing ones (for example: Def#body returns the AST node of the body).
So if the returned node already has a location, we should not override it. Pre-existing nodes are typically created from parsing source code and thus should be expected to have a location.
I did not verify this for all cases, so this change has some potential for injecting a false location into an existing node becuase we're mutating the stored instance without cloning it. But I don't think there's a high risk for this, nor would this have a major effect. An incorrect location is worse than no location, but not much. And the fix for both is identical: make sure the correct location is used when the node is created.

This fixes the immediate bug in #15202, not the deeper issue with AST nodes missing location info being passed to LLVM.

@straight-shoota
Copy link
Member Author

Seems like the location has much more effects on the behaviour of AST nodes than I had anticipated. It's more than just debug information, both in regular semantics as well as macro expansion.
So the absence or presence of a node location has consequences beyond just making the information available. It affects for example lookup rules and macro re-parsing.

As a result, I presume it's probably not a good idea to proceed with this proposal. Adding a location on all nodes resulting from a macro call has undesired effects on multiple language features. And I probably haven't discovered all of them yet.

These intricasies affect mostly edge cases in macro usage. I was able to catch a couple of them from building stdlib. Code bases with more extensive use of macros (such as the athena framework maybe) could help discover more issues, but even then there would be no certainty.

@straight-shoota
Copy link
Member Author

One issue are file-private objects. If a MacroId gets the location of the call it might be a different file scope than the original location and thus not be able to see file-private object. This is mostly relevant for ASTNode#id:

# macro.cr
macro m(name)
  {{ name.id }}
end
require "./call-macro"

private FOO = "foo"

m FOO # Error: undefined constant FOO (at `{{ name.id }}`)

So ASTNode#id and similar methods must always have the original location.

If the resulting nodes have no location, they'll expand right in the surrounding context. But if they have a location, the location is recorded in a list of macro expansion pragmas, and the parser recalls the original location.
For some reason having a location can also trip up the parser:

macro m(x)
 { {{ x.stringify }}: 1} # assume `x.stringify` has a location
end

m foo # Error: space not allowed between named argument name and ':' (expanded to `{ "foo": 1}`)

I'm not sure how exactly this happens, if it's an error in the parser or just missing a condition. I suppose this situation might never happen in a vanilla compiler, but I'm not sure.

@straight-shoota straight-shoota deleted the chore/macro-method-interpret-location branch November 22, 2024 22:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Module validation failed: inlinable function call in a function with debug info must have a !dbg location
1 participant