Search code examples
webassembly

WebAssembly expecting unreachable code with if else


Why doesn't WebAssembly understand that when there's an if and an else, and both of them return, there's no way to get passed that if/else statement?

Consider the following wat. It's impossible to get passed the if/else, but wat2wasm still complains that not all paths return an i32.

(module
  (func (result i32)
    i32.const 0
    i32.const 1
    i32.gt_s
    (if
      (then
        i32.const 50
        return
      )
      (else
        i32.const 100
        return
      )
    )
  )
)

The error I'm getting is:

6:5: error: type mismatch in implicit return, expected [i32] but got []
    (if

The only way I can get around it is to add an explicit return after the if/else, even if that's not reachable:


(module
  (func (result i32)
    i32.const 0
    i32.const 1
    i32.gt_s
    (if
      (then
        i32.const 50
        return
      )
      (else
        i32.const 100
        return
      )
    )
    i32.const 100
    return 
  )
)

Solution

  • You can't do that because the items present on the stack at the end of the function must match the function's return type, no matter whether it is actually possible to reach the end of the function's body.

    Here is the relevant part of the standard. It specifies that every valid function has a body with a single expression. In this case, the expression is the sequence of instructions in your function body. For the function to be valid, the expression must have the same type as the function's return type. In your first example, that isn't the case, because the expression has the type [], while the function has the return type [i32]. The validator ultimately doesn't care whether it's possible to reach the code after the two returning branches, it just sees that the types don't match and throws an error.

    A more canonical way to get around this may be to use the unreachable instruction instead of returning a dummy value:

    (module
      (func (result i32)
        i32.const 0
        i32.const 1
        i32.gt_s
        (if
          (then
            i32.const 50
            return
          )
          (else
            i32.const 100
            return
          )
        )
        unreachable
      )
    )