Skip to content

Poor error message related to higher rank lifetimes #37300

@iopq

Description

@iopq

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.

Activity

added
A-diagnosticsArea: Messages for errors, warnings, and lints
on Oct 20, 2016
nagisa

nagisa commented on Oct 22, 2016

@nagisa
Member

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

iopq commented on Oct 23, 2016

@iopq
Author

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

nagisa commented on Oct 23, 2016

@nagisa
Member

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

iopq commented on Oct 23, 2016

@iopq
Author

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

nagisa commented on Oct 23, 2016

@nagisa
Member

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.

added
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
on Mar 9, 2017
c7hm4r

c7hm4r commented on Jun 25, 2020

@c7hm4r

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.

added
A-higher-rankedArea: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs)
A-closuresArea: Closures (`|…| { … }`)
on Sep 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-closuresArea: Closures (`|…| { … }`)A-diagnosticsArea: Messages for errors, warnings, and lintsA-higher-rankedArea: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs)C-enhancementCategory: An issue proposing an enhancement or a PR with one.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @steveklabnik@nagisa@TimNN@iopq@c7hm4r

        Issue actions

          Poor error message related to higher rank lifetimes · Issue #37300 · rust-lang/rust