Search code examples
gofor-loopcontrol-flow

Missing return statement in for loop with condition


I have noticed that when I write the following code, the compiler yields a missing return statement error:

// Similar loops make sense in retry patterns
// but this is just a simple example
func TestMethod() int {
    for i := 0; i < 10; i++ {
        return 0
    }
}

this is while the following compiles without any error:

func TestMethod() int {
    for {
        return 0
    }
}

The fist code is both logically and technically fine as there is no possible way the method cannot return. Is there any reason why the compiler is showing that error? or it is some sort of a missing logic or bug?


Solution

  • Expanding @Cerise Limón's comment into an answer, the assertion that "the first code is .. technically fine" is wrong.

    The Go language specification says this:

    If the function's signature declares result parameters, the function body's statement list must end in a terminating statement.

    And also this:

    [terminating statements include] a "for" statement in which:
    - there are no "break" statements referring to the "for" statement, and
    - the loop condition is absent, and
    - the "for" statement does not use a range clause.

    (emphasis added by me)

    Examining the code in the first function we can see that these conditions of the specification are not met:

    func TestMethod() int {
        for i:= 0; i < 10; i++ {
            return 0
        }
    }
    

    The function has a result parameter (the int return value) so must end in a terminating statement, but the final statement of this function is a for statement with a condition, which is not a "terminating statement", as defined by the specification.

    It may seem odd but is, in fact, technically correct.

    Bonus Material

    So why is the second function fine?

    func TestMethod() int {
        for {
            return 0
        }
    }
    

    In this case, the final statement in this function is a for with no condition and with no break statement referring to the for loop, satisfying the language specification definition of a terminating statement.

    There is logic at work.

    If a for statement with no condition contains a break, then the loop may terminate so the function needs a return statement.

    If a for statement with no condition does not contain a break (and has no return statements), then the loop will not terminate (at least, not as the result of a normal execution path that requires a function return value).

    Also worth noting is that there is no control flow analysis to determine whether any break statements are reachable; they only need to exist. e.g. the following will also trigger a "missing return" compilation error, even though the break is demonstrably unreachable:

    func foo() int {
        for {
            if false {
                break
            }
            return 0
        }
        // <-- error: missing return
    }