upvote
Do you have an example of a piece of code that behaves in a surprising way because of this rule?
reply
I don’t need to write examples because the article has plenty. All the fixes that Waffle needs to fix are precisely the code that behaves in a surprising way.
reply
None of this has anything bad to say about coercion or fallback, it's a consequence of the fact that Rust is an expression-oriented language which had expressions (like `loop {}`) which logically evaluated to the never type when in return position, and yet did not have the machinery in place to support it as a proper concept anywhere outside of return position, and so they chose the unit type as a relatively benign alternative in those contexts, which caused no problems whatsoever until the day came when they decided to actually implement the never type.
reply
Let's avoid using the term "subtyping", which as you say is irrelevant here. The reason you need diverging functions to satisfy arbitrary type obligations (i.e. to coerce to any other type) is because otherwise anything as simple as `let x = Some(42); x.unwrap();` just completely fails to compile, because `unwrap` is internally just:

    fn unwrap<T>(t: Option<T>) -> T {
        match t {
            Some(foo) => foo,
            None => panic!()
        }
    }
...and this function couldn't otherwise typecheck because it doesn't return a `T` in the `None` branch. You need coercion here.
reply
No you don’t need coercion. You only need polymorphism. The type of `panic!()` could be an arbitrary U, which unifies just fine with the type T here.

Generally languages with such polymorphism have a never type only because they don’t also support impredicative polymorphism.

reply
And then once you have `fn foo<T>() -> T`, what do you write in the body that allows it to typecheck?
reply