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

Pretty-print macro matchers instead of using source code #86282

Merged
merged 3 commits into from
Jul 5, 2021

Conversation

camelid
Copy link
Member

@camelid camelid commented Jun 14, 2021

Fixes #86208.

@camelid camelid added A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) T-rustdoc labels Jun 14, 2021
@rust-highfive
Copy link
Collaborator

r? @ollie27

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 14, 2021
@camelid
Copy link
Member Author

camelid commented Jun 14, 2021

r? @jyn514 (feel free to reassign)

@rust-highfive rust-highfive assigned jyn514 and unassigned ollie27 Jun 14, 2021
@camelid
Copy link
Member Author

camelid commented Jun 14, 2021

Beta-nominating because this fixes a P-high stable-to-beta regression.

@camelid camelid added the beta-nominated Nominated for backporting to the compiler in the beta channel. label Jun 14, 2021
@camelid
Copy link
Member Author

camelid commented Jun 14, 2021

Before/after:

stable (pre-regression)

image

beta (with regression)

image

this PR (with fix)

image

@camelid
Copy link
Member Author

camelid commented Jun 14, 2021

I left some comments in the commit messages too, so they may be helpful to read.

@camelid camelid force-pushed the macro_rules-matchers branch 2 times, most recently from 656da0c to 87e0452 Compare June 14, 2021 00:17
Comment on lines 6 to 24
// @has 'foo/macro.todo.html'
// @has - '//span[@class="macro"]' 'macro_rules!'
// @has - '//span[@class="ident"]' 'todo'
// Note: count = 2 * ('=' + '>') + '+' = 2 * (1 + 1) + 1 = 5
// @count - '//pre[@class="rust macro"]//span[@class="op"]' 5

// @has - '{ ()'
// @has - '//span[@class="op"]' '='
// @has - '//span[@class="op"]' '>'
// @has - '{ ... };'

// @has - '($ ($'
// @has - '//span[@class="ident"]' 'arg'
// @has - ':'
// @has - '//span[@class="ident"]' 'tt'
// @has - '//span[@class="op"]' '+'
// @has - ')'
Copy link
Member Author

@camelid camelid Jun 14, 2021

Choose a reason for hiding this comment

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

Do you know of a way to do a @has check that matches on the innerText of an element (in this case, <pre class="rust macro">) to avoid having so many individual checks?

Copy link
Member

Choose a reason for hiding this comment

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

I don't, @GuillaumeGomez may.

Actually my understanding is that is always used innerText, are you sure doing it the obvious way doesn't work?

Copy link
Member

Choose a reason for hiding this comment

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

Just like @jyn514 said. The problem might be that the text doesn't "look like" what you might expect but that's it. :)

Copy link
Member Author

Choose a reason for hiding this comment

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

I had tried something like @has - 'macro_rules! todo {' and it failed; maybe I need to explicitly specify //pre? I also had this issue in #83501 where @has - 'Size: 1 byte' didn't work because Size: was wrapped with <b>.

Copy link
Member

Choose a reason for hiding this comment

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

Ah! Maybe try with //text() at the end.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, it doesn't seem to be working. //text() by itself gave this error:

27: Non-absolute XPath is not supported due to implementation issues
	    // @has - '//text()' 'macro_rules! macro1 {'
28: Non-absolute XPath is not supported due to implementation issues
	    // @has - '//text()' '() => { ... };'
29: Non-absolute XPath is not supported due to implementation issues
	    // @has - '//text()' '$ ($ arg : expr), +) => { ... };'
30: Non-absolute XPath is not supported due to implementation issues
	    // @has - '//text()' '}'

Encountered 4 errors

and //pre//text() gave this:

27: @has check failed
	`XPATH PATTERN` did not match
	    // @has - '//pre//text()' 'macro_rules! macro1 {'
28: @has check failed
	`XPATH PATTERN` did not match
	    // @has - '//pre//text()' '() => { ... };'
29: @has check failed
	`XPATH PATTERN` did not match
	    // @has - '//pre//text()' '$ ($ arg : expr), +) => { ... };'
30: @has check failed
	`XPATH PATTERN` did not match
	    // @has - '//pre//text()' '}'

Encountered 4 errors

I also tried //pre///text() (extra slash), but that didn't work either.

@rust-log-analyzer

This comment has been minimized.

@camelid
Copy link
Member Author

camelid commented Jun 14, 2021

I figured out a way to print the matchers in a prettier way, but it may have edge cases that I'm not aware of. Here's the new output:

image

And here's what the code looks like:

pub(super) fn render_macro_matcher(matcher: &TokenTree) -> String {
    match matcher {
        TokenTree::Token(tok) => rustc_ast_pretty::pprust::token_to_string(tok),
        TokenTree::Delimited(_span, delim_tok, stream) => {
            let open_tok = Token::new(token::OpenDelim(*delim_tok), DUMMY_SP);
            let close_tok = Token::new(token::CloseDelim(*delim_tok), DUMMY_SP);
            format!(
                "{}{}{}",
                rustc_ast_pretty::pprust::token_to_string(&open_tok),
                stream.trees().map(|tt| render_macro_matcher(&tt)).collect::<String>(),
                rustc_ast_pretty::pprust::token_to_string(&close_tok)
            )
        }
    }
}

@rust-log-analyzer

This comment has been minimized.

Copy link
Member

@jyn514 jyn514 left a comment

Choose a reason for hiding this comment

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

I figured out a way to print the matchers in a prettier way, but it may have edge cases that I'm not aware of.

I don't think rustdoc's pretty print should behave differently from rustc's. Can you change this in rustc_ast_pretty instead? It should be easier there because these already have to be handled.

matchers
.iter()
.map(|matcher| format!(" {} => {{ ... }};\n", render_macro_matcher(matcher)))
.collect::<String>()
Copy link
Member

Choose a reason for hiding this comment

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

Rather than allocating a new string for each arm, can you use a for loop and push_str?

Copy link
Member Author

Choose a reason for hiding this comment

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

I changed it to use writeln!, which I think should generate code fairly similar to push_str, but is more readable.

/// as part of an item declaration.
pub(super) fn render_macro_matcher(matcher: &TokenTree) -> String {
rustc_ast_pretty::pprust::tt_to_string(matcher)
}
Copy link
Member

Choose a reason for hiding this comment

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

Why have this as a separate function? Just use tt_to_string.

Copy link
Member Author

Choose a reason for hiding this comment

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

We may not use tt_to_string in the future, or we may have additional logic, so I'd rather err on the side of having an extra function. But I can remove it if you prefer.

Copy link
Member

Choose a reason for hiding this comment

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

Please remove it until and unless we add more logic.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually, render_macro_matcher is used in another place, for rendering macros 2.0. I'd really rather keep it so there aren't multiple places to update later on.

Copy link
Member

Choose a reason for hiding this comment

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

I don't understand why you think this would ever change. Rustdoc uses rustc in lots of places, it doesn't make sense to wrap every single one in our own function.

Copy link
Member

Choose a reason for hiding this comment

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

Oh I see, this is the function you mentioned above for removing the whitespace in the matcher. I think we should keep the function if we keep your special-casing, and remove it if not. And I do like that the special-casing makes it prettier. So I guess I'm in favor of keeping it.

Copy link
Member

Choose a reason for hiding this comment

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

See also the discussion in rust-lang/compiler-team#403

Comment on lines 6 to 24
// @has 'foo/macro.todo.html'
// @has - '//span[@class="macro"]' 'macro_rules!'
// @has - '//span[@class="ident"]' 'todo'
// Note: count = 2 * ('=' + '>') + '+' = 2 * (1 + 1) + 1 = 5
// @count - '//pre[@class="rust macro"]//span[@class="op"]' 5

// @has - '{ ()'
// @has - '//span[@class="op"]' '='
// @has - '//span[@class="op"]' '>'
// @has - '{ ... };'

// @has - '($ ($'
// @has - '//span[@class="ident"]' 'arg'
// @has - ':'
// @has - '//span[@class="ident"]' 'tt'
// @has - '//span[@class="op"]' '+'
// @has - ')'
Copy link
Member

Choose a reason for hiding this comment

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

I don't, @GuillaumeGomez may.

Actually my understanding is that is always used innerText, are you sure doing it the obvious way doesn't work?

src/librustdoc/clean/inline.rs Outdated Show resolved Hide resolved
@camelid
Copy link
Member Author

camelid commented Jun 14, 2021

Can you change this in rustc_ast_pretty instead? It should be easier there because these already have to be handled.

The problem is that they aren't already handled. For example, this is what print_tt()'s docs say (tt_to_string() is just a wrapper around this function):

This doesn’t deserve to be called “pretty” printing, but it should be meaning-preserving. A quick hack that might help would be to look at the spans embedded in the TTs to decide where to put spaces and newlines. But it’d be better to parse these according to the grammar of the appropriate macro, transcribe back into the grammar we just parsed from, and then pretty-print the resulting AST nodes (so, e.g., we print expression arguments as expressions). It can be done! I think.

From what I can tell, it just puts a space after every token, which is why the output is not so great:

        match tt {
            TokenTree::Token(token) => {
                let token_str = self.token_to_string_ext(&token, convert_dollar_crate);
                self.word(token_str);
                if let token::DocComment(..) = token.kind {
                    self.hardbreak()
                }
            }
            // ...

So I don't think it would be easier to change in rustc_ast_pretty. It might even be harder because we'd have to deal with the existing pretty-printing logic.

@Mark-Simulacrum
Copy link
Member

Dropping beta nomination; this is not ready for beta backport based on the extensive discussion on PR and #86208 does not seem like a critical bug. #86208 will shortly be a stable/stable regression and I don't think this warrants a backport in that case.

@Mark-Simulacrum Mark-Simulacrum removed the beta-nominated Nominated for backporting to the compiler in the beta channel. label Jun 14, 2021
@camelid
Copy link
Member Author

camelid commented Jun 14, 2021

Dropping beta nomination; this is not ready for beta backport based on the extensive discussion on PR and #86208 does not seem like a critical bug. #86208 will shortly be a stable/stable regression and I don't think this warrants a backport in that case.

Yeah, I realized that a backport into 1.53 wouldn't make sense, but I left the label on since this will likely land in 1.55 and need to be backported to 1.54. Should I just wait until 1.53 is released before adding the label back?

@Mark-Simulacrum
Copy link
Member

I do not think it should be backported to 1.54 either; it is merely fixing a (seemingly to me) minor bug, and not patching a beta regression.

@jyn514
Copy link
Member

jyn514 commented Jun 14, 2021

@Mark-Simulacrum it is a beta regression (stable now; it broke in 1.53), but for something that has been broken and fixed several times in the past.

@jyn514 jyn514 added T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. and removed T-rustdoc-temp labels Jun 22, 2021
@bors

This comment has been minimized.

@jyn514 jyn514 removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 26, 2021
@camelid
Copy link
Member Author

camelid commented Jul 4, 2021

I guess we should. But AFAIK rustc_ast_pretty is mostly only used for -Zunpretty.

I think the problem is that stringify! relies on rustc_ast_pretty.

For example, this code:

fn main() {
    println!("{}", stringify!($foo));
}

produces the following on nightly:

$ foo

but produces this instead after this PR:

$foo

@petrochenkov
Copy link
Contributor

It seems fine to omit the space after $, although eventually we should fully preserve token jointness information produced by lexer and pretty-print precisely instead of guessing with fn tt_prepend_space.

I think the problem is that stringify! relies on rustc_ast_pretty.

It's not a problem, similar changes were done to the pretty-printer quite often in the past, stringify! docs even have a disclaimer about this.

r? @jyn514

@rust-highfive rust-highfive assigned jyn514 and unassigned petrochenkov Jul 4, 2021
@jyn514
Copy link
Member

jyn514 commented Jul 4, 2021

@bors r+

@bors
Copy link
Contributor

bors commented Jul 4, 2021

📌 Commit 7ffec70 has been approved by jyn514

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 4, 2021
@bors
Copy link
Contributor

bors commented Jul 5, 2021

⌛ Testing commit 7ffec70 with merge 09d9b60...

@bors
Copy link
Contributor

bors commented Jul 5, 2021

☀️ Test successful - checks-actions
Approved by: jyn514
Pushing 09d9b60 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Jul 5, 2021
@bors bors merged commit 09d9b60 into rust-lang:master Jul 5, 2021
@rustbot rustbot added this to the 1.55.0 milestone Jul 5, 2021
@camelid camelid deleted the macro_rules-matchers branch July 5, 2021 21:23
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jan 9, 2022
…uillaumeGomez

rustdoc: Preserve rendering of macro_rules matchers when possible

Fixes rust-lang#92331. This approach restores the behavior prior to rust-lang#86282 **if** the matcher token held by the compiler **and** the matcher token found in the source code are identical TokenTrees. Thus rust-lang#86208 remains fixed, but without regressing formatting for the vast majority of macros which are not macro-generated.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jan 10, 2022
…uillaumeGomez

rustdoc: Preserve rendering of macro_rules matchers when possible

Fixes rust-lang#92331. This approach restores the behavior prior to rust-lang#86282 **if** the matcher token held by the compiler **and** the matcher token found in the source code are identical TokenTrees. Thus rust-lang#86208 remains fixed, but without regressing formatting for the vast majority of macros which are not macro-generated.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jan 10, 2022
…uillaumeGomez

rustdoc: Preserve rendering of macro_rules matchers when possible

Fixes rust-lang#92331. This approach restores the behavior prior to rust-lang#86282 **if** the matcher token held by the compiler **and** the matcher token found in the source code are identical TokenTrees. Thus rust-lang#86208 remains fixed, but without regressing formatting for the vast majority of macros which are not macro-generated.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jan 12, 2022
…uillaumeGomez

rustdoc: Preserve rendering of macro_rules matchers when possible

Fixes rust-lang#92331. This approach restores the behavior prior to rust-lang#86282 **if** the matcher token held by the compiler **and** the matcher token found in the source code are identical TokenTrees. Thus rust-lang#86208 remains fixed, but without regressing formatting for the vast majority of macros which are not macro-generated.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jan 13, 2022
…uillaumeGomez

rustdoc: Preserve rendering of macro_rules matchers when possible

Fixes rust-lang#92331. This approach restores the behavior prior to rust-lang#86282 **if** the matcher token held by the compiler **and** the matcher token found in the source code are identical TokenTrees. Thus rust-lang#86208 remains fixed, but without regressing formatting for the vast majority of macros which are not macro-generated.
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Jan 13, 2022
…uillaumeGomez

rustdoc: Preserve rendering of macro_rules matchers when possible

Fixes rust-lang#92331. This approach restores the behavior prior to rust-lang#86282 **if** the matcher token held by the compiler **and** the matcher token found in the source code are identical TokenTrees. Thus rust-lang#86208 remains fixed, but without regressing formatting for the vast majority of macros which are not macro-generated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

rustdoc: Regression in display of macro_rules! matchers