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

Poor error message related to higher rank lifetimes #37300

Open
iopq opened this issue Oct 20, 2016 · 6 comments
Open

Poor error message related to higher rank lifetimes #37300

iopq opened this issue Oct 20, 2016 · 6 comments
Labels
A-closures Area: Closures (`|…| { … }`) A-diagnostics Area: Messages for errors, warnings, and lints A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@iopq
Copy link

iopq commented Oct 20, 2016

https://bitbucket.org/iopq/fizzbuzz-in-rust/src/6d739f4781c90be95ac47e067562471b0c52f9f8/src/lib.rs?at=error&fileviewer=file-view-default

After I try to use the tool.rs implementation of second I get this error message:

   Compiling fizzbuzz v0.0.1 (file:///C:/Users/Igor/Documents/rust/fizzbuzz)
error[E0281]: type mismatch: the type `fn(_) -> _ {tool::second::<_>}` implements the trait `std::ops::FnMut<(_,)>`, but the trait `for<'r> std::ops::FnMut<(&'r _,)>` is required (expected concrete lifetime, found bound lifetime parameter )

  --> src\lib.rs:52:11
   |
52 |            .filter(apply(second, i))
   |                    ^^^^^
   |
   = note: required by `apply`

error[E0271]: type mismatch resolving `for<'r> <fn(_) -> _ {tool::second::<_>} as std::ops::FnOnce<(&'r _,)>>::Output == _`
  --> src\lib.rs:52:11
   |
52 |            .filter(apply(second, i))
   |                    ^^^^^ expected bound lifetime parameter , found concrete lifetime
   |
   = note: concrete lifetime that was found is lifetime '_#11r
   = note: required by `apply`

I still don't quite understand this error message. The lifetimes are anonymous, so I don't know what it's talking about. The 'r lifetime is elided, I assume? There's no error code to help me understand the issue with concrete lifetimes vs. bound lifetime parameters.

@TimNN TimNN added the A-diagnostics Area: Messages for errors, warnings, and lints label Oct 20, 2016
@nagisa
Copy link
Member

nagisa commented Oct 22, 2016

Its saying that your fn(_) -> _ {tool::second::<_>} must implement std::ops::FnMut<(&'r _,)> for all possible lifetimes 'r (∀, for all, any, arbitrary), unrelated to any other lifetime. The function only implements std::ops::FnMut(_,)>, i.e. a FnMut which does not really satisfy that requirement.

To help with reasoning why this error is reported consider an equivalent:

filter(apply(|c| second(c), i))

The types here are:

  • c: &&(&str, &std::ops::Fn(i32) -> bool);
  • second: fn second<P: Second>(seq: P) -> P::Second;
  • &(&str, &std::ops::Fn(i32) -> bool): Second, but not &&(&str, &std::ops::Fn(i32) -> bool): Second;

At this point compiler tries these things:

  • Look for &&(&str, &std::ops::Fn(i32) -> bool): Second, which is not satisfied;
  • Noting that &(&str, &std::ops::Fn(i32) -> bool): Second does hold try finding the second: for<'r> Fn*(&'r T) where T = &(&str, &std::ops::Fn(i32) -> bool).

I feel like the error reported in such circumstances cannot be pointing at the right place 100% of the time, as the actual error might be either that &&(_,_): Second is not satisfied or the one that you just got, and user might be interested in either of those.


The solution fixing the error would be to dereference the c somehow… for example this way:

filter(apply(|&c| second(c), i))

@iopq
Copy link
Author

iopq commented Oct 23, 2016

filter(apply(|c| second(c), i)) gives a really NICE error message:

error[E0277]: the trait bound `&&(&str, &std::ops::Fn(i32) -> bool): tool::sequence::Cons` is not satisfied
  --> src\lib.rs:52:27
   |
52 |         .filter(apply(|c| second(c), i))
   |                           ^^^^^^ trait `&&(&str, &std::ops::Fn(i32) -> bool): tool::sequence::Cons` not satisfied
   |
   = help: the following implementations were found:
   = help:   <(A, B) as tool::sequence::Cons>
   = help:   <&'a (A, B) as tool::sequence::Cons>
   = help:   <&'a mut (A, B) as tool::sequence::Cons>
   = note: required because of the requirements on the impl of `tool::sequence::Second` for `&&(&str, &std::ops::Fn(i32) -> bool)`
   = note: required by `tool::second`

ah, so I need to use the git version of tool

the newest version has the correct impl, so when I do tool = { git = "https://github.com/Stebalien/tool-rs" } it actually compiles

so now the issue is:

filter(apply(|c| second(c), i)) works and filter(apply(second, i)) doesn't

and I assume the author of tool can't fix this one because of the higher rank lifetime issue?

@nagisa
Copy link
Member

nagisa commented Oct 23, 2016

Oh, so I didn’t check the issue closely enough.

So… even with the change to the tool crate, second still only implements Fn*<(_,)>, whereas in your apply you have F: FnMut(&B) -> G bound (which is equivalent to F: for<'r> FnMut(&'r B) -> G). These will never match as I’ve already explained in the comment above.

Changing your apply to the code below (with reasoning comments) fixes your problem.

fn apply<A, B, C, F, G>(mut f: F, a: A) 
-> impl FnMut(&B) -> C // must still be `for<'r> impl FnMut(&'r B) -> C`, because that’s what filter requires
         where F: FnMut(B) -> G, // must not be `for<'r> FnMut(&'r B) -> G`, because regular functions do not implement it
               G: FnMut(A) -> C,
               B: Copy, // for dereferencing
               A: Clone {

    move |b| f(*b)(a.clone()) // this must do any bridging necessary to satisfy the requirements between filter and regular functions
}

The error still (and even more so, now) seems totally correct (although kind-of opaque) to me.

@iopq
Copy link
Author

iopq commented Oct 23, 2016

Ah, that does fix my issue.

The error is correct, but I still don't understand it that well.

for all possible lifetimes 'r (∀, for all, any, arbitrary), unrelated to any other lifetime. The function only implements std::ops::FnMut(_,)>

How would that function implement such a thing?

@nagisa
Copy link
Member

nagisa commented Oct 23, 2016

How would that function implement such a thing?

I have no idea, but I have a feeling that you cannot implement traits for regular functions, so the only way to deal with the issue is to tweak bounds.

@steveklabnik steveklabnik added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Mar 9, 2017
@Mark-Simulacrum Mark-Simulacrum added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jul 26, 2017
@c7hm4r
Copy link

c7hm4r commented Jun 25, 2020

The error message for this problem has changed to:

error[E0308]: mismatched types
  --> src/lib.rs:52:17
   |
52 |         .filter(apply(second, i))
   |                 ^^^^^ one type is more general than the other
   |
   = note: expected type `std::ops::FnOnce<(&&(&str, &dyn std::ops::Fn(i32) -> bool),)>`
              found type `std::ops::FnOnce<(&&(&str, &dyn std::ops::Fn(i32) -> bool),)>`

While this is wrong or at least incomplete, it would be at least much more comprehensible. I think this bug can be closed. The problem seems to be a duplicate of #41078.

@fmease fmease added A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) A-closures Area: Closures (`|…| { … }`) labels Sep 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: Closures (`|…| { … }`) A-diagnostics Area: Messages for errors, warnings, and lints A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) C-enhancement Category: An issue proposing an enhancement or a PR with one. 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

7 participants