Advanced Traits

Orphan Rules in Depth

The orphan rule (E0117) is the crate-boundary coherence rule that forbids implementing a foreign trait for a foreign type. In its full RFC 2451 formulation (rebalanced coherence), an implementation impl<P1..=Pn> ForeignTrait<T1..=Tm> for T0 is legal only if at least one local type appears in T0..=Tm before any uncovered generic type parameter Pi.

Formal Definition of Covered vs. Uncovered Type Parameters

Given impl<P1..=Pn> Trait<T1..=Tm> for T0:

  • A type parameter Pi is uncovered if it appears directly as T0 or one of T1..=Tm (or behind a fundamental type like &Pi, &mut Pi, or Box<Pi>), rather than wrapped inside a non-fundamental type constructor like Vec<Pi> or LocalWrapper<Pi>.
  • When Trait is a foreign trait (such as From, TryFrom, Add, or Display), at least one local type LocalType must appear in the sequence T0, T1, ..., Tm strictly to the left of the first uncovered type parameter P.
Sequence of Positions in `impl<T> ForeignTrait<T1, T2> for T0`:
  Position 0: `T0` (Self type)
  Position 1: `T1` (1st trait parameter)
  Position 2: `T2` (2nd trait parameter)

Rule: Moving left-to-right (T0 -> T1 -> T2), you MUST hit a `LocalType`
      BEFORE hitting an uncovered generic parameter `T`!

Examples of Legal vs. Illegal Foreign Trait Implementations

Suppose Local is a struct defined in the current crate and From<T> is the foreign trait from std::convert:

impl Header Position T0 (Self) Position T1 Legal under Orphan Rule? Reason
impl From<u32> for String String (foreign) u32 (foreign) No (E0117) No local type appears anywhere
impl<T> From<T> for Local Local (local) T (uncovered) Yes Local appears at T0, before T at T1
impl<T> From<Local> for Vec<T> Vec<T> (T is covered) Local (local) Yes! T is covered inside Vec<T>, and Local appears at T1
impl<T> From<Local> for T T (uncovered!) Local (local) No (E0210) Uncovered T appears at T0, before Local at T1
// ❌ does not compile
struct LocalWrapper(u32);

// Rejected (E0210): uncovered type parameter `T` appears at `T0` (Self)
// BEFORE `LocalWrapper` appears at `T1`!
impl<T> From<LocalWrapper> for T {
    fn from(_: LocalWrapper) -> T {
        todo!()
    }
}

fn main() {}
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`LocalWrapper`)
 --> src/main.rs:6:6
  |
6 | impl<T> From<LocalWrapper> for T {
  |      ^ type parameter `T` must be covered by another type when it appears before the first local type (`LocalWrapper`)
  |
  = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type

Why Covered Type Parameters (Vec<T>) Are Allowed Before Local

In impl<T> From<LocalList<T>> for Vec<T>, the self type T0 is Vec<T> (where T is covered by Vec), and the first trait parameter T1 is LocalList<T> (a local type). Because T is covered in T0 and a local type appears at T1, this implementation is completely legal in stable Rust!

struct LocalPair<T>(T, T);

// Legal! `T` in `Vec<T>` is covered by `Vec`, and `LocalPair<T>` is a local type at `T1`:
impl<T> From<LocalPair<T>> for Vec<T> {
    fn from(pair: LocalPair<T>) -> Self {
        vec![pair.0, pair.1]
    }
}

fn main() {
    let pair = LocalPair("first", "second");
    let vec: Vec<&str> = Vec::from(pair);
    println!("converted to foreign Vec<T>: {:?}", vec);
}
converted to foreign Vec<T>: ["first", "second"]

Fundamental Types (&T, &mut T, Box<T>)

References (&T, &mut T) and Box<T> are marked #[fundamental] in the standard library. Unlike Vec<T>, a #[fundamental] type constructor does not cover its inner type parameter: Box<T> is treated as uncovered T, whereas Box<LocalType> is treated as a local type (so impl ForeignTrait for Box<LocalType> is allowed!).