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

proc_macro: Use ToTokens trait in quote macro #134693

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

SpriteOvO
Copy link
Contributor

@SpriteOvO SpriteOvO commented Dec 23, 2024

Tracking issues: #130977, #54722

This PR changed quote macro to use ToTokens trait instead of TokenStream::from, and added a test case for directly referencing an individual token.

r? @dtolnay
CC @tgross35

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 23, 2024
@rust-log-analyzer

This comment has been minimized.

@SpriteOvO SpriteOvO force-pushed the proc-macro-use-to-tokens-in-quote branch from 519aec5 to 0b32dec Compare December 23, 2024 18:02
@tgross35
Copy link
Contributor

Thanks for working on this!

Could you update the new test file with applicable tests from https://github.com/dtolnay/quote/blob/aafba72e10919ad47c05169271cb78e614fb2b9d/tests/test.rs? Because of token stream limitations we can't actually mark them #[test] or add the assert! (eventually we will, this should be a FIXME), but keeping the quote! invocations at least allows us to verify that the expected things do quote.

We can probably reuse the UI tests from https://github.com/dtolnay/quote/tree/aafba72e10919ad47c05169271cb78e614fb2b9d/tests/ui too. I think you can just make a new tests/ui/proc-macro/quote directory.

@tgross35 tgross35 added A-proc-macros Area: Procedural macros WG-macros Working group: Macros T-libs Relevant to the library team, which will review and decide on the PR/issue. and removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Dec 23, 2024
@dtolnay dtolnay added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 27, 2024
@SpriteOvO SpriteOvO force-pushed the proc-macro-use-to-tokens-in-quote branch from 0b32dec to 7e77f06 Compare January 4, 2025 01:54
@SpriteOvO
Copy link
Contributor Author

I have updated the PR for the macro implementation, and I will migrate the test cases from quote crate later.

@rust-log-analyzer

This comment has been minimized.

@SpriteOvO SpriteOvO force-pushed the proc-macro-use-to-tokens-in-quote branch from 7e77f06 to 5d0a6c5 Compare January 4, 2025 02:21
@rust-log-analyzer

This comment has been minimized.

@SpriteOvO SpriteOvO force-pushed the proc-macro-use-to-tokens-in-quote branch from 5d0a6c5 to 858ad51 Compare January 4, 2025 16:51
@rustbot
Copy link
Collaborator

rustbot commented Jan 4, 2025

Some changes occurred in src/tools/clippy

cc @rust-lang/clippy

@SpriteOvO SpriteOvO force-pushed the proc-macro-use-to-tokens-in-quote branch from 858ad51 to 6404cf5 Compare January 5, 2025 22:50
@SpriteOvO
Copy link
Contributor Author

SpriteOvO commented Jan 8, 2025

I'm working on migrating the applicable tests from https://github.com/dtolnay/quote/blob/0245506323a3616daa2ee41c6ad0b871e4d78ae4/tests/test.rs. It seems like the current proc_macro::quote! is still incomplete? Some features (quote_spanned!, format_ident!, repetition) are still not implemented, because of that many test cases cannot be migrated.

// - quote_spanned:
//   - fn test_quote_spanned_impl
//   - fn test_type_inference_for_span
// - format_ident:
//   - fn test_format_ident
//   - fn test_format_ident_strip_raw
// - repetition:
//   - fn test_iter
//   - fn test_array
//   - fn test_fancy_repetition
//   - fn test_nested_fancy_repetition
//   - fn test_duplicate_name_repetition
//   - fn test_duplicate_name_repetition_no_copy
//   - fn test_btreeset_repetition
//   - fn test_variable_name_conflict
//   - fn test_nonrep_in_repetition
//   - fn test_closure
//   - fn test_star_after_repetition

And many tests cases failed with proc_macro::quote!, e.g.

/*
message: assertion `left == right` failed
             left: "impl < 'a , T : ToTokens > ToTokens for & 'a T { fn to_tokens (& self , tokens : & mut TokenStream) { (* * self) . to_tokens (tokens) } }"
            right: "impl < 'a, T : ToTokens > ToTokens for & 'a T\n{\n    fn to_tokens(& self, tokens : & mut TokenStream)\n    { (** self).to_tokens(tokens) }\n}"
*/
fn test_quote_impl() {
    let tokens = quote! {
        impl<'a, T: ToTokens> ToTokens for &'a T {
            fn to_tokens(&self, tokens: &mut TokenStream) {
                (**self).to_tokens(tokens)
            }
        }
    };

    let expected = concat!(
        "impl < 'a , T : ToTokens > ToTokens for & 'a T { ",
        "fn to_tokens (& self , tokens : & mut TokenStream) { ",
        "(* * self) . to_tokens (tokens) ",
        "} ",
        "}"
    );

    assert_eq!(expected, tokens.to_string());
}
/*
message: assertion `left == right` failed
             left: "X < X > (X) [X] { X }"
            right: "X <X > (X) [X] { X }"
*/
fn test_substitution() {
    let x = X;
    let tokens = quote!($x <$x> ($x) [$x] {$x});

    let expected = "X < X > (X) [X] { X }";

    assert_eq!(expected, tokens.to_string());
}
/*
message: assertion `left == right` failed
             left: "struct SerializeWith < 'a , T > where T : Serialize { value : & 'a String , phantom : :: std :: marker :: PhantomData < Cow < 'a , str > > , } impl < 'a , T > :: serde :: Serialize for SerializeWith < 'a , T > where T : Serialize { fn serialize < S > (& self , s : & mut S) -> Result < () , S :: Error > where S : :: serde :: Serializer { SomeTrait :: serialize_with (self . value , s) } } SerializeWith { value : self . x , phantom : :: std :: marker :: PhantomData :: < Cow < 'a , str > > , }"
            right: "struct SerializeWith < 'a, T > where T : Serialize\n{\n    value : & 'a String, phantom : :: std :: marker :: PhantomData <Cow < 'a,\n    str > >,\n} impl < 'a, T > :: serde :: Serialize for SerializeWith < 'a, T > where T :\nSerialize\n{\n    fn serialize < S > (& self, s : & mut S) -> Result < (), S :: Error >\n    where S : :: serde :: Serializer\n    { SomeTrait :: serialize_with(self.value, s) }\n} SerializeWith\n{\n    value : self.x, phantom : :: std :: marker :: PhantomData ::<Cow < 'a, str\n    > >,\n}"
*/
fn test_advanced() { /* ... */ }

and more.

I propose to open a new PR to add these test cases with fixes, and leave a FIXME for these unimplemented features, to keep this PR clean. What do you think? @tgross35

@tgross35
Copy link
Contributor

tgross35 commented Jan 8, 2025

I'm working on migrating the applicable tests from https://github.com/dtolnay/quote/blob/0245506323a3616daa2ee41c6ad0b871e4d78ae4/tests/test.rs. It seems like the current proc_macro::quote! is still incomplete? Some features (quote_spanned!, format_ident!, repetition) are still not implemented, because of that many test cases cannot be migrated.

At least at this time, there is no plan for quote_spanned or format_ident so just ignore any tests out that rely on these. We definitely want repetition at some point, so keeping a list of missing tests for repetition in a FIXME comment sounds reasonable.

And many tests cases failed with proc_macro::quote!, e.g.

The examples you listed look like they have the same meaning but some different spacing. Updating the whitespace to match should be fine, as long as there aren't other inconsistencies.

library/proc_macro/src/quote.rs Outdated Show resolved Hide resolved
library/proc_macro/src/quote.rs Outdated Show resolved Hide resolved
@SpriteOvO
Copy link
Contributor Author

SpriteOvO commented Jan 8, 2025

Something is wrong with raw string.

/*
message: assertion `left == right` failed
             left: "# [doc = r\" doc\"]"
            right: "#[doc = \" doc\"]"
*/
fn test_outer_line_comment() {
    let tokens = quote! {
        /// doc
    };
    let expected = "# [doc = r\" doc\"]";
    assert_eq!(expected, tokens.to_string());
}

/*
message: `"r#raw_id"` is not a valid identifier
*/
fn test_quote_raw_id() {
    let id = quote!(r#raw_id);
    assert_eq!(id.to_string(), "r#raw_id");
}

@tgross35
Copy link
Contributor

tgross35 commented Jan 8, 2025

We probably need to call to Ident::new_raw rather than Ident::new in some cases, like quote has https://github.com/dtolnay/quote/blob/0245506323a3616daa2ee41c6ad0b871e4d78ae4/src/runtime.rs#L486.

For doc comments, maybe proc_macro2 and proc_macro unquote strings differently? @dtolnay would know better. You could run a test like this with our quote and see if it unquotes the same https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=19cdf0381b312f9ad5fac14af49e55f7.

@tgross35
Copy link
Contributor

tgross35 commented Jan 8, 2025

We probably need to call to Ident::new_raw rather than Ident::new in some cases, like quote has https://github.com/dtolnay/quote/blob/0245506323a3616daa2ee41c6ad0b871e4d78ae4/src/runtime.rs#L486.

Also if you prefer not to fix this here, it is okay to just open an issue and leave the test as a FIXME. I'd be happy to merge this nearly as-is since it's a big improvement over what we have, as long as tests pass and dtolnay has no objection.

Same goes for the r# string discrepancy as long as we understand where it is coming from.

@SpriteOvO
Copy link
Contributor Author

Also if you prefer not to fix this here, it is okay to just open an issue and leave the test as a FIXME. I'd be happy to merge this nearly as-is since it's a big improvement over what we have, as long as tests pass and dtolnay has no objection.

I'm fine to fix it in this PR as long as it's not a huge diff :)

Also, compilefail tests are still being migrated.

@SpriteOvO SpriteOvO marked this pull request as draft January 8, 2025 23:05
@SpriteOvO SpriteOvO force-pushed the proc-macro-use-to-tokens-in-quote branch 4 times, most recently from ef4e0b0 to fd21ab6 Compare January 9, 2025 01:45
@SpriteOvO SpriteOvO force-pushed the proc-macro-use-to-tokens-in-quote branch from c084d56 to bba8cd1 Compare January 9, 2025 18:43
@SpriteOvO
Copy link
Contributor Author

SpriteOvO commented Jan 9, 2025

For doc comments, maybe proc_macro2 and proc_macro unquote strings differently? @dtolnay would know better. You could run a test like this with our quote and see if it unquotes the same play.rust-lang.org?version=stable&mode=debug&edition=2021&gist=19cdf0381b312f9ad5fac14af49e55f7.

This is the output of our quote!. It looks like they have the same semantics - just escaped or not. I think it's fine to update the test cases with the new output.

&t = TokenStream [
    Punct {
        ch: '#',
        spacing: Alone,
        span: #5 bytes(76..94),
    },
    Group {
        delimiter: Bracket,
        stream: TokenStream [
            Ident {
                ident: "doc",
                span: #4 bytes(324157..324202),
            },
            Punct {
                ch: '=',
                spacing: Alone,
                span: #5 bytes(76..94),
            },
            Literal {
                kind: Str,
                symbol: " doc with \\\"all\\\" r\\\"kinds\\\" of r##\\\"strings\\\"##",
                suffix: None,
                span: #4 bytes(324157..324202),
            },
        ],
        span: #5 bytes(76..94),
    },
]
#[doc = " doc with \"all\" r\"kinds\" of r##\"strings\"##"]

@SpriteOvO SpriteOvO force-pushed the proc-macro-use-to-tokens-in-quote branch from bba8cd1 to dce1dc6 Compare January 9, 2025 19:39
@SpriteOvO SpriteOvO marked this pull request as ready for review January 9, 2025 19:40
@SpriteOvO SpriteOvO force-pushed the proc-macro-use-to-tokens-in-quote branch from dce1dc6 to 8859f8d Compare January 9, 2025 19:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-proc-macros Area: Procedural macros S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-libs Relevant to the library team, which will review and decide on the PR/issue. WG-macros Working group: Macros
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants