Confusing diagnose message in which the opaque types from RPIT are reported as unrelated types
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
Code
pub struct Bar;
trait BarBar {}
impl BarBar for Bar {}
pub struct Foo<T> {
t: T,
bar: Bar,
}
pub type Foo1 = Foo<i32>;
pub type Foo2 = Foo<String>;
pub trait FooFoo {
fn bar(self) -> impl BarBar;
}
impl<T> FooFoo for Foo<T> {
fn bar(self) -> impl BarBar {
self.bar
}
}
enum Oh {
FooInt(Foo1),
FooStr(Foo2),
}
impl FooFoo for Oh {
fn bar(self) -> impl BarBar {
use Oh::*;
match self {
FooInt(fi) => fi.bar(),
FooStr(fs) => fs.bar(),
}
}
}
Current output
error[E0308]: `match` arms have incompatible types
--> src\lib.rs:45:27
|
30 | fn bar(self) -> impl BarBar {
| -----------
| |
| the expected opaque type
| the found opaque type
...
43 | / match self {
44 | | FooInt(fi) => fi.bar(),
| | -------- this is found to be of type `impl BarBar`
45 | | FooStr(fs) => fs.bar(),
| | ^^^^^^^^ expected `i32`, found `String`
46 | | }
| |_________- `match` arms have incompatible types
|
= note: expected opaque type `impl BarBar` (`i32`)
found opaque type `impl BarBar` (`String`)
= note: distinct uses of `impl Trait` result in different opaque types
help: you could change the return type to be a boxed trait object
|
41 - fn bar(self) -> impl BarBar {
41 + fn bar(self) -> Box<dyn BarBar> {
|
help: if you change the return type to expect trait objects, box the returned expressions
|
44 ~ FooInt(fi) => Box::new(fi.bar()),
45 ~ FooStr(fs) => Box::new(fs.bar()),
|
For more information about this error, try `rustc --explain E0308`.
Desired output
// I don't know. I expected the code to compile at first,
// but maybe I am missing something so that's arguable.
// However, anyway, neither fi.bar() is i32 nor fs.bar() is String, so the diagnose parts:
fs.bar(),
^^^^^^^^ expected `i32`, found `String`
// ...and:
= note: expected opaque type `impl BarBar` (`i32`)
found opaque type `impl BarBar` (`String`)
// seem confusing to me.
Rationale and extra context
Why I expected the code to compile:
In my understanding, RPITIT is a sugar for associated types. So I tried the "desugared" code and that compiles:
pub struct Bar;
trait BarBar {}
impl BarBar for Bar {}
pub struct Foo<T> {
t: T,
bar: Bar,
}
pub type Foo1 = Foo<i32>;
pub type Foo2 = Foo<String>;
pub trait FooFoo {
type BarBarT: BarBar;
fn bar(self) -> Self::BarBarT;
}
impl<T> FooFoo for Foo<T> {
type BarBarT = Bar;
fn bar(self) -> Bar {
self.bar
}
}
enum Oh {
FooInt(Foo1),
FooStr(Foo2),
}
impl FooFoo for Oh {
type BarBarT = Bar;
fn bar(self) -> Bar {
use Oh::*;
match self {
FooInt(fi) => fi.bar(),
FooStr(fs) => fs.bar(),
}
}
}
But the code using RPITIT doesn't. I don't know what is going on there.
Other cases
I also tried this code:
pub struct Bar;
trait BarBar {}
impl BarBar for Bar {}
pub struct Foo<T> {
t: T,
bar: Bar,
}
pub type Foo1 = Foo<i32>;
pub type Foo2 = Foo<String>;
pub trait FooFoo {
fn bar(self) -> impl BarBar;
}
impl FooFoo for Foo1 {
fn bar(self) -> impl BarBar {
self.bar
}
}
impl FooFoo for Foo2 {
fn bar(self) -> impl BarBar {
self.bar
}
}
enum Oh {
FooInt(Foo1),
FooStr(Foo2),
}
impl FooFoo for Oh {
fn bar(self) -> impl BarBar {
use Oh::*;
match self {
FooInt(fi) => fi.bar(),
FooStr(fs) => fs.bar(),
}
}
}
And the code above cannot compile either:
error[E0308]: `match` arms have incompatible types
--> src\lib.rs:39:27
|
19 | fn bar(self) -> impl BarBar {
| ----------- the expected opaque type
...
24 | fn bar(self) -> impl BarBar {
| ----------- the found opaque type
...
37 | / match self {
38 | | FooInt(fi) => fi.bar(),
| | -------- this is found to be of type `impl BarBar`
39 | | FooStr(fs) => fs.bar(),
| | ^^^^^^^^ expected opaque type, found a different opaque type
40 | | }
| |_________- `match` arms have incompatible types
|
= note: expected opaque type `impl BarBar`
found opaque type `impl BarBar`
= note: distinct uses of `impl Trait` result in different opaque types
help: you could change the return type to be a boxed trait object
|
35 - fn bar(self) -> impl BarBar {
35 + fn bar(self) -> Box<dyn BarBar> {
|
help: if you change the return type to expect trait objects, box the returned expressions
|
38 ~ FooInt(fi) => Box::new(fi.bar()),
39 ~ FooStr(fs) => Box::new(fs.bar()),
|
For more information about this error, try `rustc --explain E0308`.
However this case above makes sense for me since there are separate trait implementations. The diagnose message is also clear.
Edit:
I also came up with a case which does not require RPITIT, just RPIT. The case below gives a similar error message to the "Current output" section.
pub struct Bar;
trait BarBar {}
impl BarBar for Bar {}
pub struct Foo<T> {
t: T,
bar: Bar,
}
pub type Foo1 = Foo<i32>;
pub type Foo2 = Foo<String>;
pub trait FooFoo {
fn bar(self) -> impl BarBar;
}
fn bar<T>(f: Foo<T>) -> impl BarBar {
f.bar
}
enum Oh {
FooInt(Foo1),
FooStr(Foo2),
}
fn oh_bar(oh: Oh) -> impl BarBar {
use Oh::*;
match oh {
FooInt(fi) => bar(fi),
FooStr(fs) => bar(fs),
}
}
Rust Version
rustc 1.88.0 (6b00bc388 2025-06-23)
binary: rustc
commit-hash: 6b00bc3880198600130e1cf62b8f8a93494488cc
commit-date: 2025-06-23
host: x86_64-pc-windows-gnu
release: 1.88.0
LLVM version: 20.1.5
Anything else?
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the diagnostic with the Rust code in the issue using rustc 1.88.0, then compare the RPITIT and RPIT cases with the associated-type version. Done means the incompatible-match diagnostic no longer presents the opaque types as i32 and String, while still explaining why the arms cannot be unified.
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
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100