Skip to content

Add utility macros to help with writing tests. #10453

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

Merged
merged 1 commit into from
Mar 12, 2023

Conversation

Jarcho
Copy link
Contributor

@Jarcho Jarcho commented Mar 5, 2023

Adds two utility macros to help with testing:

  • external expands to it's argument tokens, but makes them appear to come from an external macro. Helps make tests for in_external_macro much more readable.
  • inline_macros is an attribute macro which allows the use of a pseudo inline! macro which expands to it's argument tokens, but makes them appear to be from a crate-local macro expansion. This removes the need to write macro_rules boilerplate when testing how lints interact with macros.

external's usage is simple. external!(struct Foo { x: u32}); will make the struct appear as though it came from an external macro. Individual tokens can be escaped if needed. external!($x + 0 / 10) will make everything except x appear as though it came from an external macro. Can also use $literal and $(tokens...) as well.


inline_macros is more complicated due to compiler constraints. Given:

#[inline_macros]
fn foo() {
    inline!(5 + 5 / 10);
}

inline!(5 + 5 / 10) will be replace with a call to a generated macro which expands to the contained tokens.

Tokens can be escaped by prefixing them with $:

#[inline_macros]
fn foo() {
    let x = 5;
    inline!($x + 5 / $10);
}

This will pass x as an ident argument and 10 as a literal argument.

Token sequences can also be passed with $(...):

#[inline_macros]
fn foo() {
    let mut x = 5;
    inline!(if $(x >= 5) {
        $x = 5;
    });
}

This will pass x >= 5 as tt arguments, and x as an ident argument.


Not 100% sure inline_macros is actually worth having. It does make the tests a little easier to read once you're used to it and it becomes more useful once there are multiple macro tests. The verbosity of declaring single use macros starts to hurt at that point.

changelog: None

@rustbot
Copy link
Collaborator

rustbot commented Mar 5, 2023

r? @dswij

(rustbot has picked a reviewer for you, use r? to override)

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Mar 5, 2023
@Alexendoo
Copy link
Member

external looks like it'd save a good amount of hassle since you have to learn about aux-build stuff to create external macro_rules currently anyway

I'm not sure about inline_macros though, I prefer looking at some macro_rules definitions in the same file even if they are annoying to write

@Jarcho
Copy link
Contributor Author

Jarcho commented Mar 6, 2023

I'm going to see if rewriting it to use the same escaping syntax external uses can work. Would make it a little less gnarly.

@Jarcho
Copy link
Contributor Author

Jarcho commented Mar 7, 2023

And done. The description has been updated for the new syntax.

@Alexendoo
Copy link
Member

Haven't tested it but an alternative mechanism for inline could be

declare_inline_macro!(inline);

fn main() {
  inline!(5 + 5 / 10);
}

Where declare_inline_macro expands to something like

// `inline_impl` being similar to `with_span`
macro_rules! inline {
    ($($tt:tt)*) => proc_macros::inline_impl!(inline $($tt)*),
}

May or may not be preferable to the attribute macro, I'm assuming proc macros can expand to macro_rules here, I know macro_rules themselves can

@Jarcho
Copy link
Contributor Author

Jarcho commented Mar 7, 2023

I'm not sure how to make that work. The tokens inside inline need to end up as part of a macro_rules expansion, but we can't create a macro_rules macro where inline appears. If proc-macros could tag tokens as coming from internal expansions this would be simpler.

@Alexendoo
Copy link
Member

Ah right of course, it's not enough to just get a span from somewhere else in the file

@bors
Copy link
Contributor

bors commented Mar 9, 2023

☔ The latest upstream changes (presumably #10467) made this pull request unmergeable. Please resolve the merge conflicts.

@Jarcho Jarcho force-pushed the test_utils branch 2 times, most recently from b2590f3 to a541584 Compare March 10, 2023 17:43
Copy link
Member

@dswij dswij left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, personally I find the changes makes things easier to read. One thing that'd be good will be having documentation on using these. There were a couple of confusions on writing tests for macro in the past, think it would be a good time to add it now.

r=me if we're adding the documentation in a separate PR.

@Jarcho Jarcho force-pushed the test_utils branch 2 times, most recently from 52990ce to 364a61e Compare March 12, 2023 20:55
@Jarcho
Copy link
Contributor Author

Jarcho commented Mar 12, 2023

Minor implementation changes. inline_macros can now be use on type, const and static items. It can also expand anywhere in the item, not just inside the block. e.g.

#[inline_macros]
fn foo<T: Into<inline!(u32)>>(x: inline!(u32)) -> inline!(u32) { ... }

The escape character for external and with_span has changed to $ to match inline.

I don't think this needs to be held back on adding it to the book. There isn't anything on testing macros to start with, and there are outstanding PRs to rewrite the documentation anyways.

@Jarcho
Copy link
Contributor Author

Jarcho commented Mar 12, 2023

@bors r=dswij

@bors
Copy link
Contributor

bors commented Mar 12, 2023

📌 Commit 1c7048d has been approved by dswij

It is now in the queue for this repository.

@bors
Copy link
Contributor

bors commented Mar 12, 2023

⌛ Testing commit 1c7048d with merge e65ad6f...

@bors
Copy link
Contributor

bors commented Mar 12, 2023

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: dswij
Pushing e65ad6f to master...

@bors bors merged commit e65ad6f into rust-lang:master Mar 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants