Skip to content

Type inference doesn't properly handle closures that don't return #111539

Open
@zackw

Description

@zackw

In the code below, both of the demo_* functions provoke type inference errors that I believe should not happen.

use std::error::Error;
use std::process::exit;

fn demo_one<F>(f: F) -> ()
where
    F: FnOnce() -> Result<(), Box<dyn Error>>,
{
    f().or_else(|e| {
        eprintln!("{:?}", e);
        exit(1)
    });
}

fn demo_two<F>(f: F) -> ()
where
    F: FnOnce() -> Result<(), Box<dyn Error>>,
{
    f().or_else(|e| -> ! {
        eprintln!("{:?}", e);
        exit(1)
    });
}

The errors I observe are (suggestions omitted for space):

error[E0282]: type annotations needed for `Result<(), F>`
 --> src/lib.rs:8:17
8 |     f().or_else(|e| {
error[E0271]]: expected `[closure@lib.rs:18:17]` to be a closure that returns `Result<(), _>`, but it returns `!`
  --> src/lib.rs:18:17
18 |       f().or_else(|e| -> ! {

I believe these errors to be incorrect, because:

  1. Both closures end with a call to std::process::exit, which does not return. The return type of the closure in demo_one should therefore have been inferred to be !, matching the closure in demo_two. (Note: whether that call has a ; afterward does not make any difference.)
  2. As documented in https://doc.rust-lang.org/std/primitive.never.html, ! coerces to any type, therefore a callable which never returns ought to be compatible with a caller expecting any return type.

Meta

rustc --version --verbose:

rustc 1.69.0 (84c898d65 2023-04-16)
binary: rustc
commit-hash: 84c898d65adf2f39a5a98507f1fe0ce10a2b8dbc
commit-date: 2023-04-16
host: aarch64-unknown-linux-gnu
release: 1.69.0
LLVM version: 15.0.7

Identical behavior observed from nightly (playground link).

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-closuresArea: Closures (`|…| { … }`)A-diagnosticsArea: Messages for errors, warnings, and lintsA-inferenceArea: Type inferenceC-bugCategory: This is a bug.D-confusingDiagnostics: Confusing error or lint that should be reworked.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language 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