A strange error message about diverging function call


#1

this the code:

    fn main() {
        fn diverging_fun() -> String {
            println!("diverging function will never return.");
            panic!("diverging");
        }
        
        fn test_diverging(condition:bool) ->i32 {
            if condition {
                3 + 5
            } else {
                diverging_fun();
                //diverging_fun()
            }
        }
        
        test_diverging(true);
    }

1. When the function call diverging_fun() with semicolon, the error message:

<anon>:17:9: 21:10 error: if and else have incompatible types:
     expected `i32`,
        found `()`
    (expected i32,
        found ()) [E0308]

2. When the function call diverging_fun() without semicolon:

<anon>:12:21: 12:36 error: mismatched types:
expected `i32`,
found `collections::string::String`
(expected i32,
found struct `collections::string::String`) [E0308]    

the second is normal, but the first one, the statement diverging_fun(); return a '()' ?


#2

This is because your diverging_fun() is not typed as a diverging function; it’s typed as returning String, and so any code that uses it is going to assume that that is the case. Rust only considers the function signature when typechecking the call site; this saves a lot of processing time and complexity. This is also why we don’t have function signature inference. In this case, divergence only applies to the body of the function, as an excuse for why it doesn’t actually return String.

If you change the signature of diverging_fun() to reflect the fact that it diverges:

fn diverging_fun() -> ! { /* ... */ }

Then it compiles.

By the way, any expression followed by a semicolon evaluates to (). That has nothing to do with divergence.