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

RA getting confused on the combo of test_log::test and ntest::timeout #11109

Open
zeenix opened this issue Dec 23, 2021 · 7 comments
Open

RA getting confused on the combo of test_log::test and ntest::timeout #11109

zeenix opened this issue Dec 23, 2021 · 7 comments

Comments

@zeenix
Copy link

zeenix commented Dec 23, 2021

Since a few weeks, RA is giving me Expected identifier! error on all ntest::timeout macro usage in my code, when used together with test_log::test macro (see screenshot). Since I'm using this comb in most of my tests, that's quite many errors so it's hard to see how many real errors I got.

Screenshot from 2021-12-23 16-11-33

I can reproduce in both VS Code and vim.

rust-analyzer version: 0add6e9 2021-12-20 stable (but I get the same with: 4ea1f58 2021-12-23 nightly).

rustc version: v1.56.1

@azewierzejew
Copy link

azewierzejew commented Jan 13, 2022

As far as I've tested it's release 2021-11-22 183ef04 that breaks this. 2021-11-15 still works for me.

@mati865
Copy link
Contributor

mati865 commented Jul 18, 2023

I think this is an upstream ntest issue that should be fixed by becheran/ntest#23

@mati865
Copy link
Contributor

mati865 commented Jul 20, 2023

The crash is no more with becheran/ntest#23 (there is no release yet) but run/debug annotations are still missing: becheran/ntest#18

I've tried to debug it but the investigation led me to parts of RA that are rather hard to follow for somebody who is not familiar with them.
One of the things I'm fairly confident in and could help somebody more experiences for this code:

#[test]
fn some_test() {
    ()
}

#[test]
#[ntest_timeout::timeout(1000)]
fn some_other_test() {
    ()
}

For some_test, raw_attrs from crates/hir-def/src/item_tree.rs return:

RawAttrs {
    entries: Some(
        [
            Attr {
                id: AttrId {
                    id: 0,
                },
                path: ModPath {
                    kind: Plain,
                    segments: [
                        Name(
                            Text(
                                "test",
                            ),
                        ),
                    ],
                },
                input: None,
            },
        ],
    ),
}

So is_test() later on returns true but for some_other_test we get:

RawAttrs {
    entries: None,
}

causing is_test() to return false.

I doubt I'll have some much more time to spend on this issue so hopefully somebody comes up with an idea what is wrong or how to debug it.

@HKalbasi
Copy link
Member

If I understand correctly, ntest uses #[rustc_test_marker] instead of the usual #[test] which r-a doesn't support. Does ntest work on stable?
And it might be hard to support that, since it is applied on an item but affects a different item.

@mati865
Copy link
Contributor

mati865 commented Jul 21, 2023

If I understand correctly, ntest uses #[rustc_test_marker] instead of the usual #[test] which r-a doesn't support.

I think this is just cargo-expand expanding #[test], please see expansion below "Without using the timeout macro it would have expanded to:" in becheran/ntest#18 (comment)

Does ntest work on stable?

Yes.


Don't know if it's relevant but I should have mentioned it, when RA initially parses the code it sees attribute macros. This is the same raw_attrs call from item_tree.rs for the test marked with #[ntest_timeout...]:

Details
RawAttrs {
    entries: Some(
        [
            Attr {
                id: AttrId {
                    id: 0,
                },
                path: ModPath {
                    kind: Plain,
                    segments: [
                        Name(
                            Text(
                                "test",
                            ),
                        ),
                    ],
                },
                input: None,
            },
            Attr {
                id: AttrId {
                    id: 1,
                },
                path: ModPath {
                    kind: Plain,
                    segments: [
                        Name(
                            Text(
                                "ntest_timeout",
                            ),
                        ),
                        Name(
                            Text(
                                "timeout",
                            ),
                        ),
                    ],
                },
                input: Some(
                    TokenTree(
                        (
                            SUBTREE () 0 4294967295
                              LITERAL 1000 1,
                            TokenMap {
                                entries: [
                                    (
                                        0,
                                        Delimiter(
                                            0..6,
                                        ),
                                    ),
                                    (
                                        1,
                                        Token(
                                            1..5,
                                        ),
                                    ),
                                ],
                                synthetic_entries: [],
                            },
                        ),
                    ),
                ),
            },
        ],
    ),
}

So RA will always (during initial parsing and when working with code) get correct RawAttrs for standard test but for the test decorated with ntest_timeout initial parsing (raw_attrs is actually called twice and both time it gives the attributes) will show all the attributes but after that subsequent calls to raw_attrs will just return entries: None.

@HKalbasi
Copy link
Member

What Expand macro recursively action of rust-analyzer gives with and without the timeout macro?

@mati865
Copy link
Contributor

mati865 commented Jul 21, 2023

  • just test
#[test]
fn some_test() {
    ()
}

gives:
Not available

  • ntest
#[test]
#[ntest_timeout::timeout(1000)]
fn some_other_test() {
    ()
}

gives:

// Recursive expansion of timeout macro
// =====================================

fn some_other_test() {
    fn ntest_callback() {
        ()
    }
    let ntest_timeout_now = std::time::Instant::now();
    let (sender, receiver) = std::sync::mpsc::channel();
    std::thread::spawn(move || if let Ok(()) = sender.send(ntest_callback()) {});
    match receiver.recv_timeout(std::time::Duration::from_millis(1000u64)) {
        Ok(t) => return t,
        Err(std::sync::mpsc::RecvTimeoutError::Timeout) => panic!(
            "timeout: the function call took {} ms. Max time {} ms",
            ntest_timeout_now.elapsed().as_millis(),
            1000u64
        ),
        Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => panic!(),
    }
}
  • tokio, not apples to apples comparison because tokio::test replaces #[test] while ntest::timeout is an addition to either of them
#[tokio_macros::test]
async fn some_another_test() {
    ()
}

gives:

// Recursive expansion of test macro
// ==================================

#[::core::prelude::v1::test]
fn some_another_test() {
    let body = async { () };
    tokio::pin!(body);
    let body: ::std::pin::Pin<&mut dyn ::std::future::Future<Output = ()>> = body;
    #[allow(clippy::expect_used, clippy::diverging_sub_expression)]
    {
        return tokio::runtime::Builder::new_current_thread()
            .enable_all()
            .build()
            .expect("Failed building the Runtime")
            .block_on(body);
    }
}

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

No branches or pull requests

4 participants