1;;! component_model_async = true
2
3;; This test contains two components $C and $D that test that a trap occurs
4;; when closing the writable end of a future (in $C) before having written
5;; a value while closing the readable end of a future (in $D) before reading
6;; a value is fine.
7;;
8;; (Copied from
9;; https://github.com/WebAssembly/component-model/blob/future-trap/test/async/futures-must-write.wast)
10(component
11  (component $C
12    (core module $Memory (memory (export "mem") 1))
13    (core instance $memory (instantiate $Memory))
14    (core module $CM
15      (import "" "mem" (memory 1))
16      (import "" "future.new" (func $future.new (result i64)))
17      (import "" "future.write" (func $future.write (param i32 i32) (result i32)))
18      (import "" "future.drop-writable" (func $future.drop-writable (param i32)))
19
20      (global $fw (mut i32) (i32.const 0))
21
22      (func $start-future (export "start-future") (result i32)
23        ;; create a new future, return the readable end to the caller
24        (local $ret64 i64)
25        (local.set $ret64 (call $future.new))
26        (global.set $fw (i32.wrap_i64 (i64.shr_u (local.get $ret64) (i64.const 32))))
27        (i32.wrap_i64 (local.get $ret64))
28      )
29      (func $attempt-write (export "attempt-write") (result i32)
30        ;; because the caller already dropped the readable end, this write will eagerly
31        ;; return DROPPED having written no values.
32        (local $ret i32)
33        (local.set $ret (call $future.write (global.get $fw) (i32.const 42)))
34        (if (i32.ne (i32.const 0x01 (; DROPPED=1 | (0<<4) ;)) (local.get $ret))
35          (then
36            (i32.load (i32.add (local.get $ret) (i32.const 0x8000_0000)))
37          unreachable))
38
39        ;; return without trapping
40        (i32.const 42)
41      )
42      (func $drop-writable (export "drop-writable")
43        ;; maybe boom
44        (call $future.drop-writable (global.get $fw))
45      )
46    )
47    (type $FT (future u8))
48    (canon future.new $FT (core func $future.new))
49    (canon future.write $FT async (memory $memory "mem") (core func $future.write))
50    (canon future.drop-writable $FT (core func $future.drop-writable))
51    (core instance $cm (instantiate $CM (with "" (instance
52      (export "mem" (memory $memory "mem"))
53      (export "future.new" (func $future.new))
54      (export "future.write" (func $future.write))
55      (export "future.drop-writable" (func $future.drop-writable))
56    ))))
57    (func (export "start-future") (result (future u8)) (canon lift (core func $cm "start-future")))
58    (func (export "attempt-write") (result u32) (canon lift (core func $cm "attempt-write")))
59    (func (export "drop-writable") (canon lift (core func $cm "drop-writable")))
60  )
61  (component $D
62    (import "c" (instance $c
63      (export "start-future" (func (result (future u8))))
64      (export "attempt-write" (func (result u32)))
65      (export "drop-writable" (func))
66    ))
67
68    (core module $Memory (memory (export "mem") 1))
69    (core instance $memory (instantiate $Memory))
70    (core module $Core
71      (import "" "mem" (memory 1))
72      (import "" "future.read" (func $future.read (param i32 i32) (result i32)))
73      (import "" "future.drop-readable" (func $future.drop-readable (param i32)))
74      (import "" "start-future" (func $start-future (result i32)))
75      (import "" "attempt-write" (func $attempt-write (result i32)))
76      (import "" "drop-writable" (func $drop-writable))
77
78      (func $drop-readable-future-before-read (export "drop-readable-future-before-read") (result i32)
79        ;; call 'start-future' to get the future we'll be working with
80        (local $fr i32)
81        (local.set $fr (call $start-future))
82        (if (i32.ne (i32.const 1) (local.get $fr))
83          (then unreachable))
84
85        ;; ok to immediately drop the readable end
86        (call $future.drop-readable (local.get $fr))
87
88        ;; the callee will see that we dropped the readable end when it tries to write
89        (call $attempt-write)
90      )
91      (func $drop-writable-future-before-write (export "drop-writable-future-before-write")
92        ;; call 'start-future' to get the future we'll be working with
93        (local $fr i32)
94        (local.set $fr (call $start-future))
95        (if (i32.ne (i32.const 1) (local.get $fr))
96          (then unreachable))
97
98        ;; boom
99        (call $drop-writable)
100      )
101    )
102    (type $FT (future u8))
103    (canon future.new $FT (core func $future.new))
104    (canon future.read $FT async (memory $memory "mem") (core func $future.read))
105    (canon future.drop-readable $FT (core func $future.drop-readable))
106    (canon lower (func $c "start-future") (core func $start-future'))
107    (canon lower (func $c "attempt-write") (core func $attempt-write'))
108    (canon lower (func $c "drop-writable") (core func $drop-writable'))
109    (core instance $core (instantiate $Core (with "" (instance
110      (export "mem" (memory $memory "mem"))
111      (export "future.new" (func $future.new))
112      (export "future.read" (func $future.read))
113      (export "future.drop-readable" (func $future.drop-readable))
114      (export "start-future" (func $start-future'))
115      (export "attempt-write" (func $attempt-write'))
116      (export "drop-writable" (func $drop-writable'))
117    ))))
118    (func (export "drop-readable-future-before-read") (result u32) (canon lift (core func $core "drop-readable-future-before-read")))
119    (func (export "drop-writable-future-before-write") (canon lift (core func $core "drop-writable-future-before-write")))
120  )
121  (instance $c (instantiate $C))
122  (instance $d (instantiate $D (with "c" (instance $c))))
123  (func (export "drop-writable-future-before-write") (alias export $d "drop-writable-future-before-write"))
124  (func (export "drop-readable-future-before-read") (alias export $d "drop-readable-future-before-read"))
125)
126
127(assert_return (invoke "drop-readable-future-before-read") (u32.const 42))
128(assert_trap (invoke "drop-writable-future-before-write") "cannot drop future write end without first writing a value")
129