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

Absurd error in a very specific case of assert_eq! inside select! #2026

Closed
Ploppz opened this issue Jan 7, 2020 · 2 comments · Fixed by #2243
Closed

Absurd error in a very specific case of assert_eq! inside select! #2026

Ploppz opened this issue Jan 7, 2020 · 2 comments · Fixed by #2243

Comments

@Ploppz
Copy link

Ploppz commented Jan 7, 2020

Making a minimal example took a while because I could not reproduce it at first due to the very narrow circumstances that triggers this error. I don't know exactly what these circumstances are but my best guess is assert_eq! inside futures::select!. (however only when asserting equivalence of bools and not Strings, as explained further down.

Cargo.toml

[package]
name = "reproduce"
version = "0.1.0"
authors = ["Erlend Langseth <3rledhl@gmail.com>"]
edition = "2018"

[dependencies]
# Actix
actix-web = "2.0"
actix-rt = "1.0.0"
actix-http = "1.0.0"

# Serde
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

# Other
futures = "0.3.1"

src/main.rs

use actix_http::http::StatusCode;
use futures::{FutureExt, select};
use serde::{Serialize, Deserialize};
use actix_web::{
    test::TestServer,
    App
};
use std:: time::Duration;

#[derive(Serialize, Deserialize)]
struct Foo {
    a: String,
}
impl Foo {
    pub fn get_id(&self) -> &str {
        &self.a
    }
    pub fn is_success(&self) -> bool {
        true
    }
}

macro_rules! response_to_string {
    ($response:expr) => {
        std::str::from_utf8($response.body().await.unwrap().as_ref())
            .unwrap()
            .to_string()
    };
}
macro_rules! assert_status {
    ($response:expr, $expected_status:expr) => {
        if $response.status() != $expected_status {
            panic!(
                "Expected status {:?}, got {:?}.\nBODY:{}",
                $expected_status,
                $response.status(),
                response_to_string!($response)
            );
        }
    }
}

macro_rules! create_test_server {
    ($srv:ident) => {
        let $srv = actix_web::test::start({
            move || App::new()
        });
    };
}


async fn poll_operation_until_done(id: String, srv: &TestServer) -> Foo {
    loop {
        // now, poll operation
        let mut response = srv.get(format!("/admin/v1/operations/{}", id))
            .send() .await.unwrap();
        match response.status() {
            StatusCode::OK => {
                return response.json::<Foo>().await.unwrap();
            }
            StatusCode::NOT_FOUND => {
                // ok -  not finished yet
            }
            status => panic!("Unexpected HTTP status code {}", status)
        }
        // assert_status!(response, StatusCode::OK);
        actix_rt::time::delay_for(Duration::from_millis(60)).await;
    }
}

#[actix_rt::test]
async fn test_delete_articles() {
    create_test_server!(srv);

    macro_rules! run_test {
        ($should_succeed:expr) => {
            let mut response = srv.post("/api/v1/lala")
                .send_json(&Foo {a: "abc".to_string()}).await.unwrap();
            assert_status!(response, StatusCode::OK);
            
            let id = response.json::<Foo>().await.unwrap().get_id().to_owned();

            select! {
                op_info = poll_operation_until_done(id, &srv).fuse() =>
                    assert_eq!(op_info.is_success(), $should_succeed), // line 85
                _ = actix_rt::time::delay_for(Duration::from_secs(30)).fuse() =>
                    panic!("timeout reached")
            }
        }
    }
    run_test!(false);
}

fn main() {
}

Running it with cargo c --tests we get the error

error[E0425]: cannot find value `id` in this scope
  --> src/main.rs:91:5
   |
91 |     run_test!(false);
   |     ^^^^^^^^^^^^^^^^^
   |     |
   |     not found in this scope
   |     in this macro invocation
   |
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
help: possible candidate is found in another module, you can import it into scope
   |
1  | use std::process::id;
   |

(look below for more output)

Now... a small change I found that could fix this error is to replace line 85 (annotated with a comment) with assert_eq!(op_info.a, "heyhey"),.
So definitely something strange is going on - this line doesn't even have anything to do with id.

Appendix

Maybe it's useful with the output of

RUSTFLAGS="-Z external-macro-backtrace" cargo c --tests
error[E0425]: cannot find value `id` in this scope
   --> <::futures_util::async_await::select_mod::select macros>:4:20
    |
1   |                           /  ($ ($ proc_macro : tt) *) =>
2   |                           |  {
3   |                           |      {
4   |                           |          # [derive ($ crate :: proc_macro_hack_select)] enum ProcMacroHack
    |                           |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                           |                     |
    |                           |                     not found in this scope
    |                           |                     in this expansion of `proc_macro_call_2!` (#28)
5   |                           |          { Nested = (stringify ! { $ ($ proc_macro) * }, 0) . 1, } $ crate ::
    |  _________________________|____________________________________________________________________-
6   | |                         |          proc_macro_call_select ! { ($ ($ proc_macro) *) }
    | |_________________________|__________________________________________________________- in this macro invocation (#4)
7   |                           |      }
8   |                           |  } ;
    |                           |____- in this expansion of `$crate::inner_macro::select!` (#3)
    | 
   ::: src/main.rs:75:5
    |
75  | /                                macro_rules! run_test {
76  | |                                    ($should_succeed:expr) => {
77  | |                                        let mut response = srv.post("/api/v1/lala")
78  | |                                            .send_json(&Foo {a: "abc".to_string()}).await.unwrap();
...   |
83  | /                                        select! {
84  |                                              op_info = poll_operation_until_done(id, &srv).fuse() =>
85  |                                                  assert_eq!(op_info.is_success(), $should_succeed),
86  |                                              _ = actix_rt::time::delay_for(Duration::from_secs(30)).fuse() =>
87  |                                                  panic!("timeout reached")
88  | |                                        }
    | |________________________________________- in this macro invocation (#2)
89  | |                                    }
90  | |                                }
    | |________________________________- in this expansion of `run_test!` (#1)
91  |                                  run_test!(false);
    |                                  ----------------- in this macro invocation (#1)
    | 
   ::: <::proc_macro_nested::dispatch macros>:1:29
    |
1   |                              (() $ ($ bang : tt) *) => { $ crate :: count ! ($ ($ bang) *) } ;
    |                              -                           --------------------------------- in this macro invocation (#27)
    |     _________________________|
    |    |
2   |    |                         ((($ ($ first : tt) *) $ ($ rest : tt) *) $ ($ bang : tt) *) =>
3   |    |                         { $ crate :: dispatch ! (($ ($ first) * $ ($ rest) *) $ ($ bang) *) } ;
    |    |                           -----------------------------------------------------------------
    |    |                           |
    |    |                           in this macro invocation (#5)
    |    |                           in this macro invocation (#7)
    |    |                           in this macro invocation (#9)
    |    |                           in this macro invocation (#13)
    |    |                           in this macro invocation (#15)
    |    |                           in this macro invocation (#17)
    |    |                           in this macro invocation (#19)
    |    |                           in this macro invocation (#21)
    |    |                           in this macro invocation (#25)
4   |    |                         (([$ ($ first : tt) *] $ ($ rest : tt) *) $ ($ bang : tt) *) =>
...      |
9   |    |                         { $ crate :: dispatch ! (($ ($ rest) *) $ ($ bang) * !) } ;
    |    |                           -----------------------------------------------------
    |    |                           |
    |    |                           in this macro invocation (#12)
    |    |                           in this macro invocation (#24)
...      |
12  |    |                         (($ first : tt $ ($ rest : tt) *) $ ($ bang : tt) *) =>
13  |    |                         { $ crate :: dispatch ! (($ ($ rest) *) $ ($ bang) *) } ;
    |    |                           ---------------------------------------------------   -
    |    |                           |                                                     |
    |    |                           |                                                     in this expansion of `$crate::proc_macro_call_select!` (#4)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#5)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#6)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#7)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#8)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#9)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#10)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#11)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#12)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#13)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#14)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#15)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#16)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#17)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#18)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#19)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#20)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#21)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#22)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#23)
    |    |                           |                                                     in this expansion of `$crate::dispatch!` (#24)
    |    |___________________________|_____________________________________________________in this expansion of `$crate::dispatch!` (#25)
    |                                |                                                     in this expansion of `$crate::dispatch!` (#26)
    |                                in this macro invocation (#6)
    |                                in this macro invocation (#8)
    |                                in this macro invocation (#10)
    |                                in this macro invocation (#11)
    |                                in this macro invocation (#14)
    |                                in this macro invocation (#16)
    |                                in this macro invocation (#18)
    |                                in this macro invocation (#20)
    |                                in this macro invocation (#22)
    |                                in this macro invocation (#23)
    |                                in this macro invocation (#26)
    | 
   ::: <::proc_macro_nested::count macros>:1:1
    |
1   |   /                          () => { proc_macro_call_0 ! () } ; (!) => { proc_macro_call_1 ! () } ; (! !)
2   |   |                          => { proc_macro_call_2 ! () } ; (! ! !) => { proc_macro_call_3 ! () } ;
    |   |                               ---------------------- in this macro invocation (#28)
3   |   |                          (! ! ! !) => { proc_macro_call_4 ! () } ; (! ! ! ! !) =>
4   |   |                          { proc_macro_call_5 ! () } ; (! ! ! ! ! !) => { proc_macro_call_6 ! () } ;
...     |
104 |   |                           ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !) =>
105 |   |                          { proc_macro_call_64 ! () } ;
    |   |______________________________________________________- in this expansion of `$crate::count!` (#27)
    | 
   ::: <::futures::select macros>:1:1
    |
1   |                            / ($ ($ tokens : tt) *) =>
2   |                            | {
3   |                            |     $ crate :: inner_macro :: select !
    |  __________________________|_____-
4   | |                          |     { futures_crate_path (:: futures) $ ($ tokens) * }
    | |__________________________|______________________________________________________- in this macro invocation (#3)
5   |                            | }
    |                            |_- in this expansion of `select!` (#2)
    |
help: possible candidate is found in another module, you can import it into scope
    |
1   | use std::process::id;
    |

error: aborting due to previous error

For more information about this error, try `rustc --explain E0425`.
error: could not compile `reproduce`.
@Ploppz
Copy link
Author

Ploppz commented Jan 8, 2020

Seems like it's not due to assert_eq! at all but rather the usage of $should_succeed that determines whether or not the error happens.

@taiki-e
Copy link
Member

taiki-e commented Oct 1, 2020

This will probably be fixed by dtolnay/proc-macro-hack#62. (Rust 1.45+)

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.

2 participants