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
)
)
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
)
)