Skip to content

Inherent impl blocks on trait objects don't check for coherence or overlapping impls until called #38967

Closed
@QuietMisdreavus

Description

@QuietMisdreavus

Consider the following snippet:

trait A {}

trait B {}

trait C<T> {}

impl <T: A> C<T> { fn asdf(&self) { println!("asdf"); } }

impl <T: B> C<T> { fn asdf(&self) { println!("asdf!!"); } }

struct Z {}
impl A for Z {}
impl B for Z {}

struct W {}
impl C<Z> for W {}

fn main() {
    let asdf = Box::new(W {}) as Box<C<Z>>;
    
    asdf.asdf();
}

When asdf.asdf() is called, which impl should be used? Is it possible to select one impl or the other?

When discussing this in #rust, @mbrubeck also found that impls on trait objects don't check for overlap at all:

trait C<T> {}

impl<T> C<T> { fn asdf(&self) {} }
impl<T> C<T> { fn asdf(&self) {} }

struct W {}
impl<T> C<T> for W {}

fn main() {
    let b = Box::new(W {}) as Box<C<()>>;
    b.asdf();
}

In both of these examples, taking out the call to asdf() makes the sample compile, meaning that it's only upon method resolution that this conflict is found. The former can be ruled out as a coherence issue, and the latter is directly an overlapping impl, that wouldn't be allowed on a regular struct/enum.

cc #36889, per talchas in #rust

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-trait-systemArea: Trait systemP-mediumMedium priorityT-compilerRelevant to the compiler 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