I have this Rust code:
use std::fmt;
struct S {
    a: i32,
    b: i32,
    c: Vec<String>,
}
impl fmt::Display for S {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match &self.a {
            -1 => {
                if &self.b < &0 {
                    write!(f, "Invalid a & b\n")
                } else {
                    write!(f, "Invalid a, valid b\n")
                }
            }
            _ => write!(f, "Valid a & b\n"),
        };
        // not including this above semicolon causes an error
        if &self.c.len() > &0 {
            write!(f, "{}", &self.c.join("\n"))
        } else {
            write!(f, "")
        }
    }
}
fn main() {
    let s = S {
        a: 0,
        b: 0,
        c: vec![String::from("something")],
    };
    println!("{}", s)
}
The match is there to check whether arguments a and b are valid, and the if statement below is to check whether argument c has at least 1 string in it to print out.
This code fails when I don't include a semicolon just after the match statement:
error[E0308]: mismatched types
  --> src/main.rs:14:21
   |
13 | /                 if &self.b < &0 {
14 | |                     write!(f, "Invalid a & b\n")
   | |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `std::result::Result`
15 | |                 } else {
16 | |                     write!(f, "Invalid a, valid b\n")
17 | |                 }
   | |_________________- expected this to be `()`
   |
   = note: expected unit type `()`
                   found enum `std::result::Result<(), std::fmt::Error>`
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
help: try adding a semicolon
   |
2  | ($ dst . write_fmt ($ crate :: format_args ! ($ ($ arg) *));)
   |                                                            ^
help: consider using a semicolon here
   |
17 |                 };
   |                  ^
error[E0308]: mismatched types
  --> src/main.rs:16:21
   |
13 | /                 if &self.b < &0 {
14 | |                     write!(f, "Invalid a & b\n")
15 | |                 } else {
16 | |                     write!(f, "Invalid a, valid b\n")
   | |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `std::result::Result`
17 | |                 }
   | |_________________- expected this to be `()`
   |
   = note: expected unit type `()`
                   found enum `std::result::Result<(), std::fmt::Error>`
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
help: try adding a semicolon
   |
2  | ($ dst . write_fmt ($ crate :: format_args ! ($ ($ arg) *));)
   |                                                            ^
help: consider using a semicolon here
   |
17 |                 };
   |                  ^
I am trying to make sense of what this error means. I know that semicolons are used to discard the result of an expression, and it seems by putting a semicolon after a match I am discarding the result of the match expression. Looking at the error message it says that it expected a () type instead of the type std::fmt::Result on the lines where a write! is performed. 
- Why does it expect this 
()type, when all branches of the match statement and its inner if are callingwrite!and returning astd::fmt::Result? - When I don't include the second part of the code that checks the length of the argument 
c, suddenly the code works even without the semicolon. Why does it not error out without a semicolon when the second if that checks forc.len() > 0is omitted?