Skip to content

wasm: emit a clean error for scalar ?T/!T returns instead of an internal ICE - #27516

Merged
medvednikov merged 1 commit into
vlang:masterfrom
enghitalo:fix-wasm-scalar-option-result-ice
Jun 26, 2026
Merged

wasm: emit a clean error for scalar ?T/!T returns instead of an internal ICE#27516
medvednikov merged 1 commit into
vlang:masterfrom
enghitalo:fix-wasm-scalar-option-result-ice

Conversation

@enghitalo

Copy link
Copy Markdown
Contributor

Description

On the native wasm backend, a function returning a scalar option/result (e.g. fn f() ?int) aborts the compiler with an internal ICE instead of the intended user-facing error:

$ v -b wasm -o /tmp/x.wasm opt.v
wasm error: get_wasm_type: unreachable type 'int' ast.TypeInfo(ast.UnknownTypeInfo{})

Root cause

In fn_decl (vlib/v/gen/wasm/gen.v), the return-type match rts.info handles option/result only:

  • inside the MultiReturn arm (option types are not implemented),
  • after the match (result types are not implemented),
  • and for the void-option case (returning a void option is forbidden).

A scalar ?T/!T return is not a MultiReturn, so it falls into the else arm and calls get_wasm_type(rt) on the option/result-wrapped type before any guard runs — and that aborts with the unreachable type ... UnknownTypeInfo ICE. The existing guards were effectively dead code for this case.

Fix

Guard option/result in the non-void scalar arm, before lowering the type. g.v_error already exits, so this short-circuits before get_wasm_type.

After

$ v -b wasm -o /tmp/x.wasm opt.v
opt.v:1:8: error: option types are not implemented
    1 | fn f() ?int {
      |        ~~~~
  • fn f() !intresult types are not implemented (located).
  • fn f() ? (void option) → still returning a void option is forbidden (unchanged).
  • Normal returns and the rest of the wasm test suite are unaffected.

This is in the spirit of #27451 (replace internal get_wasm_type ICEs with clean errors), covering the scalar option/result cases specifically.

Tests

Adds vlib/v/gen/wasm/tests/scalar_option_result_error_test.v (asserts the located error is produced and the internal ICE string does not leak). Full vlib/v/gen/wasm/tests/ suite passes; v fmt clean.

Checklist

  • tests pass locally (v test vlib/v/gen/wasm/tests/)
  • v fmt -w applied

…nternal ICE

A function returning a scalar option/result (e.g. `fn f() ?int`) reaches the
`else` arm of `fn_decl`'s return-type match and calls `get_wasm_type` on the
option/result-wrapped type, which aborts with an internal
`get_wasm_type: unreachable type 'int' ast.TypeInfo(ast.UnknownTypeInfo{})`
instead of the intended located "option/result types are not implemented" user
error. The existing guards only run inside the MultiReturn arm, after the match
(result), or for the void-option case, so they were dead code for a scalar
`?T`/`!T` return.

Guard option/result before lowering the type in the non-void scalar arm. The
void-option case still reports "returning a void option is forbidden".

Adds vlib/v/gen/wasm/tests/scalar_option_result_error_test.v.
@medvednikov
medvednikov merged commit 5bc4b1a into vlang:master Jun 26, 2026
82 of 85 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants