-
Notifications
You must be signed in to change notification settings - Fork 14k
Description
The Rust compiler incorrectly identifies completely unrelated types as equivalent when checking for conflicting trait implementations, resulting in E0119 errors where none should occur. Specifically, in my use, the compiler reports that impl Display for SceneError conflicts with impl Display for <InternalDomain as Domain>::Event, even though these resolve to completely different types with different names, variants, and no relationship.
I tried this code:
Project structure with multiple files:
Cargo.toml:
[package]
name = "compiler-bug-repro"
version = "0.1.0"
edition = "2021"
[dependencies]
myapp-common = { path = "../myapp-common" }myapp-common/Cargo.toml:
[package]
name = "myapp-common"
version = "0.1.0"
edition = "2021"myapp-common/src/lib.rs:
pub mod domain;
pub mod internal_domain;
#[macro_export]
macro_rules! impl_domain_msg_display {
($domain:ty) => {
impl std::fmt::Display for <$domain as Domain>::Event {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl std::fmt::Display for <$domain as Domain>::Command {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl std::fmt::Display for <$domain as Domain>::Query {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
};
}myapp-common/src/domain.rs:
pub trait Domain {
type Event;
type Command;
type Query;
}myapp-common/src/internal_domain.rs:
use crate::domain::Domain;
#[derive(Debug, Clone)]
pub struct InternalDomain;
crate::impl_domain_msg_display!(InternalDomain);
impl Domain for InternalDomain {
type Event = InternalEvent;
type Command = InternalCommand;
type Query = InternalQuery;
}
#[derive(Debug, Default, Clone, Copy)]
pub enum InternalEvent {
#[default]
Noop,
}
#[derive(Debug, Clone, Default)]
pub enum InternalCommand {
#[default]
Noop,
}
#[derive(Debug, Clone)]
pub enum InternalQuery {
Noop,
}src/lib.rs:
mod error;
pub use error::*;src/error.rs:
#[derive(Debug, Clone)]
pub enum SceneError {
TimedOut,
Internal(std::sync::Arc<dyn std::error::Error + Send + Sync + 'static>),
}
impl std::error::Error for SceneError {}
impl std::fmt::Display for SceneError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}I expected to see this happen: The code should compile successfully, as SceneError and <InternalDomain as Domain>::Event (which resolves to InternalEvent) are completely different types with different names, different variants, and no relationship. Each should be able to have its own Display implementation.
Instead, this happened: The compiler reports E0119 (conflicting implementations):
error[E0119]: conflicting implementations of trait `std::fmt::Display` for type `<InternalDomain as myapp_common::domain::Domain>::Event`
--> src/error.rs:13:1
|
13 | impl std::fmt::Display for SceneError {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `myapp_common`:
- impl std::fmt::Display for <InternalDomain as myapp_common::domain::Domain>::Event;
Additional Evidence
The issue persists even when:
- Changing
SceneErrorto a completely different name likeSceneErrorTest - Using completely different enum variants
- Removing all imports from
myapp-common
This suggests the compiler is incorrectly unifying types during trait coherence checking.
Meta
rustc --version --verbose:
rustc 1.90.0 (5bc8c42bb 2024-05-18)
binary: rustc
commit-hash: 5bc8c42bb498327e81c4c63d5d24f3dbbea6f2ab
commit-date: 2024-05-18
host: x86_64-unknown-linux-gnu
release: 1.90.0
LLVM version: 18.1.0
Also tested on:
rustc 1.91.1 (ed61e7d7e 2025-11-07)
binary: rustc
commit-hash: ed61e7d7e242494fb7057f2657300d9e77bb4fcb
commit-date: 2025-11-07
host: x86_64-unknown-linux-gnu
release: 1.91.1
LLVM version: 21.1.2