Odd error when semi is put after break or continue

Here’s the code:

script {
    fun main() {
        loop {
            break; // this semi here causes error
        }
    }
}
   ┌── /scripts/script.move:4:18 ───
   │
 4 │             break;
   │                  ^ Unreachable code. This statement (and any following statements) will not be executed. In some cases, this will result in unused resource values.
   │

For some reason the only possible way to use break and continue (and return) is without semicolon in the end, when these statements are in “open scope”.

But! It is possible to put semi after when they are paired with if:

script {
    fun main() {
        loop {
            if (true) break;
            if (true) continue;
            if (true) return;
            if (true) break // also valid - but it's the last expression
        }
    }
}

I don’t know what to ask. Maybe if you did it on purpose? Though I should say that for me this case is not obvious and even confusing every time I use these statements.

1 Like

Semicolons in Move are used as separators between expressions in a sequence, not as terminators at the ends of statements. Because of that, you don’t need a semicolon at the end of a sequence. If you have one, there is an implied unit expression “()” after the semicolon. The compiler error about unreachable code is saying that the implied code after the “break” is unreachable.

Pairing with “if” is not what makes the semicolons valid (at least not directly). Your example has 4 “if” expressions in a sequence, so you need semicolons as separators between them. (And, this works with “if” because otherwise, you’d run into unreachable code errors.)

Am I right when saying that semicolon in “compiler terms” automatically puts empty expression afterwards? So in Rust it would be: expression; ().

You may have misunderstood my point with “ifs”. I can write it in this way:

script {
    fun main() {
        loop {
            if (true) break;
       }
   }
}

If is an expression, right? Then why can I put semi afterwards?

About compiler error. What actually cases confusion is error pointing at semicolon saying that semi is an unreachable code. How can semi be executed? It’s just not clear to me (nor to anybody else who I asked).

I’ll be updating the error message for this case to hopefully make it less confusing.

As @bobwilson stated, they behave as separators, almost to the point of binary operators. So you could think of them as a funny function fun semi<A, B>(a: A, b: B): B { ... } where we then write them as a; b

In the case of trailing semicolons, they add () after the trailing semicolon. So if you have

loop {
    break;
}

This is equivalent to

loop {
    break;
    () // dead code
}

Thus you will get an error that the code after the break is unreachable. It looks funny in the error message as there is no () to point to, and we have to then point to the ;

In the case of the if, it is because the ; is binding to the if not the break. That is

loop {
    if (cond) break;
}

is equivalent to

loop {
    if (cond) break else ();
    () // dead code
}

I have updated the error message so it will now look something like:

error: 

   ┌── tests/move_check/liveness/trailing_semi.move:4:18 ───
   │
 4 │             break;
   │                  ^ Unnecessary trailing ';'
   ·
 4 │             break;
   │             ----- Divergent expression. Any code following the evaluation of this expression will be dead
   ·
 4 │             break;
   │                  - A trailing ';' in an expression block implicitly adds a '()' value after the semicolon. That '()' value will not be reachable
   │
1 Like

Thanks a lot! Now is much better.