rust-lang / rust-lang/rust

Type inference fails to unify `impl Trait` in `map_or_else` closures

Open
#151,913 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-closures A-coercions A-dyn-trait A-inference C-bug T-compiler
Dominant language
Rust
Stars
119k
Forks
16.2k
PR merge metrics
PR metrics pending

Description

I tried this code:

struct A { a: i32 }
struct B;

trait Tag {}
impl Tag for A {}
impl Tag for B {}

fn return_a() -> impl Tag {
    A { a: 42 }
}

fn return_b() -> impl Tag {
    B
}

fn return_a_or_b() -> Box<dyn Tag> {
    None.map_or_else(|| Box::new(return_a()), |_v: i32| Box::new(return_b()))
}

I expected to see this happen:
I think these code should compile

Instead, this happened: explanation

error[E0308]: mismatched types
 --> src/main.rs:15:56
   |
15 |     None.map_or_else(|| Box::new(return_a()), |v: i32| Box::new(return_b()))
   |                                                        -------- ^^^^^^^^^^ expected opaque type, found a different opaque type
   |                                                        |
   |                                                        arguments to this function are incorrect
   |
   = note: expected opaque type `impl Tag`
              found opaque type `impl Tag`
   = note: distinct uses of `impl Trait` result in different opaque types

Meta

rustc --version --verbose:

rustc 1.92.0 (ded5c06cf 2025-12-08)
binary: rustc
commit-hash: ded5c06cf21d2b93bffd5d884aa6e96934ee4234
commit-date: 2025-12-08
host: x86_64-pc-windows-msvc
release: 1.92.0
LLVM version: 21.1.3
Backtrace

N/A (not a crash)

Additional Notes

This issue occurs with map_or_else, but not with explicit casts. Workaround:

fn return_a_or_b() -> Box<dyn Tag> {
    None.map_or_else(
        || Box::new(return_a()) as Box<dyn Tag>,
        |_v: i32| Box::new(return_b()) as Box<dyn Tag>,
    )
}

Using an if statement also works without casts:

fn return_a_or_b() -> Box<dyn Tag> {
    if true {
        Box::new(return_a())
    } else {
        Box::new(return_b())
    }
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the supplied Rust reproducer for map_or_else, comparing its inferred closure return types with the explicit Box<dyn Tag> casts and the equivalent if statement. Trace the compiler's handling of distinct impl Trait opaque types and type inference; done means the original example compiles without casts and the regression is covered by compiler testing.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.