Why does `panic!()` (and other macros that make panics) return `()` instead of `!`?

In type theory, the return type of a function that never returns is the bottom type. In Rust, a panic call never returns, and the bottom type is !.
However, Rust analyzer annotates the return type of panic!() as (). Is this an mistake?
screenshot

You're probably on edition <=2021. This is called the never type fallback. On edition >=2024 it returns !.

Yes. Time for update.
screenshot

There's some fairly complex history to this change. I wasn’t around for the beginning, but I understand it to be roughly as follows:

  • In Rust 1.0, ! wasn’t really a type at all, but like void in C: a marker that a function diverges (does not return). The return type of such functions was considered (), even though that value would never be seen.
  • RFC 1216 proposed that ! should become a proper type, which coerces to any other type.
  • The compiler was changed to implement RFC 1216, and people discovered that this broke lots of code expecting (). As a stopgap, ! was made to coerce to () whenever actually used (or something like that; this description is probably wrong.)
  • Much debate over how to solve this problem occurred.
  • In 1.80, a lint was added to warn when !-to-() fallback occurs in unsafe code (since that would mean that the unsafe code might become unsound when the actual, uninhabited, ! type was in use instead).
  • In 1.81, a lint was added to warn when replacing () fallback with actual ! would cause a type error (to detect code incompatible with the change to actual !).
  • In 1.85, the 2024 edition was added, in which ! doesn’t fallback to () any more (but you still can’t refer to the ! type.
  • Attempts to fully stabilize ! as a nameable type, and eliminate the () fallback entirely, are ongoing.