Skip to main content

wasm_bindgen/convert/
closures.rs

1use alloc::boxed::Box;
2use core::mem;
3
4#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
5use crate::__rt::maybe_catch_unwind;
6use crate::closure::{
7    Closure, ImmediateClosure, IntoWasmClosure, IntoWasmClosureRef, IntoWasmClosureRefMut,
8    ScopedClosure, WasmClosure, WasmClosureFnOnce, WasmClosureFnOnceAbort,
9};
10use crate::convert::slices::WasmSlice;
11use crate::convert::traits::UpcastFrom;
12use crate::convert::RefFromWasmAbi;
13use crate::convert::{FromWasmAbi, IntoWasmAbi, ReturnWasmAbi, WasmAbi, WasmRet};
14use crate::describe::{inform, WasmDescribe, FUNCTION};
15use crate::sys::Undefined;
16use crate::JsValue;
17use crate::UnwrapThrowExt;
18use crate::__rt::marker::ErasableGeneric;
19use crate::throw_str;
20#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
21use core::panic::AssertUnwindSafe;
22
23macro_rules! closures {
24    // Unwind safe passing
25    ([$($maybe_unwind_safe:tt)*] $($rest:tt)*) => {
26        closures!(@process [$($maybe_unwind_safe)*] $($rest)*);
27    };
28
29    // One-arity recurse
30    (@process [$($unwind_safe:tt)*] ($($var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) $($rest:tt)*) => {
31        closures!(@impl_for_args ($($var),*) FromWasmAbi [$($unwind_safe)*] $($var::from_abi($var) => $var $arg1 $arg2 $arg3 $arg4)*);
32        closures!(@process [$($unwind_safe)*] $($rest)*);
33    };
34
35    // Base case
36    (@process [$($unwind_safe:tt)*]) => {};
37
38    // A counter helper to count number of arguments.
39    (@count_one $ty:ty) => (1);
40
41    (@describe ( $($ty:ty),* )) => {
42        // Needs to be a constant so that interpreter doesn't crash on
43        // unsupported operations in debug mode.
44        const ARG_COUNT: u32 = 0 $(+ closures!(@count_one $ty))*;
45        inform(ARG_COUNT);
46        $(<$ty>::describe();)*
47    };
48
49    // This silly helper is because by default Rust infers `|var_with_ref_type| ...` closure
50    // as `impl Fn(&'outer_lifetime A)` instead of `impl for<'temp_lifetime> Fn(&'temp_lifetime A)`
51    // while `|var_with_ref_type: &A|` makes it use the higher-order generic as expected.
52    (@closure ($($ty:ty),*) $($var:ident)* $body:block) => (move |$($var: $ty),*| $body);
53
54    (@impl_for_fn $is_mut:literal [$($mut:ident)?] $Fn:ident $FnArgs:tt $FromWasmAbi:ident $($var_expr:expr => $var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) => (const _: () = {
55        impl<$($var,)* R> IntoWasmAbi for &'_ $($mut)? (dyn $Fn $FnArgs -> R + '_)
56        where
57            Self: WasmDescribe,
58        {
59            type Abi = WasmSlice;
60
61            fn into_abi(self) -> WasmSlice {
62                unsafe {
63                    let (a, b): (usize, usize) = mem::transmute(self);
64                    WasmSlice { ptr: a as u32, len: b as u32 }
65                }
66            }
67        }
68
69        unsafe impl<'a, $($var,)* R> ErasableGeneric for &'a $($mut)? (dyn $Fn $FnArgs -> R + 'a)
70        where
71            $($var: ErasableGeneric,)*
72            R: ErasableGeneric
73        {
74            type Repr = &'static (dyn $Fn ($(<$var as ErasableGeneric>::Repr,)*) -> <R as ErasableGeneric>::Repr + 'static);
75        }
76
77        unsafe impl<'a, 'b, $($var,)* R> ErasableGeneric for ImmediateClosure<'a, dyn $Fn $FnArgs -> R + 'b>
78        where
79            $($var: ErasableGeneric,)*
80            R: ErasableGeneric,
81        {
82            type Repr = &'static ImmediateClosure<'static, dyn $Fn ($(<$var as ErasableGeneric>::Repr,)*) -> <R as ErasableGeneric>::Repr + 'static>;
83        }
84
85        // Generate invoke function that checks unwind_safe flag when unwinding is available
86        // unwind_safe flag is the MSV of the vtable pointer for a closure, distinguishing
87        // closures which are and are not unwind safe
88        #[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
89        #[allow(non_snake_case)]
90        unsafe extern "C-unwind" fn invoke<$($var: $FromWasmAbi,)* R: ReturnWasmAbi>(
91            a: usize,
92            b: usize,
93            $(
94            $arg1: <$var::Abi as WasmAbi>::Prim1,
95            $arg2: <$var::Abi as WasmAbi>::Prim2,
96            $arg3: <$var::Abi as WasmAbi>::Prim3,
97            $arg4: <$var::Abi as WasmAbi>::Prim4,
98            )*
99        ) -> WasmRet<R::Abi> {
100            if a == 0 {
101                throw_str("closure invoked recursively or after being dropped");
102            }
103            let unwind_safe = (b & 0x80000000) != 0;
104            let b = b & 0x7FFFFFFF;
105            let ret = {
106                let f: & $($mut)? dyn $Fn $FnArgs -> R = mem::transmute((a, b));
107                $(
108                    let $var = $var::Abi::join($arg1, $arg2, $arg3, $arg4);
109                )*
110                if unwind_safe {
111                    maybe_catch_unwind(AssertUnwindSafe(|| f($($var_expr),*)))
112                } else {
113                    f($($var_expr),*)
114                }
115            };
116            ret.return_abi().into()
117        }
118
119        // When unwinding is not available, generate a simple invoke function
120        #[cfg(not(all(feature = "std", target_arch = "wasm32", panic = "unwind")))]
121        #[allow(non_snake_case)]
122        unsafe extern "C-unwind" fn invoke<$($var: $FromWasmAbi,)* R: ReturnWasmAbi>(
123            a: usize,
124            b: usize,
125            $(
126            $arg1: <$var::Abi as WasmAbi>::Prim1,
127            $arg2: <$var::Abi as WasmAbi>::Prim2,
128            $arg3: <$var::Abi as WasmAbi>::Prim3,
129            $arg4: <$var::Abi as WasmAbi>::Prim4,
130            )*
131        ) -> WasmRet<R::Abi> {
132            if a == 0 {
133                throw_str("closure invoked recursively or after being dropped");
134            }
135            let b = b & 0x7FFFFFFF;
136            let ret = {
137                let f: & $($mut)? dyn $Fn $FnArgs -> R = mem::transmute((a, b));
138                $(
139                    let $var = $var::Abi::join($arg1, $arg2, $arg3, $arg4);
140                )*
141                f($($var_expr),*)
142            };
143            ret.return_abi().into()
144        }
145
146        #[allow(clippy::fn_to_numeric_cast)]
147        impl<$($var,)* R> WasmDescribe for dyn $Fn $FnArgs -> R + '_
148        where
149            $($var: $FromWasmAbi,)*
150            R: ReturnWasmAbi,
151        {
152            #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
153            fn describe() {
154                inform(FUNCTION);
155                inform(invoke::<$($var,)* R> as *const () as usize as u32);
156                closures!(@describe $FnArgs);
157                R::describe();
158                R::describe();
159            }
160        }
161
162        unsafe impl<'__closure, $($var,)* R> WasmClosure for dyn $Fn $FnArgs -> R + '__closure
163        where
164            Self: WasmDescribe,
165        {
166            const IS_MUT: bool = $is_mut;
167            type AsMut = dyn FnMut $FnArgs -> R + '__closure;
168            fn to_wasm_slice(r: &Self) -> WasmSlice {
169                let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&r) };
170                WasmSlice { ptr, len }
171            }
172        }
173
174        impl<T, $($var,)* R> IntoWasmClosure<dyn $Fn $FnArgs -> R> for T
175        where
176            T: 'static + $Fn $FnArgs -> R,
177        {
178            fn unsize(self: Box<Self>) -> Box<dyn $Fn $FnArgs -> R> { self }
179        }
180    };);
181
182    // IntoWasmClosureRef is only implemented for Fn, not FnMut.
183    // IntoWasmClosureRefMut is implemented for FnMut.
184    // Since Fn: FnMut, any Fn closure can be used as FnMut, so this covers all cases.
185    (@impl_unsize_closure_ref $FnArgs:tt $FromWasmAbi:ident $($var_expr:expr => $var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) => (
186        impl<'a, 'b, T: 'a, $($var: 'a + $FromWasmAbi,)* R: 'a + ReturnWasmAbi> IntoWasmClosureRef<'b, dyn Fn $FnArgs -> R + 'a> for T
187        where
188            'a: 'b,
189            T: Fn $FnArgs -> R,
190        {
191            type Static = dyn Fn $FnArgs -> R;
192            type WithLifetime = dyn Fn $FnArgs -> R + 'b;
193            fn unsize_closure_ref(&self) -> &(dyn Fn $FnArgs -> R + 'a) { self }
194        }
195
196        impl<'a, 'b, T: 'a, $($var: 'a + $FromWasmAbi,)* R: 'a + ReturnWasmAbi> IntoWasmClosureRefMut<'b, dyn FnMut $FnArgs -> R + 'a> for T
197        where
198            'a: 'b,
199            T: FnMut $FnArgs -> R,
200        {
201            type Static = dyn FnMut $FnArgs -> R;
202            type WithLifetime = dyn FnMut $FnArgs -> R + 'b;
203            fn unsize_closure_ref(&mut self) -> &mut (dyn FnMut $FnArgs -> R + 'a) { self }
204        }
205    );
206
207    (@impl_for_args $FnArgs:tt $FromWasmAbi:ident [$($maybe_unwind_safe:tt)*] $($var_expr:expr => $var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) => {
208        closures!(@impl_for_fn false [] Fn $FnArgs $FromWasmAbi $($var_expr => $var $arg1 $arg2 $arg3 $arg4)*);
209        closures!(@impl_for_fn true [mut] FnMut $FnArgs $FromWasmAbi $($var_expr => $var $arg1 $arg2 $arg3 $arg4)*);
210        closures!(@impl_unsize_closure_ref $FnArgs $FromWasmAbi $($var_expr => $var $arg1 $arg2 $arg3 $arg4)*);
211
212        // The memory safety here in these implementations below is a bit tricky. We
213        // want to be able to drop the `Closure` object from within the invocation of a
214        // `Closure` for cases like promises. That means that while it's running we
215        // might drop the `Closure`, but that shouldn't invalidate the environment yet.
216        //
217        // Instead what we do is to wrap closures in `Rc` variables. The main `Closure`
218        // has a strong reference count which keeps the trait object alive. Each
219        // invocation of a closure then *also* clones this and gets a new reference
220        // count. When the closure returns it will release the reference count.
221        //
222        // This means that if the main `Closure` is dropped while it's being invoked
223        // then destruction is deferred until execution returns. Otherwise it'll
224        // deallocate data immediately.
225
226        #[allow(non_snake_case, unused_parens)]
227        impl<T, $($var,)* R> WasmClosureFnOnce<dyn FnMut $FnArgs -> R, $FnArgs, R> for T
228        where
229            T: 'static + (FnOnce $FnArgs -> R),
230            $($var: $FromWasmAbi + 'static,)*
231            R: ReturnWasmAbi + 'static,
232            $($maybe_unwind_safe)*
233        {
234            fn into_fn_mut(self) -> Box<dyn FnMut $FnArgs -> R> {
235                let mut me = Some(self);
236                Box::new(move |$($var),*| {
237                    let me = me.take().expect_throw("FnOnce called more than once");
238                    me($($var),*)
239                })
240            }
241
242            fn into_js_function(self) -> JsValue {
243                use alloc::rc::Rc;
244                use crate::__rt::WasmRefCell;
245
246                let rc1 = Rc::new(WasmRefCell::new(None));
247                let rc2 = rc1.clone();
248
249                let closure = Closure::once(closures!(@closure $FnArgs $($var)* {
250                    let result = self($($var),*);
251
252                    // And then drop the `Rc` holding this function's `Closure`
253                    // alive.
254                    debug_assert_eq!(Rc::strong_count(&rc2), 1);
255                    let option_closure = rc2.borrow_mut().take();
256                    debug_assert!(option_closure.is_some());
257                    drop(option_closure);
258
259                    result
260                }));
261
262                let js_val = closure.as_ref().clone();
263
264                *rc1.borrow_mut() = Some(closure);
265                debug_assert_eq!(Rc::strong_count(&rc1), 2);
266                drop(rc1);
267
268                js_val
269            }
270        }
271
272        #[allow(non_snake_case, unused_parens)]
273        impl<T, $($var,)* R> WasmClosureFnOnceAbort<dyn FnMut $FnArgs -> R, $FnArgs, R> for T
274        where
275            T: 'static + (FnOnce $FnArgs -> R),
276            $($var: $FromWasmAbi + 'static,)*
277            R: ReturnWasmAbi + 'static,
278        {
279            fn into_fn_mut(self) -> Box<dyn FnMut $FnArgs -> R> {
280                let mut me = Some(self);
281                Box::new(move |$($var),*| {
282                    let me = me.take().expect_throw("FnOnce called more than once");
283                    me($($var),*)
284                })
285            }
286
287            fn into_js_function(self) -> JsValue {
288                use alloc::rc::Rc;
289                use crate::__rt::WasmRefCell;
290
291                let rc1 = Rc::new(WasmRefCell::new(None));
292                let rc2 = rc1.clone();
293
294                let closure = Closure::once_wrap(closures!(@closure $FnArgs $($var)* {
295                    let result = self($($var),*);
296
297                    // And then drop the `Rc` holding this function's `Closure`
298                    // alive.
299                    debug_assert_eq!(Rc::strong_count(&rc2), 1);
300                    let option_closure = rc2.borrow_mut().take();
301                    debug_assert!(option_closure.is_some());
302                    drop(option_closure);
303
304                    result
305                }));
306
307                let js_val = closure.as_ref().clone();
308
309                *rc1.borrow_mut() = Some(closure);
310                debug_assert_eq!(Rc::strong_count(&rc1), 2);
311                drop(rc1);
312
313                js_val
314            }
315        }
316    };
317
318    ([$($unwind_safe:tt)*] $( ($($var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) )*) => ($(
319        closures!(@impl_for_args ($($var),*) FromWasmAbi [$($maybe_unwind_safe)*] $($var::from_abi($var) => $var $arg1 $arg2 $arg3 $arg4)*);
320    )*);
321}
322
323#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
324closures! {
325    [T: core::panic::UnwindSafe,]
326    ()
327    (A a1 a2 a3 a4)
328    (A a1 a2 a3 a4 B b1 b2 b3 b4)
329    (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4)
330    (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4)
331    (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4)
332    (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4)
333    (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4 G g1 g2 g3 g4)
334    (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4 G g1 g2 g3 g4 H h1 h2 h3 h4)
335}
336
337#[cfg(not(all(feature = "std", target_arch = "wasm32", panic = "unwind")))]
338closures! {
339    []
340    ()
341    (A a1 a2 a3 a4)
342    (A a1 a2 a3 a4 B b1 b2 b3 b4)
343    (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4)
344    (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4)
345    (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4)
346    (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4)
347    (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4 G g1 g2 g3 g4)
348    (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4 G g1 g2 g3 g4 H h1 h2 h3 h4)
349}
350
351// Comprehensive type-safe cross-function covariant and contravariant casting rules
352macro_rules! impl_fn_upcasts {
353    () => {
354        impl_fn_upcasts!(@arities
355            [0 []]
356            [1 [A1 B1] O1]
357            [2 [A1 B1 A2 B2] O2]
358            [3 [A1 B1 A2 B2 A3 B3] O3]
359            [4 [A1 B1 A2 B2 A3 B3 A4 B4] O4]
360            [5 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5] O5]
361            [6 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6] O6]
362            [7 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7] O7]
363            [8 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7 A8 B8] O8]
364        );
365    };
366
367    (@arities) => {};
368
369    (@arities [$n:tt $args:tt $($opt:ident)?] $([$rest_n:tt $rest_args:tt $($rest_opt:ident)?])*) => {
370        impl_fn_upcasts!(@same $args);
371        impl_fn_upcasts!(@cross_all $args [] $([$rest_n $rest_args $($rest_opt)?])*);
372        impl_fn_upcasts!(@arities $([$rest_n $rest_args $($rest_opt)?])*);
373    };
374
375    (@same []) => {
376        impl<R1, R2> UpcastFrom<fn() -> R1> for fn() -> R2
377        where
378            R2: UpcastFrom<R1>
379        {}
380
381        impl<'a, R1, R2> UpcastFrom<dyn Fn() -> R1 + 'a> for dyn Fn() -> R2 + 'a
382        where
383            R2: UpcastFrom<R1>
384        {}
385
386        impl<'a, R1, R2> UpcastFrom<dyn FnMut() -> R1 + 'a> for dyn FnMut() -> R2 + 'a
387        where
388            R2: UpcastFrom<R1>
389        {}
390    };
391
392    // Arguments implemented with contravariance
393    (@same [$($A1:ident $A2:ident)+]) => {
394        impl<R1, R2, $($A1, $A2),+> UpcastFrom<fn($($A1),+) -> R1> for fn($($A2),+) -> R2
395        where
396            R2: UpcastFrom<R1>,
397            $($A1: UpcastFrom<$A2>,)+
398        {}
399
400        impl<'a, R1, R2, $($A1, $A2),+> UpcastFrom<dyn Fn($($A1),+) -> R1 + 'a> for dyn Fn($($A2),+) -> R2 + 'a
401        where
402            R2: UpcastFrom<R1>,
403            $($A1: UpcastFrom<$A2>,)+
404        {}
405
406        impl<'a, R1, R2, $($A1, $A2),+> UpcastFrom<dyn FnMut($($A1),+) -> R1 + 'a> for dyn FnMut($($A2),+) -> R2 + 'a
407        where
408            R2: UpcastFrom<R1>,
409            $($A1: UpcastFrom<$A2>,)+
410        {}
411    };
412
413    // Cross-all: done
414    (@cross_all $args:tt $opts:tt) => {};
415
416    // Cross-all: process next
417    (@cross_all $args:tt [$($opts:ident)*] [$next_n:tt $next_args:tt $next_opt:ident] $([$rest_n:tt $rest_args:tt $($rest_opt:ident)?])*) => {
418        impl_fn_upcasts!(@extend $args [$($opts)* $next_opt]);
419        impl_fn_upcasts!(@shrink $args [$($opts)* $next_opt]);
420        impl_fn_upcasts!(@cross_all $args [$($opts)* $next_opt] $([$rest_n $rest_args $($rest_opt)?])*);
421    };
422
423    // Extend: 0 -> N
424    (@extend [] [$($O:ident)+]) => {
425        impl<R1, R2, $($O),+> UpcastFrom<fn() -> R1> for fn($($O),+) -> R2
426        where
427            R2: UpcastFrom<R1>,
428            $($O: UpcastFrom<Undefined>,)+
429        {}
430
431        impl<'a, R1, R2, $($O),+> UpcastFrom<dyn Fn() -> R1 + 'a> for dyn Fn($($O),+) -> R2 + 'a
432        where
433            R2: UpcastFrom<R1>,
434            $($O: UpcastFrom<Undefined>,)+
435        {}
436
437        impl<'a, R1, R2, $($O),+> UpcastFrom<dyn FnMut() -> R1 + 'a> for dyn FnMut($($O),+) -> R2 + 'a
438        where
439            R2: UpcastFrom<R1>,
440            $($O: UpcastFrom<Undefined>,)+
441        {}
442    };
443
444    // Extend: N -> M
445    (@extend [$($A1:ident $A2:ident)+] [$($O:ident)+]) => {
446        impl<R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<fn($($A1),+) -> R1> for fn($($A2,)+ $($O),+) -> R2
447        where
448            R2: UpcastFrom<R1>,
449            $($A1: UpcastFrom<$A2>,)+  // Contravariant
450            $($O: UpcastFrom<Undefined>,)+
451        {}
452
453        impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn Fn($($A1),+) -> R1 + 'a> for dyn Fn($($A2,)+ $($O),+) -> R2 + 'a
454        where
455            R2: UpcastFrom<R1>,
456            $($A1: UpcastFrom<$A2>,)+  // Contravariant
457            $($O: UpcastFrom<Undefined>,)+
458        {}
459
460        impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn FnMut($($A1),+) -> R1 + 'a> for dyn FnMut($($A2,)+ $($O),+) -> R2 + 'a
461        where
462            R2: UpcastFrom<R1>,
463            $($A1: UpcastFrom<$A2>,)+  // Contravariant
464            $($O: UpcastFrom<Undefined>,)+
465        {}
466    };
467
468    // Shrink: N -> 0
469    (@shrink [] [$($O:ident)+]) => {
470        impl<R1, R2, $($O),+> UpcastFrom<fn($($O),+) -> R1> for fn() -> R2
471        where
472            R2: UpcastFrom<R1>,
473            $($O: UpcastFrom<Undefined>,)+
474        {}
475
476        impl<'a, R1, R2, $($O),+> UpcastFrom<dyn Fn($($O),+) -> R1 + 'a> for dyn Fn() -> R2 + 'a
477        where
478            R2: UpcastFrom<R1>,
479            $($O: UpcastFrom<Undefined>,)+
480        {}
481
482        impl<'a, R1, R2, $($O),+> UpcastFrom<dyn FnMut($($O),+) -> R1 + 'a> for dyn FnMut() -> R2 + 'a
483        where
484            R2: UpcastFrom<R1>,
485            $($O: UpcastFrom<Undefined>,)+
486        {}
487    };
488
489    // Shrink: M -> N
490    (@shrink [$($A1:ident $A2:ident)+] [$($O:ident)+]) => {
491        impl<R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<fn($($A1,)+ $($O),+) -> R1> for fn($($A2),+) -> R2
492        where
493            R2: UpcastFrom<R1>,
494            $($A1: UpcastFrom<$A2>,)+  // Contravariant
495            $($O: UpcastFrom<Undefined>,)+
496        {}
497
498        impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn Fn($($A1,)+ $($O),+) -> R1 + 'a> for dyn Fn($($A2),+) -> R2 + 'a
499        where
500            R2: UpcastFrom<R1>,
501            $($A1: UpcastFrom<$A2>,)+  // Contravariant
502            $($O: UpcastFrom<Undefined>,)+
503        {}
504
505        impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn FnMut($($A1,)+ $($O),+) -> R1 + 'a> for dyn FnMut($($A2),+) -> R2 + 'a
506        where
507            R2: UpcastFrom<R1>,
508            $($A1: UpcastFrom<$A2>,)+  // Contravariant
509            $($O: UpcastFrom<Undefined>,)+
510        {}
511    };
512}
513
514impl_fn_upcasts!();
515
516// Copy the above impls down here for where there's only one argument and it's a
517// reference. We could add more impls for more kinds of references, but it
518// becomes a combinatorial explosion quickly. Let's see how far we can get with
519// just this one! Maybe someone else can figure out voodoo so we don't have to
520// duplicate.
521
522// We need to allow coherence leak check just for these traits because we're providing separate implementation for `Fn(&A)` variants when `Fn(A)` one already exists.
523#[allow(coherence_leak_check)]
524const _: () = {
525    #[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
526    closures!(@impl_for_args (&A) RefFromWasmAbi [T: core::panic::UnwindSafe,] &*A::ref_from_abi(A) => A a1 a2 a3 a4);
527
528    #[cfg(not(all(feature = "std", target_arch = "wasm32", panic = "unwind")))]
529    closures!(@impl_for_args (&A) RefFromWasmAbi [] &*A::ref_from_abi(A) => A a1 a2 a3 a4);
530};
531
532// UpcastFrom impl for ScopedClosure.
533// ScopedClosure<T1> upcasts to ScopedClosure<T2> when the underlying closure type T1 upcasts to T2.
534// The dyn Fn/FnMut UpcastFrom impls above encode correct variance (covariant return, contravariant args).
535impl<'a, 'b, T1, T2> UpcastFrom<ScopedClosure<'a, T1>> for ScopedClosure<'b, T2>
536where
537    T1: ?Sized + WasmClosure,
538    T2: ?Sized + WasmClosure + UpcastFrom<T1>,
539{
540}
541
542// UpcastFrom impl for ImmediateClosure.
543// ImmediateClosure<T2> upcasts from ImmediateClosure<T1> when T2's dyn type upcasts from T1's dyn type.
544// Since ImmediateClosure is #[repr(transparent)] over &'a mut T, this is a zero-cost transmute.
545impl<'a, 'b, T1, T2> UpcastFrom<ImmediateClosure<'a, T1>> for ImmediateClosure<'b, T2>
546where
547    T1: ?Sized + WasmClosure,
548    T2: ?Sized + WasmClosure,
549    T2: UpcastFrom<T1>,
550{
551}