An !
argument is a contradiction at compile time, because you cannot obtain a !
value in the first place to call the function with. Merely obtaining a !
is undefined behaviour. The compiler doesn't have to emit the function body at all; it's dead code. And all dead code is equivalent.
There is no contradiction in different impls having different associated types. The proposal is to allow !
to have multiple impls of a single trait in certain conditions; namely, for 'purely negative' traits I mentioned. Impls of such traits for !
can only differ in their choice of associated types, and are otherwise equivalent. Choosing a specific impl is therefore a mere matter of type inference, no different from choosing a specific instance of a generic type.
Of course this would require re-working some fundamentals. For one thing, instantiating a generic with a trait bound would require establishing an identity for the impl and passing it along with the type; the compiler can no longer 're-derive' the impl each time the type is used. But it's not a priori inconsistent.
Also, general impl-relevance has been requested before:
@canndrew's proposal leaves vacuous impls for !
anonymous, because type inference is sufficient to distinguish between them – at least in the motivating cases. I can imagine some (admittedly rather contrived) cases where it wouldn't be:
trait Foo {
type Iter: Iterator;
}
struct Bar;
impl Foo for Bar {
type Iter = !;
}
What is <Bar as Foo>::Iter::Item
? A specific impl of Iterator
for !
would have to be chosen by the time Foo
is implemented for Bar
, but there is no syntax to disambiguate it.