Skip to content

Unhelpful error "one type is more general than the other" in async code #64650

Open

Description

@Seeker14491

The following code does not compile:

// Crate versions:
// futures-preview v0.3.0-alpha.18
// runtime v0.3.0-alpha.7

use futures::{prelude::*, stream::FuturesUnordered};

#[runtime::main]
async fn main() {
    let entries: Vec<_> = vec![()]
        .into_iter()
        .map(|x| async { vec![()].into_iter().map(|_| x) })
        .collect::<FuturesUnordered<_>>()
        .map(stream::iter)
        .flatten()
        .collect()
        .await;
}

It produces this error message:

error[E0308]: mismatched types
 --> src\main.rs:3:1
  |
3 | #[runtime::main]
  | ^^^^^^^^^^^^^^^^ one type is more general than the other
  |
  = note: expected type `std::ops::FnOnce<(std::iter::Map<std::vec::IntoIter<()>, [closure@src\main.rs:7:51: 7:56 x:&()]>,)>`
             found type `std::ops::FnOnce<(std::iter::Map<std::vec::IntoIter<()>, [closure@src\main.rs:7:51: 7:56 x:&()]>,)>`

In this case, the code can be made to compile by adding move in two places on this line:

// ...
        .map(|x| async move { vec![()].into_iter().map(move |_| x) })
// ...

Some possibly related issues: #57362, #60658

rustc version: 1.39.0-nightly (97e58c0d3 2019-09-20)

Activity

  1. added
    A-diagnosticsArea: Messages for errors, warnings, and lints
    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.
    on Sep 21, 2019
  2. added
    AsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.
    on Oct 1, 2019
  3. Seeker14491 commented on Oct 1, 2019

    @Seeker14491
    ContributorAuthor

    Here's an updated reproduction that doesn't use the runtime crate:

    // Using futures-preview v0.3.0-alpha.19
    use futures::StreamExt;
    
    fn main() {
        enter(run())
    }
    
    async fn run() {
        let entries: Vec<_> = vec![()]
            .into_iter()
            .map(|x| async { vec![()].into_iter().map(|_| x) })
            .collect::<futures::stream::FuturesUnordered<_>>()
            .map(futures::stream::iter)
            .flatten()
            .collect()
            .await;
    }
    
    pub fn enter(x: impl Send) {}

    Error:

    error[E0308]: mismatched types
     --> src\main.rs:5:5
      |
    5 |     enter(run())
      |     ^^^^^ one type is more general than the other
      |
      = note: expected type `std::ops::FnOnce<(std::iter::Map<std::vec::IntoIter<()>, [closure@src\main.rs:11:51: 11:56 x:&()]>,)>`
                 found type `std::ops::FnOnce<(std::iter::Map<std::vec::IntoIter<()>, [closure@src\main.rs:11:51: 11:56 x:&()]>,)>`
    

    ructc version: rustc 1.40.0-nightly (22bc9e1d9 2019-09-30)

  4. added
    D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.
    D-confusingDiagnostics: Confusing error or lint that should be reworked.
    on Feb 22, 2020
  5. djc commented on Mar 8, 2020

    @djc
    Contributor

    Someone was just asking about this in hyper's gitter channel. The diagnostics here are surprisingly bad. Ping?

  6. Aaron1011 commented on Mar 18, 2020

    @Aaron1011
    Contributor

    The output is better on nightly:

    error[E0597]: `x` does not live long enough
      --> src/main.rs:10:55
       |
    10 |         .map(|x| async { vec![()].into_iter().map(|_| x) })
       |                        -------------------------------^---
       |                        |                              |  |
       |                        |                              |  `x` dropped here while still borrowed
       |                        |                              borrowed value does not live long enough
       |                        value captured here by generator
    
    error[E0308]: mismatched types
     --> src/main.rs:4:5
      |
    4 |     enter(run())
      |     ^^^^^ one type is more general than the other
      |
      = note: expected type `std::ops::FnOnce<(std::iter::Map<std::vec::IntoIter<()>, [closure@src/main.rs:10:51: 10:56 x:&()]>,)>`
                 found type `std::ops::FnOnce<(std::iter::Map<std::vec::IntoIter<()>, [closure@src/main.rs:10:51: 10:56 x:&()]>,)>`
    
    error: aborting due to 2 previous errors
    

    but still contains the spurious "mismatched types" error.

  7. Aaron1011 commented on Mar 24, 2020

    @Aaron1011
    Contributor

    I think the 'one type is more general than the other' error is another instance of #64552

  8. Nashenas88 commented on Oct 13, 2020

    @Nashenas88
    Contributor

    This doesn't include async, but the conditions are similar enough, and I found it equally confusing (especially once I realized what the fix was): https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f2cf25b58f393f4a4377b0086e0032a2

    inline:

    #[derive(Clone)]
    struct A;
    
    trait CloneableFn: Fn(&A) + CloneBox {}
    
    trait CloneBox {
        fn clone_box(&self) -> Box<dyn CloneableFn>;
    }
    
    impl<T> CloneableFn for T where T: Fn(&A) + CloneBox {}
    
    impl<T> CloneBox for T where T: Fn(&A) + Clone + 'static {
        fn clone_box(&self) -> Box<dyn CloneableFn> {
            Box::new(self.clone()) as Box<dyn CloneableFn>
        }
    }
    
    
    fn take_cfn(cfn: Box<dyn CloneableFn>, a: A) {
        cfn(&a);
    }
    
    fn main() {
        let a = A;
        let closure = move |_| { // solve with `move |_: &A|`
            let _b = a.clone();
        };
        take_cfn(Box::new(closure) as Box<dyn CloneableFn>, A);
    }

    Error:

    error[E0308]: mismatched types
      --> src/main.rs:28:14
       |
    28 |     take_cfn(Box::new(closure) as Box<dyn CloneableFn>, A);
       |              ^^^^^^^^^^^^^^^^^ one type is more general than the other
       |
       = note: expected type `for<'r> std::ops::Fn<(&'r A,)>`
                  found type `std::ops::Fn<(&A,)>`
    
  9. jerel commented on Jan 12, 2021

    @jerel

    I ran into this same issue this week using tokio. Here's my conclusion, in case it's helpful for narrowing in on the bug.

    Reduced down to as few lines as possible it looks like this:

    runtime.spawn(async {
      warp::serve(
        routes
          .or(other_routes)
          .or(more_routes)
          .map(|reply| {
            warp::reply::with_header(reply, "Sec-WebSocket-Protocol", "graphql-ws")
          })
      )
      .run(([0, 0, 0, 0], 3001))
      .await;
    });

    and fails with:

       --> src/lib.rs:185:14
        |
    185 |   runtime.spawn(async {
        |           ^^^^^ one type is more general than the other
        |
        = note: expected type `std::ops::FnOnce<(warp::generic::Either<(warp::generic::Either<(warp::http::Response<std::vec::Vec<u8>>,), (warp::http::Response<std::vec::Vec<u8>>,)>,), (impl warp::Reply,)>,)>`
                   found type `std::ops::FnOnce<(warp::generic::Either<(warp::generic::Either<(warp::http::Response<std::vec::Vec<u8>>,), (warp::http::Response<std::vec::Vec<u8>>,)>,), (impl warp::Reply,)>,)>`

    Those types are identical aren't they? I managed to work around it like this:

    + .with(warp::reply::with::header("Sec-WebSocket-Protocol", "graphql-ws"))
    - .map(|reply| {
    -   warp::reply::with_header(reply, "Sec-WebSocket-Protocol", "graphql-ws")
    - })

    The first version has been working fine in another part of the codebase, something about how it's called here triggers it maybe? The other way I'm using it is in a #[tokio::main] function instead of runtime.spawn but the implementation is identical.

  10. Shizcow commented on Jan 25, 2021

    @Shizcow

    I have found a fairly minimal way to reproduce without external dependencies, and several useful observations. It's not using async, so maybe this is more fitted for #64552?

    Tested with rustc 1.51.0-nightly (d98d2f57d 2021-01-18)

    This is the reproduction code:

    pub struct BoxHolder<BoxedFn> {
        data: BoxedFn,
    }
    
    impl<Ret> BoxHolder<Box<fn(&str) -> Ret>> {
        pub fn box_and_set_data(&mut self, ptr: fn(&str) -> Ret) {
            let pre_boxed: Box<fn(&str) -> Ret> = Box::new(ptr); // box contents have concrete size, type annotations are for clarity
            self.data = pre_boxed; // not the case here
        }
    }
    
    fn a(a: &str) -> &str {
        ""
    }
    
    fn main() {
        let mut foo: BoxHolder<Box<fn(&str) -> &str>> = BoxHolder { data: Box::new(a) };
        foo.box_and_set_data(a);
    }

    The above yields the following error:

    error[E0308]: mismatched types
      --> src/main.rs:19:9
       |
    19 |     foo.box_and_set_data(a);
       |         ^^^^^^^^^^^^^^^^ one type is more general than the other
       |
       = note: expected mutable reference `&mut BoxHolder<Box<for<'r> fn(&'r str) -> &str>>`
                  found mutable reference `&mut BoxHolder<Box<for<'r> fn(&'r str) -> &'r str>>`
    

    Replacing the generic Ret with &str does let the code compile, but I have some more observations that more naturally lead to this conclusion. Besides, non-generic fn return parameters aren't fun!

    From the error it looks like a lifetime is either forgotten or elided. Removing the type annotations on foo gives a little more data:

    fn main() {
        // let mut foo: BoxHolder<Box<fn(&str) -> &str>> = BoxHolder { data: Box::new(a) };
        let mut foo = BoxHolder { data: Box::new(a) };
        foo.box_and_set_data(a);
    }

    And the new error:

    error[E0599]: no method named `box_and_set_data` found for struct `BoxHolder<Box<for<'r> fn(&'r str) -> &'r str {a}>>` in the current scope
      --> src/main.rs:18:9
       |
    1  | pub struct BoxHolder<BoxedFn> {
       | ----------------------------- method `box_and_set_data` not found for this
    ...
    18 |     foo.box_and_set_data(a);
       |         ^^^^^^^^^^^^^^^^ method not found in `BoxHolder<Box<for<'r> fn(&'r str) -> &'r str {a}>>`
    

    Well that's not right. a is supposed to be for<'r> fn(&'r str) -> &'static str, not for<'r> fn(&'r str) -> &'r str. The 'static seems to be replaced by 'r.

    What explicitly declaring the lifetime of a's return:

    // fn a(a: &str) -> &str {
    fn a(a: &str) -> &'static str {
        ""
    }
    
    fn main() {
        let mut foo = BoxHolder { data: Box::new(a) };
        foo.box_and_set_data(a);
    }

    New error:

    error[E0599]: no method named `box_and_set_data` found for struct `BoxHolder<Box<for<'r> fn(&'r str) -> &'static str {a}>>` in the current scope
      --> src/main.rs:18:9
       |
    1  | pub struct BoxHolder<BoxedFn> {
       | ----------------------------- method `box_and_set_data` not found for this
    ...
    18 |     foo.box_and_set_data(a);
       |         ^^^^^^^^^^^^^^^^ method not found in `BoxHolder<Box<for<'r> fn(&'r str) -> &'static str {a}>>`
    

    Now the lifetimes are correct but it's not picking up the impl, even though impl<Ret> is about as general as you can get. What about explicitly declaring the impl with the compiler-supplied type, but still with generic return:

    impl BoxHolder<Box<for<'r> fn(&'r str) -> &'static str>> {
        pub fn box_and_set_data(&mut self, ptr: for<'r> fn(&'r str) -> &'static str) {
            self.data = Box::new(ptr);
        }
    }
    
    fn a(a: &str) -> &'static str {
        ""
    }
    
    fn main() {
        let mut foo = BoxHolder { data: Box::new(a) };
        foo.box_and_set_data(a);
    }

    New error:

    error[E0599]: no method named `box_and_set_data` found for struct `BoxHolder<Box<for<'r> fn(&'r str) -> &'static str {a}>>` in the current scope
      --> src/main.rs:17:9
       |
    1  | pub struct BoxHolder<BoxedFn> {
       | ----------------------------- method `box_and_set_data` not found for this
    ...
    17 |     foo.box_and_set_data(a);
       |         ^^^^^^^^^^^^^^^^ method not found in `BoxHolder<Box<for<'r> fn(&'r str) -> &'static str {a}>>`
    

    Even though the impl Type is the exact same type as in the error, it's not recognized. The error is the same if the additional lifetime parameters are left out (IE impl BoxHolder<Box<fn(&str) -> &str>>). The only thing I've gotten to work is the following:

    pub struct BoxHolder<BoxedFn> {
        data: BoxedFn,
    }
    
    impl BoxHolder<Box<fn(&str) -> &str>> {
        pub fn box_and_set_data(&mut self, ptr: fn(&str) -> &str) {
            self.data = Box::new(ptr);
        }
    }
    
    fn a(a: &str) -> &str {
        ""
    }
    
    fn main() {
        let mut foo: BoxHolder<Box<fn(&str) -> &str>> = BoxHolder { data: Box::new(a) };
        foo.box_and_set_data(a);
    }

    The above code compiles correctly. It seems that BoxHolder { data: Box::new(a) } is not BoxHolder<Box<fn(&str) -> &str>> but can be imlpicitly converted into it.

    FWIW, doing type F = fn(&str) -> &str; and using F everywhere doesn't change the errors. An implicit cast to BoxHolder<Box<F>> is still required. If someone knows how to directly check the type of two variables (during compilation?) I think the next step would be seeing what the types of the following two variables are, because the type system doesn't seem to think they're equal according to the testing above:

    fn a(a: &str) -> &str {
        ""
    }
    
    fn main() {
        let a1 = a;
        let a2: fn(&str) -> &str = a;
    }

    This is all the useful information I'm able to gleam from this. I'm unsure if the later results are directly related to the initial one type is more general than the other issue, if they're another bug entirely, or if they're a thing because I just plain don't know enough rust. Hope it helps in diagnosing the root cause.

  11. estebank commented on Oct 8, 2026

    @estebank
    Contributor

    Current output:

    https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=461f44a5a1143577d4e600e46a3c4bfd

    error[E0373]: async block may outlive the current function, but it borrows `x`, which is owned by the current function
      --> src/main.rs:11:18
       |
    11 |         .map(|x| async { vec![()].into_iter().map(|_| x) })
       |                  ^^^^^ may outlive borrowed value `x` - `x` is borrowed here
       |
    note: async block is returned here
      --> src/main.rs:11:18
       |
    11 |         .map(|x| async { vec![()].into_iter().map(|_| x) })
       |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    help: to force the async block to take ownership of `x` (and any other referenced variables), use the `move` keyword
       |
    11 |         .map(|x| async move { vec![()].into_iter().map(|_| x) })
       |                        ++++
    

    https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=8bdb0d3d21de458ae4299fd66af80241

    error[E0277]: expected an `FnOnce(&A)` closure, found `{closure@src/main.rs:25:19: 25:27}`
      --> src/main.rs:28:14
       |
    28 |     take_cfn(Box::new(closure) as Box<dyn CloneableFn>, A);
       |              ^^^^^^^^^^^^^^^^^ expected an `FnOnce(&A)` closure, found `{closure@src/main.rs:25:19: 25:27}`
       |
       = help: the trait `for<'a> FnOnce(&'a A)` is not implemented for closure `{closure@src/main.rs:25:19: 25:27}`
       = note: expected a closure with signature `for<'a> fn(&'a A)`
                  found a closure with signature `fn(&A)`
    note: required for `{closure@src/main.rs:25:19: 25:27}` to implement `CloneableFn`
      --> src/main.rs:10:9
       |
    10 | impl<T> CloneableFn for T where T: Fn(&A) + CloneBox {}
       |         ^^^^^^^^^^^     ^          ------ unsatisfied trait bound introduced here
    note: required because it's used within this closure
      --> src/main.rs:25:19
       |
    25 |     let closure = move |_| { // solve with `move |_: &A|`
       |                   ^^^^^^^^
       = note: required for `Box<{closure@src/main.rs:25:19: 25:27}>` to implement `CoerceUnsized<Box<dyn CloneableFn>>`
       = note: required for the cast from `Box<{closure@src/main.rs:25:19: 25:27}>` to `Box<dyn CloneableFn>`
    

    https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=d4e19bf0b1c9956015ac072fb55cf0ff

    error[E0599]: no method named `box_and_set_data` found for struct `BoxHolder<Box<for<'a> fn(&'a str) -> &'a str>>` in the current scope
      --> src/main.rs:18:9
       |
     1 | pub struct BoxHolder<BoxedFn> {
       | ----------------------------- method `box_and_set_data` not found for this struct
    ...
    18 |     foo.box_and_set_data(a);
       |         ^^^^^^^^^^^^^^^^ method not found in `BoxHolder<Box<for<'a> fn(&'a str) -> &'a str>>`
       |
       = note: the method was found for `BoxHolder<Box<for<'a> fn(&'a str) -> Ret>>`
    

    https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=b5f2856f669ecb39bcb735517ba418e3

    error[E0599]: no method named `box_and_set_data` found for struct `BoxHolder<Box<for<'a> fn(&'a str) -> &'a str {a}>>` in the current scope
      --> src/main.rs:18:9
       |
     1 | pub struct BoxHolder<BoxedFn> {
       | ----------------------------- method `box_and_set_data` not found for this struct
    ...
    18 |     foo.box_and_set_data(a);
       |         ^^^^^^^^^^^^^^^^ method not found in `BoxHolder<Box<for<'a> fn(&'a str) -> &'a str {a}>>`
       |
       = note: the method was found for `BoxHolder<Box<for<'a> fn(&'a str) -> Ret>>`
    

    https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=0ff1324314dd4b22028f5ad3e6d09b89

    error[E0599]: no method named `box_and_set_data` found for struct `BoxHolder<Box<for<'a> fn(&'a str) -> &'static str {a}>>` in the current scope
      --> src/main.rs:17:9
       |
     1 | pub struct BoxHolder<BoxedFn> {
       | ----------------------------- method `box_and_set_data` not found for this struct
    ...
    17 |     foo.box_and_set_data(a);
       |         ^^^^^^^^^^^^^^^^ method not found in `BoxHolder<Box<for<'a> fn(&'a str) -> &'static str {a}>>`
       |
       = note: the method was found for `BoxHolder<Box<for<'r> fn(&'r str) -> &'static str>>`
    
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-async-awaitArea: Async & AwaitA-diagnosticsArea: Messages for errors, warnings, and lintsAsyncAwait-TriagedAsync-await issues that have been triaged during a working group meeting.C-enhancementCategory: An issue proposing an enhancement or a PR with one.D-confusingDiagnostics: Confusing error or lint that should be reworked.D-newcomer-roadblockDiagnostics: Confusing error or lint; hard to understand for new users.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

      Issue actions