-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
resolve: Make self
unhygienic
#33485
Conversation
I've made a terrible mistake!
So, yes, |
I don't think that follows from your example -- lambda captures are not bindings during name resolution, so all the |
That being said, I would prefer not to land this. I like that a macro expansion can only reference the locals used in the invocation, analogous to how a function call can only access the locals in the arguments. Also, if we landed this then it could be impossible to refactor out a closure inside a method body: impl {
fn f(&self) {
m!(); // If `m`'s expansion uses `self`, we wouldn't be able to refactor it ...
let g = |this: &Self| { // ... into this closure
m!();
};
g(self);
}
} |
That means nested closures are already subtly buggy. Consider the next example:
Both closures are supposed to capture the passed arguments and increment them by 1, so the program should print
and it indeed prints that value. Now, lets use this macro with two identical arguments:
Whoops, now the inner closure doesn't capture
|
Well, despite opening this PR, that would be my preference as well. |
Nah, it's a bad example. Even if it feels unhygienic, it's still compatible with an equivalent non-capturing example (this non-capturing example feels unhygienic too, though):
I wonder if there's another way to capture a variable, shadowed by one of its previous captures, which can be applied to |
My preference is not to make breaking changes to the macro system unless there is a very strong case. It seems everyone is in agreement to close this PR for now? |
Well, no one actually came up with a breaking example so far. |
@petrochenkov @nrc I'm pretty sure there are no breaking examples. Collecting information about lambda captures could be easily refactored into a post-processing pass after name resolution; that is, lambda captures are irrelevant to name resolution, hygiene, etc. |
☔ The latest upstream changes (presumably #33532) made this pull request unmergeable. Please resolve the merge conflicts. |
Name resolution has been moved to AST, so this implementation doesn't work anymore. |
What gives? I checked the merge request and apparently it has been merged into master. But the current file doesn't show the changes. I even cloned the repo and checked the file myself and it is unchanged. Even the history of the file doesn't show any changes 10 days ago which is when the merge supposedly happened. So where are the changes so I can work on this? |
I has not been merged. Something changed that caused this PR to be invalid. People in this thread generally either view this change as unnecessary or unhygienic. As Petro says if you want to have a go at implementing this you can submit a new PR with a new implementation, and see how the discussion goes then. |
That's not at all what I was asking about. It appears that the "Something changed that caused this PR to be invalid." merge doesn't exist in the code. |
Currently
self
behaves exactly like any other function parameter name, so hygiene rules apply to it.This patch makes it unhygienic and therefore behaving less like an usual function parameter and more like a special entity (which it already is in many other aspects).
See #15682 and rust-lang/rfcs#1606 for the motivation.
Why this is not a breaking change and why making
self
unhygienic is not so bad from the name resolution / hygene point of view.self
in value namespace1 can only be defined as a function-local binding in a function parameter.(EDIT: but see the discussion about closures below):
As a local binding it's available only in the function it's defined in. Nested items, including methods with their own
self
, can't refer to it.So, one
self
can never shadow anotherself
or create ambiguity, at any point in the code the set of scopes contains either 1self
or 0.Basically, this means that
self
either resolves correctly or not resolves at all, but it can't be resolved incorrectly.In this circumstances hygiene makes much less sense than for other local bindings.
Some part of the motivation for
self
hygiene still stays though, for example in this functionmacro
m!()
can sneakily modify contents ofself
without user passing it explicitly, i.e. unhygienicself
gives macros more abilities to create "side effects".In addition, if in the future
self
is used for something else than it is used today, the argumentation above may be invalidated.So, this needs a decision from the lang team.
1
self
in type namespace is already unhygienic and resolves to the current module.cc @jseyfried
r? @nrc