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 in locally defined macro doesn't get rewritten #68

Closed
athre0z opened this issue Feb 10, 2020 · 3 comments · Fixed by #78
Closed

self in locally defined macro doesn't get rewritten #68

athre0z opened this issue Feb 10, 2020 · 3 comments · Fixed by #78

Comments

@athre0z
Copy link
Sponsor

athre0z commented Feb 10, 2020

Hi there and thanks for the great lib!

I just noticed that self, when referenced from a locally defined macro, is not correctly rewritten to _self.

#[async_trait::async_trait]
trait Magic {
    async fn foo(&self);
}

struct Bar {
    x: i32,
}

#[async_trait::async_trait]
impl Magic for Bar {
    async fn foo(&self) {
        macro_rules! ref_self {
            () => {
                // reference self somehow
                let _x = self.x;
            }
        }

        ref_self!();
    }
}

fn main() {}

expands to

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
trait Magic {
    fn foo<'life0, 'async_trait>(
        &'life0 self,
    ) -> ::core::pin::Pin<
        Box<dyn ::core::future::Future<Output = ()> + ::core::marker::Send + 'async_trait>,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait;
}
struct Bar {
    x: i32,
}
impl Magic for Bar {
    fn foo<'life0, 'async_trait>(
        &'life0 self,
    ) -> ::core::pin::Pin<
        Box<dyn ::core::future::Future<Output = ()> + ::core::marker::Send + 'async_trait>,
    >
    where
        'life0: 'async_trait,
        Self: 'async_trait,
    {
        #[allow(
            clippy::missing_docs_in_private_items,
            clippy::type_repetition_in_bounds,
            clippy::used_underscore_binding
        )]
        async fn __foo(_self: &Bar) {
            let _x = self.x;
        }
        Box::pin(__foo(self))
    }
}
fn main() {}

resulting in

error[E0434]: can't capture dynamic environment in a fn item
  --> src/main.rs:16:26
   |
16 |                 let _x = self.x;
   |                          ^^^^
...
20 |         ref_self!();
   |         ------------ in this macro invocation
   |
   = help: use the `|| { ... }` closure form instead

Currently, I just work around this by just passing it in as $self:ident.

@athre0z athre0z changed the title self in locally defined macro doesn't get rewritten to _self self in locally defined macro doesn't get rewritten Feb 10, 2020
@thomaseizinger
Copy link

I just updated to the latest version but this is still a problem for me in the case where macro_rules defines a trait implementation that uses async_trait.

The following code fails to compile:

fn main() {
    let _ = Bar.foo();
}

#[async_trait::async_trait]
trait Foo {
    async fn foo(&self);
}

macro_rules! impl_foo {
    ($target:ty) => {
        #[async_trait::async_trait]
        impl Foo for $target {
            async fn foo(&self) {

            }
        }
    };
}

struct Bar;

impl_foo!(Bar);

It expands to (using cargo expand):

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
fn main() {
    let _ = Bar.foo();
}
trait Foo {
    #[must_use]
    fn foo<'life0, 'async_trait>(
        &'life0 self,
    ) -> ::core::pin::Pin<
        Box<dyn ::core::future::Future<Output = ()> + ::core::marker::Send + 'async_trait>,
    >
        where
            'life0: 'async_trait,
            Self: 'async_trait;
}
struct Bar;
impl Foo for Bar {
    fn foo<'life0, 'async_trait>(
        &'life0 self,
    ) -> ::core::pin::Pin<
        Box<dyn ::core::future::Future<Output = ()> + ::core::marker::Send + 'async_trait>,
    >
        where
            'life0: 'async_trait,
            Self: 'async_trait,
    {
        #[allow(
        clippy::missing_docs_in_private_items,
        clippy::type_repetition_in_bounds,
        clippy::used_underscore_binding
        )]
        async fn __foo(_self: &Bar) {}
        Box::pin(__foo(self))
    }
}

Interestingly this compiles if you remove the prelude import stuff 🤔
Is there a different between what cargo expand and what rustc does?

@dtolnay
Copy link
Owner

dtolnay commented Mar 30, 2020

That one is a rustc bug: #46 / rust-lang/rust#43081.

@dtolnay
Copy link
Owner

dtolnay commented Mar 30, 2020

You should be able to work around it by using $target:tt or $($target:tt)* instead of $target:ty.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants