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