Skip to content

Default impls cannot reliably expose type inequality #29499

Closed
@ebfull

Description

@ebfull
trait NotSame { }
impl NotSame for .. { }
impl<A> !NotSame for (A, A) { }

If I understand default impls right, it should be possible to express S != T using (S, T): NotSame. In fact this does work in some situations, but not generally.

doesn't work:

#![feature(optin_builtin_traits)]

trait NotSame { }
impl NotSame for .. { }
impl<A> !NotSame for (A, A) { }

fn f<T, U>(_: T, _: U) where (T, U): NotSame {}

struct S;
struct Z;

fn main() {
    f(S, Z); // error: the trait `NotSame` is not implemented for the type `(_, _)`
    f(S, S); // error: the trait `NotSame` is not implemented for the type `(_, _)`
}

but this does:

#![feature(optin_builtin_traits)]

use std::marker::PhantomData;

trait NotSame { }
impl NotSame for .. { }
impl<A> !NotSame for (A, A) { }

struct Choose<S, P>(PhantomData<(S, P)>);
struct Finally<P>(PhantomData<P>);

pub trait Chooser<T> {
    fn num() -> usize;
}

impl<S, Q> Chooser<S> for Choose<S, Q> {
    fn num() -> usize { 0 }
}

impl<S> Chooser<S> for Finally<S> {
    fn num() -> usize { 0 }
}

impl<R, S, Q: Chooser<S>> Chooser<S> for Choose<R, Q>
    where (S, R): NotSame
{
    fn num() -> usize { Q::num().checked_add(1).unwrap() }
}

fn main() { }

Perhaps it only works when trying to ensure there are no conflicting impls? Perhaps it's not meant to work, and the second example is a hole?

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.T-langRelevant to the language 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