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

unused_parens warning generated #118

Closed
georgemp opened this issue Aug 12, 2020 · 3 comments · Fixed by #119
Closed

unused_parens warning generated #118

georgemp opened this issue Aug 12, 2020 · 3 comments · Fixed by #119

Comments

@georgemp
Copy link

Hi,

I'm running into an issue wherein I get unused_parens warnings. A reproducible version on the rust playground can be found here.

The code is

use tokio;
use async_trait::async_trait;

#[async_trait]
trait Resetable {
    async fn reset(&mut self);
}

struct Modifier {
    action: fn(String) -> String,
}

impl Modifier {
    fn new(action: fn(String) -> String) -> Self {
        Modifier {
            action
        }
    }
}

#[async_trait]
impl Resetable for Modifier {
    async fn reset(&mut self) {
        //println!("resetting action");
        self.action = |str| str;
    }
}

#[tokio::main]
async fn main() {
    let mut modifier = Modifier::new(|str| {
        format!("{}{}", str, str)
    });
    
    let orig = "Frank".to_owned();
    let modified = (modifier.action)(orig);
    println!("{}", modified);
    
    let _ = modifier.reset().await;
    let orig = "Bob".to_owned();
    let modified = (modifier.action)(orig);
    println!("{}", modified);
}

If i uncomment the println! on line 24 (on the playground), the warning goes away. Do let me know if you would need any more details with this (or, would like me to try something else). Thanks

@dtolnay
Copy link
Owner

dtolnay commented Aug 12, 2020

This looks like a strange compiler bug, related to rust-lang/rust#43081. Inserting a println!("{:#?}", input) at the beginning of the implementation of async_trait, the tokens being passed as input to the async_trait macro by rustc are:

Full token stream
TokenStream [
    Ident {
        ident: "impl",
        span: #0 bytes(0..0),
    },
    Ident {
        ident: "Resetable",
        span: #0 bytes(0..0),
    },
    Ident {
        ident: "for",
        span: #0 bytes(0..0),
    },
    Ident {
        ident: "Modifier",
        span: #0 bytes(0..0),
    },
    Group {
        delimiter: Brace,
        stream: TokenStream [
            Ident {
                ident: "async",
                span: #0 bytes(0..0),
            },
            Ident {
                ident: "fn",
                span: #0 bytes(0..0),
            },
            Ident {
                ident: "reset",
                span: #0 bytes(0..0),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [
                    Punct {
                        ch: '&',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                    Ident {
                        ident: "mut",
                        span: #0 bytes(0..0),
                    },
                    Ident {
                        ident: "self",
                        span: #0 bytes(0..0),
                    },
                ],
                span: #0 bytes(0..0),
            },
            Group {
                delimiter: Brace,
                stream: TokenStream [
                    Ident {
                        ident: "self",
                        span: #0 bytes(0..0),
                    },
                    Punct {
                        ch: '.',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                    Ident {
                        ident: "action",
                        span: #0 bytes(0..0),
                    },
                    Punct {
                        ch: '=',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                    Group {
                        delimiter: Parenthesis,
                        stream: TokenStream [
                            Punct {
                                ch: '|',
                                spacing: Alone,
                                span: #0 bytes(0..0),
                            },
                            Ident {
                                ident: "str",
                                span: #0 bytes(0..0),
                            },
                            Punct {
                                ch: '|',
                                spacing: Alone,
                                span: #0 bytes(0..0),
                            },
                            Ident {
                                ident: "str",
                                span: #0 bytes(0..0),
                            },
                        ],
                        span: #0 bytes(0..0),
                    },
                    Punct {
                        ch: ';',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                ],
                span: #0 bytes(0..0),
            },
        ],
        span: #0 bytes(0..0),
    },
]

Notice in particular this part:

                    Ident {
                        ident: "self",
                        span: #0 bytes(0..0),
                    },
                    Punct {
                        ch: '.',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                    Ident {
                        ident: "action",
                        span: #0 bytes(0..0),
                    },
                    Punct {
                        ch: '=',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                    Group {
                        delimiter: Parenthesis,
                        stream: TokenStream [
                            Punct {
                                ch: '|',
                                spacing: Alone,
                                span: #0 bytes(0..0),
                            },
                            Ident {
                                ident: "str",
                                span: #0 bytes(0..0),
                            },
                            Punct {
                                ch: '|',
                                spacing: Alone,
                                span: #0 bytes(0..0),
                            },
                            Ident {
                                ident: "str",
                                span: #0 bytes(0..0),
                            },
                        ],
                        span: #0 bytes(0..0),
                    },

Rustc inserted unnecessary parentheses around the closure before even calling async_trait, passing the statement as self.action = (|str| str);. At the same time, it lost all the location information on the source tokens (#0 bytes(0..0)) so it blames the user for handwriting those parentheses.

@dtolnay
Copy link
Owner

dtolnay commented Aug 12, 2020

I released 0.1.37 which just suppresses the lint as a workaround.

@Aaron1011
Copy link

Now that rust-lang/rust#75734 has been fixed, the lint should no longer fire.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants