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

decl_macro: scoping and other issues #42448

Closed
r3c0d3x opened this issue Jun 5, 2017 · 7 comments
Closed

decl_macro: scoping and other issues #42448

r3c0d3x opened this issue Jun 5, 2017 · 7 comments
Assignees
Labels
A-macros-2.0 Area: Declarative macros 2.0 (#39412)

Comments

@r3c0d3x
Copy link

r3c0d3x commented Jun 5, 2017

The current implementation of decl_macro seems to have some issues, as shown in this example (playground):

#![feature(decl_macro)]

macro macro_ {
    () => {
        #[derive(Debug)]
        struct CreatedStruct;

        impl From<()> for CreatedStruct {
            fn from(_: ()) -> CreatedStruct {
                CreatedStruct
            }
        }
    };
}

macro_!();

fn main() {
    println!("{:?}", CreatedStruct);
}

I expected this to compile and just print out "CreatedStruct" (from its derived Debug implementation), but it throws the following errors instead:

error[E0425]: cannot find value `CreatedStruct` in this scope
  --> <anon>:19:22
   |
19 |     println!("{:?}", CreatedStruct);
   |                      ^^^^^^^^^^^^^ not found in this scope
   |
help: possible candidate is found in another module, you can import it into scope
   | fn main() use CreatedStruct;

error[E0046]: not all trait items implemented, missing: `from`
  --> <anon>:8:9
   |
8  | /         impl From<()> for CreatedStruct {
9  | |             fn from(_: ()) -> CreatedStruct {
10 | |                 CreatedStruct
11 | |             }
12 | |         }
   | |_________^ missing `from` in implementation
...
16 |   macro_!();
   |   ---------- in this macro invocation
   |
   = note: `from` from trait: `fn(T) -> Self`

error: aborting due to previous error(s)

That's strange because our example should be equivalent to this (playground):

macro_rules! macro_ {
    () => {
        #[derive(Debug)]
        struct CreatedStruct;

        impl From<()> for CreatedStruct {
            fn from(_: ()) -> CreatedStruct {
                CreatedStruct
            }
        }
    };
}

macro_!();

fn main() {
    println!("{:?}", CreatedStruct);
}

which works just fine.

The scoping issue is likely caused by whatever is causing #42337, but I'm not sure what is happening with the trait implementation.

CC @jseyfried

@jseyfried jseyfried self-assigned this Jun 5, 2017
@jseyfried
Copy link
Contributor

@r3c0d3x
This is intended behavior (see the information about hygiene in #40847).
The motivation for this is:

#![feature(decl_macro)]
macro m($f:ident) {
    #[derive(Debug)]
    struct S;
    fn $f() { println!("{:?}", S); }
}

fn main() {
    struct S; // This does not conflict with `S` from the macro
    m!(f);
    f();
}

Note that this is how local variables work today:

macro_rules! m {
    () => { let created_local = 0; }
}
fn main() {
    m!();
    println!("{}", created_local); // resolution error
}

Macros 2.0 extends this behavior to all item/fields/methods/etc., not just locals.

If you want your macro to define CreatedStruct, you have to pass it in to the macro as an argument (just like locals today):

macro m($i:ident) {
    struct $i;
}
fn main() {
    m!(CreatedStruct);
    CreatedStruct; // resolves
}

We plan to allow "opting out" of hygiene soon. @SergioBenitez has proposed using #, e.g.

macro m() {
    struct #CreatedStruct; // This is exempt from hygiene, so is usable outside the macro.
    let #created_local = 0; // Same with this local.
}
fn main() {
    m!();
    CreatedStruct; // resolves
    created_local; // resolves
}

This hasn't been implemented yet (but I'd be happy to mentor), so you'll need to pass in the ident as an argument for now.

#42337 only applies to macros from across crates (I believe it's a bug in how macros are encoded/decoded in the crate metadata, which needs improving).

@spearman
Copy link

I was getting familiar with the implementation to work on #35853 but it sounds like future work should be in macros 2.0, so I'm available to work on this.

@jseyfried
Copy link
Contributor

@spearman Great! I'm not sure this issue needs any work though -- everything is working as expected here.

@r3c0d3x @spearman did my explanation make sense? If so, I think we should close this.

@spearman
Copy link

It makes sense, but macros 2.0 won't be very useful until the opt-out syntax is implemented. I have macros that expand to several items. Without the opt-out syntax, the name of each item, their members, variants, and method impls will need to be provided as part of the macro invocation:

#![feature(decl_macro)]

macro foo($foo:ident, $bar:ident) {
  struct $foo {
    x : u8,
    y : u8
  }

  impl $foo {
    fn new (x : u8, y : u8) {
      Foo { x, y }
    }
  }

  enum $bar {
    A,
    B,
    C
  }
}

foo!{Foo,Bar}

fn main() {
  let v1 = Foo {
    x: 5, y: 4             // error: struct Foo has no fields named x,y
  };
  let v2 = Foo::new (5,4); // error: no function or associated item named new found for type Foo
  let v3 = Bar::A;         // error: no associated item named A for type Bar in this scope
}

@jseyfried
Copy link
Contributor

@spearman Agreed, I think implementing opt-out syntax should be the highest priority now that declarative macros 2.0 have landed.

@Mark-Simulacrum Mark-Simulacrum added the A-macros-2.0 Area: Declarative macros 2.0 (#39412) label Jun 23, 2017
@r3c0d3x
Copy link
Author

r3c0d3x commented Jun 30, 2017

Sorry about the late response. I understood the explanation and I probably should've looked more deeply into the functionality instead of opening an issue.

@r3c0d3x r3c0d3x closed this as completed Jun 30, 2017
@alexreg
Copy link
Contributor

alexreg commented Jan 27, 2018

@jseyfried Is anyone working on hygiene opt-out yet? If not, I'd be happy to give it a go, with your mentorship (although I admit I'm pretty inexperienced with the compiler).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-macros-2.0 Area: Declarative macros 2.0 (#39412)
Projects
None yet
Development

No branches or pull requests

5 participants