Rust: async syntactic oddity

Viewed 38

Why does Rust allow this:

fn main() {
    let f = |x: bool| {
        async {
            return
        }
    };
}

But not this? Specifically, the error complains that the branches return different types, when they appear to be exactly the same.

fn main() {
    let f = |x: bool| {
        if true {
            async {
                return
            }
        } else {
            async {
                return
            }
        }
    };
}
error[E0308]: `if` and `else` have incompatible types
  --> src/main.rs:42:13
   |
37 |   /         if true {
38 |   |             async {
   |  _|_____________-
39 | | |                 return
40 | | |             }
   | |_|_____________- expected because of this
41 |   |         } else {
42 | / |             async {
43 | | |                 return
44 | | |             }
   | |_|_____________^ expected `async` block, found a different `async` block
45 |   |         }
   |   |_________- `if` and `else` have incompatible types
   |
1 Answers

Every time you write async { }, the compiler makes a unique anonymous Future type. They will be distinct even if two are syntactically equivalent. This is the same for closures.

So your first snippet is simply returning an object (with an anonymous type), while your second is trying to return different types conditionally, which is not allowed. Consider using a trait object so they are the same type:

use std::future::Future;

fn main() {
    let f = |x: bool| {
        if true {
            Box::new(async {
                return
            }) as Box<dyn Future<Output=()>>
        } else {
            Box::new(async {
                return
            })
        }
    };
}
Related