
wasmFullPass(`
  (module
    (import "env" "f" (func $f (result i32 i32 i32)))
    (func (export "run") (result i32)
      (call $f)
      i32.sub
      i32.sub))`,
             42,
             { env: { f: () => [52, 10, 0] } });

wasmFullPass(`
  (module
    (import "env" "f" (func $f (result i64 i64 i64)))
    (func (export "run") (result i64)
      (call $f)
      i64.sub
      i64.sub))`,
             42n,
             { env: { f: () => [52n, 10n, 0n] } });

wasmFullPass(`
  (module
    (import "env" "f" (func $f (result f32 f32 f32)))
    (func (export "run") (result i32)
      (call $f)
      f32.sub
      f32.sub
      i32.trunc_f32_s))`,
             42,
             { env: { f: () => [52.25, 10.5, 0.25] } });

wasmFullPass(`
  (module
    (import "env" "f" (func $f (result f64 f64 f64)))
    (func (export "run") (result i32)
      (call $f)
      f64.sub
      f64.sub
      i32.trunc_f64_s))`,
             42,
             { env: { f: () => [52.25, 10.5, 0.25] } });

// Multiple values are returned as an iterable; it doesn't have to be an array.
function expectMultiValuePass(f) {
    wasmFullPass(`
      (module
        (import "env" "f" (func $f (result i32 i32 i32)))
        (func (export "run") (result i32)
          (call $f)
          i32.sub
          i32.sub))`,
                 42,
                 { env: { f } });
}
function expectMultiValueError(f, type, pattern) {
    let module = new WebAssembly.Module(wasmTextToBinary(`
      (module
        (import "env" "f" (func $f (result i32 i32 i32)))
        (func (export "run") (result i32)
          (call $f)
          i32.sub
          i32.sub))`));

    let instance = new WebAssembly.Instance(module, { env: { f } } );
    assertErrorMessage(() => instance.exports.run(), type, pattern);
}

expectMultiValuePass(() => [52, 10, 0]);
expectMultiValuePass(() => [32, -10, 0]);
expectMultiValuePass(() => [52.75, 10, 0.5]); // Values converted to i32 via ToInt32.
expectMultiValuePass(() => [42, undefined, undefined]);
expectMultiValuePass(() => (function*() { yield 52; yield 10; yield 0; })());
expectMultiValuePass(() => (function*() { yield '52'; yield '10'; yield 0; })());

// Multi-value result must be iterable.
expectMultiValueError(() => 1, TypeError, /iterable/);
expectMultiValueError(() => 1n, TypeError, /iterable/);

// Check that the iterator's values are collected first, and that the
// length of the result is correct.
expectMultiValueError(() => [1], TypeError, /expected 3, got 1/);
expectMultiValueError(() => [1n], TypeError, /expected 3, got 1/);
expectMultiValueError(() => [52, 10, 0, 0], TypeError, /expected 3, got 4/);
expectMultiValueError(() => (function*() { yield 52; yield 10; yield 0; yield 0; })(),
                      TypeError, /expected 3, got 4/);

// Check that side effects from conversions are done in order.
{
    let calls = [];
    function log(x) { calls.push(x); return x; }
    function logged(x) { return { valueOf: () => log(x) } }
    expectMultiValuePass(() => [logged(52), logged(10), logged(0)]);
    assertEq(calls.join(','), '52,10,0');
}

function expectMultiValueResult(text, expected) {
    let instance = wasmEvalText(text);
    assertDeepEq(instance.exports.run(), expected);
}

expectMultiValueResult(`
  (module
    (func (export "run") (result i32 i32 i32)
      (i32.const 0)
      (i32.const 52)
      (i32.const 10)))`, [0, 52, 10]);
expectMultiValueResult(`
  (module
    (func (export "run") (result f32 f32 f32)
      (f32.const 0.5)
      (f32.const 52.5)
      (f32.const 10.5)))`, [0.5, 52.5, 10.5]);
expectMultiValueResult(`
  (module
    (func (export "run") (result f64 f64 f64)
      (f64.const 0.5)
      (f64.const 52.5)
      (f64.const 10.5)))`, [0.5, 52.5, 10.5]);

expectMultiValueResult(`
  (module
    (func (export "run") (result i32 i64 i32)
      (i32.const 0)
      (i64.const 52)
      (i32.const 10)))`, [0, 52n, 10]);
expectMultiValueResult(`
  (module
    (func (export "run") (result i64 i32 i64)
      (i64.const 0)
      (i32.const 52)
      (i64.const 10)))`, [0n, 52, 10n]);
expectMultiValueResult(`
  (module
    (func (export "run") (result i64 i64 i64)
      (i64.const 0)
      (i64.const 52)
      (i64.const 10)))`, [0n, 52n, 10n]);
