Skip to content

Incorrect compiler hint for complicated type handler #64548

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

Open
olegnn opened this issue Sep 17, 2019 · 5 comments
Open

Incorrect compiler hint for complicated type handler #64548

olegnn opened this issue Sep 17, 2019 · 5 comments
Labels
A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` C-bug Category: This is a bug. D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@olegnn
Copy link
Contributor

olegnn commented Sep 17, 2019

I was trying to implement custom macro parser but fall into strange issue.
Having following code

use proc_macro2::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream, Peek};
use syn::token::Token;

#[derive(Debug)]
struct ParseType {
    pub tokens: TokenStream,
}

mod custom {
    syn::custom_punctuation!(Arrow, ==>);
}

fn parse_until<T: Token>(
    input: ParseStream,
    ending_tokens: &[&impl Peek<Token = T>],
) -> syn::Result<TokenStream> {
    let mut tokens = TokenStream::new();
    while !input.is_empty() && !ending_tokens.into_iter().any(|token| input.peek(token)) {
        let next: proc_macro2::TokenTree = input.parse()?;
        tokens.extend(Some(next));
    }
    Ok(tokens)
}

impl Parse for ParseType {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        Ok(ParseType {
            tokens: parse_until(input, &[&custom::Arrow])?,
        })
    }
}

fn main() {
    let result: syn::Result<ParseType> =
        syn::parse2(quote! { { Ok::<usize, usize>(1) } ==> to the moon });
    println!("Parsed: {:?}", result.unwrap());
}

(Playground)

I got an error

error[E0277]: expected a `std::ops::Fn<(syn::lookahead::TokenMarker,)>` closure, found `impl Peek<Token = T>`
  --> src/main.rs:20:77
   |
20 |     while !input.is_empty() && !ending_tokens.into_iter().any(|token| input.peek(token)) {
   |                                                                             ^^^^ expected an `Fn<(syn::lookahead::TokenMarker,)>` closure, found `impl Peek<Token = T>`
   |
   = help: the trait `std::ops::Fn<(syn::lookahead::TokenMarker,)>` is not implemented for `impl Peek<Token = T>`
   = help: consider adding a `where impl Peek<Token = T>: std::ops::Fn<(syn::lookahead::TokenMarker,)>` bound
   = note: required because of the requirements on the impl of `std::ops::FnOnce<(syn::lookahead::TokenMarker,)>` for `&impl Peek<Token = T>`
   = note: required because of the requirements on the impl of `syn::lookahead::Peek` for `&&impl Peek<Token = T>`

So I added where impl Peek<Token = T>: std::ops::Fn<(syn::lookahead::TokenMarker,)> to the code and then situation became worse:

error[E0603]: module `lookahead` is private
  --> src/main.rs:18:78
   |
18 | ) -> syn::Result<TokenStream> where impl Peek<Token = T>: std::ops::Fn<(syn::lookahead::TokenMarker,)> {
   |                                                                              ^^^^^^^^^

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
  --> src/main.rs:18:37
   |
18 | ) -> syn::Result<TokenStream> where impl Peek<Token = T>: std::ops::Fn<(syn::lookahead::TokenMarker,)> {
   |                                     ^^^^^^^^^^^^^^^^^^^^

error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead
  --> src/main.rs:18:59
   |
18 | ) -> syn::Result<TokenStream> where impl Peek<Token = T>: std::ops::Fn<(syn::lookahead::TokenMarker,)> {
   |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: for more information, see https://github.com/rust-lang/rust/issues/29625

For the first of them it's ok [for me at least] that compiler can't understand which module is private, however the second and the third make me very confused, because this's the code generated by compiler itself.

@jonas-schievink jonas-schievink added A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Sep 17, 2019
@olegnn
Copy link
Contributor Author

olegnn commented Sep 17, 2019

input.peek(**token)

solved the problem but compiler hints in this case only made this little problem look so terrifying.

@cuviper
Copy link
Member

cuviper commented Sep 21, 2019

#64565 offers a more succinct version of that hint, suggesting where impl Trait bounds that aren't actually valid to write. But any hint along those lines would still be misleading in your case.

@estebank estebank added the D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. label Oct 5, 2019
@estebank
Copy link
Contributor

estebank commented Nov 25, 2019

Current output (minimal change to suggestion):

error[E0277]: expected a `std::ops::Fn<(syn::lookahead::TokenMarker,)>` closure, found `impl Peek<Token = T>`
  --> src/main.rs:20:82
   |
17 |     ending_tokens: &[&impl Peek<Token = T>],
   |                       -------------------- help: consider further restricting this bound: `impl Peek<Token = T> + std::ops::Fn<(syn::lookahead::TokenMarker,)>`
...
20 |     while !input.is_empty() && !ending_tokens.into_iter().any(|token| input.peek(token)) {
   |                                                                                  ^^^^^ expected an `Fn<(syn::lookahead::TokenMarker,)>` closure, found `impl Peek<Token = T>`
   |
   = help: the trait `std::ops::Fn<(syn::lookahead::TokenMarker,)>` is not implemented for `impl Peek<Token = T>`
   = note: required because of the requirements on the impl of `std::ops::FnOnce<(syn::lookahead::TokenMarker,)>` for `&impl Peek<Token = T>`
   = note: required because of the requirements on the impl of `syn::lookahead::Peek` for `&&impl Peek<Token = T>`

We now check if borrowing the argument would make the expression valid and suggest adding & if so. We should add a check that does the reverse (check if dereferencing the argument would make it valid) too.

@steveklabnik
Copy link
Member

Triage: output has slightly changed:

  Compiling playground v0.0.1 (/playground)
error[E0277]: expected a `std::ops::Fn<(syn::lookahead::TokenMarker,)>` closure, found `impl Peek<Token = T>`
  --> src/main.rs:20:82
   |
20 |     while !input.is_empty() && !ending_tokens.into_iter().any(|token| input.peek(token)) {
   |                                                                                  ^^^^^ expected an `Fn<(syn::lookahead::TokenMarker,)>` closure, found `impl Peek<Token = T>`
   |
   = note: required because of the requirements on the impl of `FnOnce<(syn::lookahead::TokenMarker,)>` for `&impl Peek<Token = T>`
   = note: required because of the requirements on the impl of `Peek` for `&&impl Peek<Token = T>`
help: consider further restricting this bound
   |
17 |     ending_tokens: &[&impl Peek<Token = T> + std::ops::Fn<(syn::lookahead::TokenMarker,)>],
   |                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

@Dylan-DPC
Copy link
Member

Dylan-DPC commented Dec 17, 2024

Current output:

error[E0277]: the trait bound `&&impl Peek<Token = T>: Peek` is not satisfied
   --> src/main.rs:20:82
    |
20  |     while !input.is_empty() && !ending_tokens.into_iter().any(|token| input.peek(token)) {
    |                                                                             ---- ^^^^^ the trait `Fn(syn::lookahead::TokenMarker)` is not implemented for `impl Peek<Token = T>`, which is required by `&&impl Peek<Token = T>: Peek`
    |                                                                             |
    |                                                                             required by a bound introduced by this call
    |
    = note: required for `&impl Peek<Token = T>` to implement `FnOnce(syn::lookahead::TokenMarker)`
    = note: required for `&&impl Peek<Token = T>` to implement `Peek`
note: required by a bound in `ParseBuffer::<'a>::peek`
   --> /playground/.cargo/registry/src/index.crates.io-6f17d22bba15001f/syn-2.0.90/src/parse.rs:581:20
    |
581 |     pub fn peek<T: Peek>(&self, token: T) -> bool {
    |                    ^^^^ required by this bound in `ParseBuffer::<'a>::peek`
help: consider further restricting this bound
    |
17  |     ending_tokens: &[&impl Peek<Token = T> + Fn(syn::lookahead::TokenMarker)],
    |                                            +++++++++++++++++++++++++++++++++

For more information about this error, try `rustc --explain E0277`.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` C-bug Category: This is a bug. D-invalid-suggestion Diagnostics: A structured suggestion resulting in incorrect code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants