Is the sole distinction between the two types you proposed that one is in the argument position and the other is in the return type position?
If so, then I think they should be the same type.
A function with argument position ! can never be called, because you can't pass a value of ! to it (thus it "never starts calculating").
A function with return position ! may never return, because it can't return a value of !. It is not necessarily something that never ends, it just doesn't return to its caller.
But this distinction comes from the duality of the function argument vs return position, not from the type. The arguments provide a requirement to the caller and a guarantee to the function, while the return type is a requirement to the function and a guarantee to the caller.
The reason you can't implicitly convert from u64 to i16 is that it's ill-defined in some cases.
It's just fine to be able to implicitly convert from ! to anything else, because it is well-defined and unambiguous in all cases (because there are no cases).
You could still write this function with !never if it is truly equivalent to enum !never {} (playground)
fn foo<T>(p: !never) -> T { match p {} }
even if it weren't, it'd still also be valid to write
fn foo<T>(p: !never) -> T { unreachable!() }
since you have a type-checked guarantee that this code is unreachable.
These functions aren't useless, they are very useful when you need to map types, e.g. if you need to take a Result<(), !> and make a Result<(), Error> you can just result.map_err(absurd) (absurd is the name I've seen given to this function before, I don't recall where it comes from).
Your example is nonsense, the other example is reasonable because if I'm given a value that cannot exist then I have an absurd and I'm allowed to produce anything.
I don't understand what you mean with "repair this situation". This code is valid today and must remain valid tomorrow, you cannot change that.
id_int :: Int -> Int
id_int x = x
id_str :: String -> String
id_str x = x
id :: a -> a
id x = x
-- ERROR: type mismatch
id_a_b :: a -> b
id_a_b x = x
-- ERROR: type mismatch
id_void :: Void -> a
id_void x = x
which corresponds to rust
fn id_int(x: i32) -> i32 { x }
fn id_str(x: &str) -> &str { x }
fn id<T>(x: T) -> T { x }
// Nonsense is here:
fn id_nonsense<T>(x: !) -> T { x }
The only reason your id_void doesn't work in Haskell is that Haskell doesn't allow an implicit conversion between those types. But as I said above, it's entirely reasonable for Rust to perform this implicit conversion, because there is no ambiguity about how to convert ! to another type.
What is a type of panic!() in expression if cond { 42i32 } else { panic!() } if RUST have a RULE "An if expression evaluates to the same value as the executed block, or () if no block is evaluated. An if expression must have the same type in all situations."
I'm not 100% sure how rust/std currently implements it, but there are at least 2 reasonable possibilities:
panic!()'s type is !. The ! gets implicitly converted into i32, so that the block has the type i32. I think this is what actually happens, at least in nightly.
panic!() behaves like fn panic<T>() -> T, so after type inference, the type of panic!()in that context is i32.
I think case 2 aligns with your concept of "any"!, but it does not actually involve any types other than i32 – only functions with type parameters, and it would be a conceptual mistake to confuse type parameters with types.
Note that if cond { 42i32 } else { panic!(); } is also well typed, even though the block with panic doesn't have a trailing expression and so should have type (). The panic!(); also doesn't have to be the last statement.