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

self and hygiene interact in unfortunate ways #39922

Closed
nikomatsakis opened this issue Feb 18, 2017 · 9 comments
Closed

self and hygiene interact in unfortunate ways #39922

nikomatsakis opened this issue Feb 18, 2017 · 9 comments
Assignees
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..)

Comments

@nikomatsakis
Copy link
Contributor

In this example, the code is attempting to use a macro to match generically over &self, &mut self, etc. In so doing, the self in the function signature is produced by a token-tree fragment. Unfortunately, if you do this, then self in the macro itself is considered a different self. Given that self is a keyword and not a normal variable, this seems a bit odd:

macro_rules! method {
    ($t:ty, $a:tt $($s:tt)*) => {
        impl $t {
            // To make the error go away, switch the commented code:
            // fn foo($a $($s)*) -> u32 { $($s)*.i }
            fn foo($a $($s)*) -> u32 { self.i }
        }
    };
}

struct Foo { i: u32 }

method!(Foo, &self);

fn main() {
    let mut f = Foo { i: 22 };
    f.foo();
}

Error:

error[E0424]: `self` is not available in a static method
  --> <anon>:5:40
   |
5  |             fn foo($a $($s)*) -> u32 { self.i }
   |                                        ^^^^ not available in static method
...
12 | method!(Foo, &self);
   | -------------------- in this macro invocation
   |
   = note: maybe a `self` argument is missing?

Also, the friendly error here is quite confusing.

cc @jseyfried @nrc @pnkfelix @wycats @dherman

@petrochenkov
Copy link
Contributor

Slightly different error on nightly:

rustc 1.17.0-nightly (536a900c4 2017-02-17)
error[E0424]: expected value, found module `self`
  --> <anon>:5:40
   |
5  |             fn foo($a $($s)*) -> u32 { self.i }
   |                                        ^^^^ `self` value is only available in methods with `self` parameter
...
12 | method!(Foo, &self);
   | -------------------- in this macro invocation

error: aborting due to previous error

Previous discussions: #33485 #15682 rust-lang/rfcs#1606 #34317

@jseyfried jseyfried added the A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) label Feb 19, 2017
@nikomatsakis
Copy link
Contributor Author

@petrochenkov thanks for the pointers to previous conversation. It feels like the current behavior rules out some useful constructs :/ but I can see it's a complicated question.

@jseyfried jseyfried self-assigned this Feb 22, 2017
@dherman
Copy link
Contributor

dherman commented Apr 1, 2017

I agree with @nikomatsakis that because self is a keyword it should not be renamed like a variable by the hygiene algorithm.

@jseyfried
Copy link
Contributor

jseyfried commented Apr 1, 2017

@dherman
IIUC, that would mean that the resolution of self in a macro definition would depend on where the macro is invoked. This breaks a hygiene guarantee (in the context of declarative macros 2.0).

Instead, I think we should make it more ergonomic to "opt out" of hygiene; @sergio has proposed #:

macro m() {
    #self
}
impl S {
    fn f(&self) {
        m!(); // this resolves, but wouldn't without the `#`
    }
}

macro n($e:expr) {
    impl S {
        fn f(&#self) {
            $e
        }
    }
}
n!(self /* this resolves, but wouldn't with the `#` */);

@nikomatsakis
Copy link
Contributor Author

@jseyfried can you give an example of something where the behavior would be surprising? Sorry if you've already given one =)

@jseyfried
Copy link
Contributor

@nikomatsakis sure -- I think the following would be surprising:

struct S;
impl S {
    fn f(&self) {
        m!(); // If `self` were unhygienic, this would resolve
    }
}

macro m() {
    self // the resolution of `self` here would depend on where the macro is used (i.e. not hygienic)
}

Here, m!() would be able to "silently use" a local variable (self) at the use site, which is otherwise never possible.

@nikomatsakis
Copy link
Contributor Author

@jseyfried I see. That could indeed be surprising. My example of course is somewhat different, in that the user supplies the binding. There is definitely something special about self in that it is the only way to make things that "act like" methods.

How would you phrase the macro I wrote above to make it "unhygenic"? I guess that the self.i which the macro generates might be #self.i?

@Mark-Simulacrum
Copy link
Member

@nikomatsakis I feel like discussion here leads me to believe that we don't actually want this -- should we close?

@jseyfried
Copy link
Contributor

@nikomatsakis
Yeah exactly, you could use #self.i in the macro definition

@Mark-Simulacrum I think so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..)
Projects
None yet
Development

No branches or pull requests

5 participants